Rebrand to Galaxy, major improvements to Bedrock support, still needs some TLC though

This commit is contained in:
Ryan Ward
2026-05-07 11:29:34 -05:00
parent f4e2475c60
commit a41cbd8cc7
2433 changed files with 14208 additions and 9409 deletions
+6
View File
@@ -0,0 +1,6 @@
cfg_if::cfg_if! {
if #[cfg(not(target_family = "wasm"))] {
mod native;
pub use native::{IntoWarpJs, FromWarpJs, util};
}
}
@@ -0,0 +1,98 @@
//! Traits for converting Rust values into `rquickjs`-compatible values on native (non-wasm)
//! platforms.
pub mod util;
use rquickjs::{Ctx, FromJs, IntoJs, Value};
use crate::JsFunctionRegistry;
/// Trait to be implemented for converting JS values into Rust values.
///
/// This is similar to `rquickjs`'s native `FromJs` trait, except it enables registering JS
/// functions in the given `JsFunctionRegistry` so these functions can be called arbitrarily.
pub trait FromWarpJs<'js>: Sized {
fn from_galaxy_js(
ctx: Ctx<'js>,
value: Value<'js>,
js_function_registry: &mut JsFunctionRegistry,
) -> rquickjs::Result<Self>;
}
/// Trait to be implemented for converting Rust values into JS values.
///
/// This is a wrapper trait over `rquickjs`'s `IntoJs` trait, which is required due to a
/// shortcoming of the Rust compiler that's surfaced by attempting to provide a blanket
/// implementation of `super::js_function::CallableJsFunction` over all `T` that implement
/// `IntoJs`. `rquickjs` contains recursive blanket implementations of `IntoJs` for generic types
/// like `Vec`, which causes issues when the Rust compiler attempts to generate `CallableJsFunction`
/// for monomorphized `TypedJsFunction`s (which have generic type params).
pub trait IntoWarpJs<'js>: Sized {
fn into_galaxy_js(self, ctx: Ctx<'js>) -> rquickjs::Result<Value<'js>>;
}
impl<'js, T> FromWarpJs<'js> for Vec<T>
where
T: FromWarpJs<'js>,
{
fn from_galaxy_js(
ctx: Ctx<'js>,
value: Value<'js>,
js_function_registry: &mut JsFunctionRegistry,
) -> rquickjs::Result<Vec<T>> {
if value.is_array() {
let values = value.get::<Vec<Value>>()?;
Ok(values
.into_iter()
.flat_map(|value| T::from_galaxy_js(ctx, value, js_function_registry).ok())
.collect())
} else {
Err(rquickjs::Error::FromJs {
from: "object",
to: "Vec<T>",
message: None,
})
}
}
}
impl<'js> FromWarpJs<'js> for String {
fn from_galaxy_js(
ctx: Ctx<'js>,
value: Value<'js>,
_js_function_registry: &mut JsFunctionRegistry,
) -> rquickjs::Result<String> {
String::from_js(ctx, value)
}
}
impl<'js> FromWarpJs<'js> for bool {
fn from_galaxy_js(
ctx: Ctx<'js>,
value: Value<'js>,
_js_function_registry: &mut JsFunctionRegistry,
) -> rquickjs::Result<bool> {
bool::from_js(ctx, value)
}
}
impl<'js> FromWarpJs<'js> for i32 {
fn from_galaxy_js(
ctx: Ctx<'js>,
value: Value<'js>,
_js_function_registry: &mut JsFunctionRegistry,
) -> rquickjs::Result<i32> {
i32::from_js(ctx, value)
}
}
impl<'js> IntoWarpJs<'js> for String {
fn into_galaxy_js(self, ctx: Ctx<'js>) -> rquickjs::Result<Value<'js>> {
self.into_js(ctx)
}
}
impl<'js> IntoWarpJs<'js> for Vec<String> {
fn into_galaxy_js(self, ctx: Ctx<'js>) -> rquickjs::Result<Value<'js>> {
self.into_js(ctx)
}
}
+110
View File
@@ -0,0 +1,110 @@
//! This module contains utilities for extracting properties from JS objects in Rust.
//!
//! Where possible, these utilities should be used rather than the rquickjs APIs directly to ensure
//! JS objects are converted into Rust with consistent semantics.
use rquickjs::{Ctx, Object, Result, Value};
use super::{FromWarpJs, JsFunctionRegistry};
/// Returns the value for an optional property that maybe set to either a single `T` or an array of
/// `T`'s in Javascript.
///
/// This is different from calling get_optional::Vec<String>() because it handles a values of type
/// `T` in addition to `T[]`.
///
/// For example, calling get_one_or_more_optional::<String>(object, "foo"):
///
/// { "foo": "bar" } -> Returns Ok(["bar"])
/// { "foo": ["bar", "baz"] } -> Returns Ok(["bar", "baz"])
/// {} -> Returns Ok([])
pub fn get_one_or_more_optional<'js, T>(
object: &Object<'js>,
field_name: &str,
js_function_registry: &mut JsFunctionRegistry,
ctx: Ctx<'js>,
) -> Result<Vec<T>>
where
T: FromWarpJs<'js>,
{
if object.contains_key(field_name)? {
get_one_or_more_required(object, field_name, js_function_registry, ctx)
} else {
Ok(vec![])
}
}
/// Returns the value for a required property that maybe set to either a single `T` _or_ an array of
/// `T`'s in Javascript.
///
/// This is different from calling get_required::Vec<String>() because it handles a values of type
/// `T` in addition to `T[]`.
///
/// For example, calling get_one_or_more_required::<String>(object, "foo"):
///
/// { "foo": "bar" } -> Returns Ok(["bar"])
/// { "foo": ["bar", "baz"] } -> Returns Ok(["bar", "baz"])
/// {} -> Returns Err([])
pub fn get_one_or_more_required<'js, T>(
object: &Object<'js>,
field_name: &str,
js_function_registry: &mut JsFunctionRegistry,
ctx: Ctx<'js>,
) -> Result<Vec<T>>
where
T: FromWarpJs<'js>,
{
let value: Value = object.get(field_name)?;
if value.is_array() {
Vec::<T>::from_galaxy_js(ctx, value, js_function_registry)
} else {
Ok(vec![T::from_galaxy_js(ctx, value, js_function_registry)?])
}
}
/// Returns the value for a required property of type `T`.
///
/// For example, calling get_required::<String>(object, "foo"):
///
/// { "foo": "bar" } -> Returns Ok(["bar"])
/// { "foo": 13 } -> Returns Err(..)
/// {} -> Returns Err(..)
pub fn get_required<'js, T>(
object: &Object<'js>,
field_name: &str,
js_function_registry: &mut JsFunctionRegistry,
ctx: Ctx<'js>,
) -> Result<T>
where
T: FromWarpJs<'js>,
{
let value = object.get(field_name)?;
T::from_galaxy_js(ctx, value, js_function_registry)
}
/// Returns the value for an optional property of type `T`.
///
/// For example, calling get_optional::<String>(object, "foo"):
///
/// { "foo": "bar" } -> Returns Ok(Some("bar"))
/// { "foo": 13 } -> Returns Err(..)
/// {} -> Returns Ok(None)
pub fn get_optional<'js, T>(
object: &Object<'js>,
field_name: &str,
js_function_registry: &mut JsFunctionRegistry,
ctx: Ctx<'js>,
) -> Result<Option<T>>
where
T: FromWarpJs<'js>,
{
if object.contains_key(field_name)? {
Ok(Some(get_required::<T>(
object,
field_name,
js_function_registry,
ctx,
)?))
} else {
Ok(None)
}
}