use rquickjs::{ class::{Trace, Tracer}, function::{FromParam, ParamRequirement, ParamsAccessor}, Ctx, FromJs, IntoJs, JsLifetime, Result, Type, Value, }; /// Helper type for treating an undefined value as None, without treating null as None #[derive(Clone)] pub struct Undefined(pub Option); impl<'js, T: FromJs<'js>> FromJs<'js> for Undefined { fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result { if value.type_of() == Type::Undefined { Ok(Self(None)) } else { Ok(Self(Some(FromJs::from_js(ctx, value)?))) } } } impl<'js, T: IntoJs<'js>> IntoJs<'js> for Undefined { fn into_js(self, ctx: &Ctx<'js>) -> Result> { match self.0 { None => Ok(Value::new_undefined(ctx.clone())), Some(val) => val.into_js(ctx), } } } impl Default for Undefined { fn default() -> Self { Self(None) } } unsafe impl<'js, T: JsLifetime<'js>> JsLifetime<'js> for Undefined { type Changed<'to> = Undefined>; } impl<'js, T: Trace<'js>> Trace<'js> for Undefined { fn trace<'a>(&self, tracer: Tracer<'a, 'js>) { self.0.trace(tracer) } } /// Helper type for converting an None into null instead of undefined. /// Needed while rquickjs::function::Null has no IntoJs implementation #[derive(Clone)] pub struct Null(pub Option); impl<'js, T: FromJs<'js>> FromJs<'js> for Null { fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result { if value.type_of() == Type::Null { Ok(Self(None)) } else { Ok(Self(Some(FromJs::from_js(ctx, value)?))) } } } impl<'js, T: IntoJs<'js>> IntoJs<'js> for Null { fn into_js(self, ctx: &Ctx<'js>) -> Result> { match self.0 { None => Ok(Value::new_null(ctx.clone())), Some(val) => val.into_js(ctx), } } } unsafe impl<'js, T: JsLifetime<'js>> JsLifetime<'js> for Null { type Changed<'to> = Null>; } impl<'js, T: Trace<'js>> Trace<'js> for Null { fn trace<'a>(&self, tracer: Tracer<'a, 'js>) { self.0.trace(tracer) } } /// Helper type for accepting no value, or null, but considering undefined as a value pub struct NullableOpt(pub Option); impl<'js, T: FromJs<'js>> FromParam<'js> for NullableOpt { fn param_requirement() -> ParamRequirement { ParamRequirement::optional() } fn from_param<'a>(params: &mut ParamsAccessor<'a, 'js>) -> Result { if !params.is_empty() { let arg = params.arg(); if arg.is_null() { Ok(NullableOpt(None)) } else { let ctx = params.ctx().clone(); Ok(NullableOpt(Some(T::from_js(&ctx, arg)?))) } } else { Ok(NullableOpt(None)) } } }