From 96a756baea7b15aa87f4a5c7885afc090211acb5 Mon Sep 17 00:00:00 2001 From: Luke <37006668+lukechu10@users.noreply.github.com> Date: Thu, 12 Sep 2024 11:07:11 +0200 Subject: [PATCH] Move `MaybeDyn` to new file and add some impls (#693) --- packages/sycamore-reactive/src/utils.rs | 3 - packages/sycamore-web/src/lib.rs | 2 + packages/sycamore-web/src/maybe_dyn.rs | 87 +++++++++++++++++++++++++ packages/sycamore-web/src/node/mod.rs | 68 ------------------- 4 files changed, 89 insertions(+), 71 deletions(-) create mode 100644 packages/sycamore-web/src/maybe_dyn.rs diff --git a/packages/sycamore-reactive/src/utils.rs b/packages/sycamore-reactive/src/utils.rs index 0b586ee6..656faf00 100644 --- a/packages/sycamore-reactive/src/utils.rs +++ b/packages/sycamore-reactive/src/utils.rs @@ -4,9 +4,6 @@ use crate::*; /// A trait that is implemented for reactive data that can be accessed and tracked, such as /// [`Signal`]. -/// -/// You can make your components/functions take this instead of a concrete reactive type so that it -/// can work with any reactive type. pub trait Accessor { /// Get the reactive value. For example, with [`Signal`], this just calls /// [`get`](ReadSignal::get). diff --git a/packages/sycamore-web/src/lib.rs b/packages/sycamore-web/src/lib.rs index a9796a6a..68347741 100644 --- a/packages/sycamore-web/src/lib.rs +++ b/packages/sycamore-web/src/lib.rs @@ -39,6 +39,7 @@ pub mod events; mod components; mod elements; mod iter; +mod maybe_dyn; mod node; mod noderef; mod portal; @@ -50,6 +51,7 @@ mod view; pub use self::components::*; pub use self::elements::*; pub use self::iter::*; +pub use self::maybe_dyn::*; pub use self::node::*; pub use self::noderef::*; pub use self::portal::*; diff --git a/packages/sycamore-web/src/maybe_dyn.rs b/packages/sycamore-web/src/maybe_dyn.rs new file mode 100644 index 00000000..44f001ad --- /dev/null +++ b/packages/sycamore-web/src/maybe_dyn.rs @@ -0,0 +1,87 @@ +use std::borrow::Cow; + +use wasm_bindgen::JsValue; + +/// Represents a value that can be either static or dynamic. +/// +/// This is useful for cases where you want to accept a value that can be either static or dynamic, +/// such as in component props. +/// +/// A [`MaybeDyn`] value can be created from a static value or a closure that returns the value by +/// using the [`From`] trait. +pub enum MaybeDyn> { + Static(T), + Dynamic(Box T>), +} + +impl> MaybeDyn { + /// Evaluate the value by consuming itself. + pub fn evaluate(self) -> T { + match self { + Self::Static(value) => value, + Self::Dynamic(mut f) => f(), + } + } +} + +impl, F: FnMut() -> U + 'static, U: Into> From for MaybeDyn { + fn from(mut f: F) -> Self { + Self::Dynamic(Box::new(move || f().into())) + } +} + +macro_rules! impl_from_maybe_dyn { + ($struct:ty => $($ty:ty),*) => { + $( + impl From<$ty> for $struct { + fn from(value: $ty) -> Self { + Self::Static(value.into()) + } + } + )* + }; +} + +macro_rules! impl_into_self { + ($($ty:ty),*) => { + $( + impl From<$ty> for MaybeDyn<$ty> { + fn from(value: $ty) -> Self { + Self::Static(value) + } + } + )* + }; +} + +/// A possibly dynamic string value. +pub type MaybeDynString = MaybeDyn>; +impl_from_maybe_dyn!(MaybeDynString => &'static str, String); + +/// A possibly dynamic boolean value. +pub type MaybeDynBool = MaybeDyn; + +/// A possibly dynamic [`JsValue`]. +pub type MaybeDynJsValue = MaybeDyn; +impl_from_maybe_dyn!( + MaybeDynJsValue => + String, + bool, + i8, + i16, + i32, + i64, + i128, + isize, + u8, + u16, + u32, + u64, + u128, + usize, + f32, + f64 +); +impl_into_self!(Cow<'static, str>, bool, JsValue); + +impl_into_self!(i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64); diff --git a/packages/sycamore-web/src/node/mod.rs b/packages/sycamore-web/src/node/mod.rs index e877b544..9b23b149 100644 --- a/packages/sycamore-web/src/node/mod.rs +++ b/packages/sycamore-web/src/node/mod.rs @@ -99,74 +99,6 @@ impl AttributeValue for MaybeDynJsValue { } } -/// Represents a value that can be either static or dynamic. -pub enum MaybeDyn { - Static(T), - Dynamic(Box T>), -} - -impl MaybeDyn { - /// Evaluate the value by consuming itself. - pub fn evaluate(self) -> T { - match self { - Self::Static(value) => value, - Self::Dynamic(mut f) => f(), - } - } -} - -impl U + 'static, U: Into> From for MaybeDyn { - fn from(mut f: F) -> Self { - Self::Dynamic(Box::new(move || f().into())) - } -} - -/// A possibly dynamic string value. -pub type MaybeDynString = MaybeDyn>; - -/// A possibly dynamic boolean value. -pub type MaybeDynBool = MaybeDyn; - -/// A possibly dynamic [`JsValue`]. -pub type MaybeDynJsValue = MaybeDyn; - -macro_rules! impl_from_maybe_dyn { - ($struct:ty => $($ty:ty),*) => { - $( - impl From<$ty> for $struct { - fn from(value: $ty) -> Self { - Self::Static(value.into()) - } - } - )* - }; -} - -impl_from_maybe_dyn!(MaybeDynString => &'static str, String, Cow<'static, str>); - -impl_from_maybe_dyn!(MaybeDynBool => bool); - -impl_from_maybe_dyn!( - MaybeDynJsValue => - JsValue, - String, - bool, - i8, - i16, - i32, - i64, - i128, - isize, - u8, - u16, - u32, - u64, - u128, - usize, - f32, - f64 -); - thread_local! { /// Whether we are in hydration mode or not. pub(crate) static IS_HYDRATING: Cell = const { Cell::new(false) };