diff --git a/src/core/element_maybe_signal.rs b/src/core/element_maybe_signal.rs index cc85d43..866c618 100644 --- a/src/core/element_maybe_signal.rs +++ b/src/core/element_maybe_signal.rs @@ -1,10 +1,11 @@ use crate::{UseDocument, UseWindow}; use cfg_if::cfg_if; -use leptos::html::HtmlElement; +use leptos::html::{CreateElement, ElementType}; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; +use send_wrapper::SendWrapper; use std::marker::PhantomData; -use std::ops::Deref; +use wasm_bindgen::JsCast; /// Used as an argument type to make it easily possible to pass either /// @@ -19,9 +20,9 @@ pub enum ElementMaybeSignal where T: Into + Clone + 'static, { - Static(Option), - Dynamic(Signal>), - _Phantom(PhantomData), + Static(SendWrapper>), + Dynamic(Signal, LocalStorage>), + _Phantom(PhantomData E>), } impl Default for ElementMaybeSignal @@ -29,7 +30,7 @@ where T: Into + Clone + 'static, { fn default() -> Self { - Self::Static(None) + Self::Static(SendWrapper::new(None)) } } @@ -63,15 +64,18 @@ where fn with(&self, f: impl FnOnce(&Option) -> O) -> O { match self { - Self::Static(t) => f(t), - Self::Dynamic(s) => s.with(f), + Self::Static(t) => f(&t), + Self::Dynamic(s) => { + let value = s.get(); + f(&value) + } _ => unreachable!(), } } fn try_with(&self, f: impl FnOnce(&Option) -> O) -> Option { match self { - Self::Static(t) => Some(f(t)), + Self::Static(t) => Some(f(&t)), Self::Dynamic(s) => s.try_with(f), _ => unreachable!(), } @@ -86,7 +90,7 @@ where fn with_untracked(&self, f: impl FnOnce(&Option) -> O) -> O { match self { - Self::Static(t) => f(t), + Self::Static(t) => f(&t), Self::Dynamic(s) => s.with_untracked(f), _ => unreachable!(), } @@ -94,7 +98,7 @@ where fn try_with_untracked(&self, f: impl FnOnce(&Option) -> O) -> Option { match self { - Self::Static(t) => Some(f(t)), + Self::Static(t) => Some(f(&t)), Self::Dynamic(s) => s.try_with_untracked(f), _ => unreachable!(), } @@ -108,7 +112,7 @@ where T: Into + Clone + 'static, { fn from(value: T) -> Self { - ElementMaybeSignal::Static(Some(value)) + ElementMaybeSignal::Static(SendWrapper::new(Some(value))) } } @@ -117,7 +121,7 @@ where T: Into + Clone + 'static, { fn from(target: Option) -> Self { - ElementMaybeSignal::Static(target) + ElementMaybeSignal::Static(SendWrapper::new(target)) } } @@ -128,7 +132,7 @@ macro_rules! impl_from_deref_option { E: From<$ty2> + 'static, { fn from(value: $ty) -> Self { - Self::Static((*value).clone()) + Self::Static(SendWrapper::new((*value).clone())) } } }; @@ -146,9 +150,9 @@ where fn from(target: &'a str) -> Self { cfg_if! { if #[cfg(feature = "ssr")] { let _ = target; - Self::Static(None) + Self::Static(SendWrapper::new(None)) } else { - Self::Static(document().query_selector(target).unwrap_or_default()) + Self::Static(SendWrapper::new(document().query_selector(target).unwrap_or_default())) }} } } @@ -171,10 +175,10 @@ macro_rules! impl_from_signal_string { fn from(signal: $ty) -> Self { cfg_if! { if #[cfg(feature = "ssr")] { let _ = signal; - Self::Dynamic(Signal::derive(|| None)) + Self::Dynamic(Signal::derive_local(|| None)) } else { Self::Dynamic( - Signal::derive(move || document().query_selector(&signal.get()).unwrap_or_default()), + Signal::derive_local(move || document().query_selector(&signal.get()).unwrap_or_default()), ) }} } @@ -187,10 +191,10 @@ impl_from_signal_string!(ReadSignal); impl_from_signal_string!(RwSignal); impl_from_signal_string!(Memo); -impl_from_signal_string!(Signal<&str>); -impl_from_signal_string!(ReadSignal<&str>); -impl_from_signal_string!(RwSignal<&str>); -impl_from_signal_string!(Memo<&str>); +impl_from_signal_string!(Signal<&'static str>); +impl_from_signal_string!(ReadSignal<&'static str>); +impl_from_signal_string!(RwSignal<&'static str>); +impl_from_signal_string!(Memo<&'static str>); // From signal /////////////////////////////////////////////////////////////// @@ -207,10 +211,10 @@ macro_rules! impl_from_signal_option { }; } -impl_from_signal_option!(Signal>); -impl_from_signal_option!(ReadSignal>); -impl_from_signal_option!(RwSignal>); -impl_from_signal_option!(Memo>); +impl_from_signal_option!(Signal, LocalStorage>); +impl_from_signal_option!(ReadSignal, LocalStorage>); +impl_from_signal_option!(RwSignal, LocalStorage>); +impl_from_signal_option!(Memo, LocalStorage>); macro_rules! impl_from_signal { ($ty:ty) => { @@ -219,16 +223,16 @@ macro_rules! impl_from_signal { T: Into + Clone + 'static, { fn from(signal: $ty) -> Self { - Self::Dynamic(Signal::derive(move || Some(signal.get()))) + Self::Dynamic(Signal::derive_local(move || Some(signal.get()))) } } }; } -impl_from_signal!(Signal); -impl_from_signal!(ReadSignal); -impl_from_signal!(RwSignal); -impl_from_signal!(Memo); +impl_from_signal!(Signal); +impl_from_signal!(ReadSignal); +impl_from_signal!(RwSignal); +impl_from_signal!(Memo); // From NodeRef ////////////////////////////////////////////////////////////// @@ -236,13 +240,13 @@ macro_rules! impl_from_node_ref { ($ty:ty) => { impl From> for ElementMaybeSignal<$ty, $ty> where - R: ElementDescriptor + Clone + 'static, + R: ElementType + CreateElement + Clone + Send + Sync + 'static, + R::Output: JsCast + Into<$ty> + Clone + 'static, { fn from(node_ref: NodeRef) -> Self { - Self::Dynamic(Signal::derive(move || { + Self::Dynamic(Signal::derive_local(move || { node_ref.get().map(move |el| { - let el = el.into_any(); - let el: $ty = el.deref().clone().into(); + let el: $ty = el.clone().into(); el }) })) @@ -255,90 +259,90 @@ impl_from_node_ref!(web_sys::EventTarget); impl_from_node_ref!(web_sys::Element); impl_from_node_ref!(web_sys::HtmlElement); -// From leptos::html::HTMLElement /////////////////////////////////////////////// - -macro_rules! impl_from_html_element { - ($ty:ty) => { - impl From> for ElementMaybeSignal<$ty, $ty> - where - HtmlEl: ElementDescriptor + std::ops::Deref, - { - fn from(value: HtmlElement) -> Self { - let el: &$ty = value.deref(); - Self::Static(Some(el.clone())) - } - } - }; -} - -impl_from_html_element!(web_sys::EventTarget); -impl_from_html_element!(web_sys::Element); -impl_from_html_element!(web_sys::HtmlElement); - -// From Signal ///////////////////////////////////////// - -macro_rules! impl_from_signal_html_element { - ($signal:ty, $ty:ty) => { - impl From<$signal> for ElementMaybeSignal<$ty, $ty> - where - HtmlEl: ElementDescriptor + std::ops::Deref + Clone, - { - fn from(value: $signal) -> Self { - Self::Dynamic(Signal::derive(move || { - let value = value.get(); - let el: &$ty = value.deref(); - Some(el.clone()) - })) - } - } - }; -} - -impl_from_signal_html_element!(Signal>, web_sys::EventTarget); -impl_from_signal_html_element!(ReadSignal>, web_sys::EventTarget); -impl_from_signal_html_element!(RwSignal>, web_sys::EventTarget); -impl_from_signal_html_element!(Memo>, web_sys::EventTarget); - -impl_from_signal_html_element!(Signal>, web_sys::Element); -impl_from_signal_html_element!(ReadSignal>, web_sys::Element); -impl_from_signal_html_element!(RwSignal>, web_sys::Element); -impl_from_signal_html_element!(Memo>, web_sys::Element); - -// From Signal> ///////////////////////////////////////// - -macro_rules! impl_from_signal_html_element { - ($signal:ty, $ty:ty) => { - impl From<$signal> for ElementMaybeSignal<$ty, $ty> - where - HtmlEl: ElementDescriptor + std::ops::Deref + Clone, - { - fn from(value: $signal) -> Self { - Self::Dynamic(Signal::derive(move || { - let el: Option<$ty> = value.get().map(|el| el.deref().clone()); - el - })) - } - } - }; -} - -impl_from_signal_html_element!(Signal>>, web_sys::EventTarget); -impl_from_signal_html_element!( - ReadSignal>>, - web_sys::EventTarget -); -impl_from_signal_html_element!(RwSignal>>, web_sys::EventTarget); -impl_from_signal_html_element!(Memo>>, web_sys::EventTarget); - -impl_from_signal_html_element!(Signal>>, web_sys::Element); -impl_from_signal_html_element!(ReadSignal>>, web_sys::Element); -impl_from_signal_html_element!(RwSignal>>, web_sys::Element); -impl_from_signal_html_element!(Memo>>, web_sys::Element); - -impl_from_signal_html_element!(Signal>>, web_sys::HtmlElement); -impl_from_signal_html_element!( - ReadSignal>>, - web_sys::HtmlElement -); -impl_from_signal_html_element!(RwSignal>>, web_sys::HtmlElement); -impl_from_signal_html_element!(Memo>>, web_sys::HtmlElement); +// // From leptos::html::HTMLElement /////////////////////////////////////////////// +// +// macro_rules! impl_from_html_element { +// ($ty:ty) => { +// impl From> for ElementMaybeSignal<$ty, $ty> +// where +// HtmlEl: ElementDescriptor + std::ops::Deref, +// { +// fn from(value: HtmlElement) -> Self { +// let el: &$ty = value.deref(); +// Self::Static(Some(el.clone())) +// } +// } +// }; +// } +// +// impl_from_html_element!(web_sys::EventTarget); +// impl_from_html_element!(web_sys::Element); +// impl_from_html_element!(web_sys::HtmlElement); +// +// // From Signal ///////////////////////////////////////// +// +// macro_rules! impl_from_signal_html_element { +// ($signal:ty, $ty:ty) => { +// impl From<$signal> for ElementMaybeSignal<$ty, $ty> +// where +// HtmlEl: ElementDescriptor + std::ops::Deref + Clone, +// { +// fn from(value: $signal) -> Self { +// Self::Dynamic(Signal::derive(move || { +// let value = value.get(); +// let el: &$ty = value.deref(); +// Some(el.clone()) +// })) +// } +// } +// }; +// } +// +// impl_from_signal_html_element!(Signal>, web_sys::EventTarget); +// impl_from_signal_html_element!(ReadSignal>, web_sys::EventTarget); +// impl_from_signal_html_element!(RwSignal>, web_sys::EventTarget); +// impl_from_signal_html_element!(Memo>, web_sys::EventTarget); +// +// impl_from_signal_html_element!(Signal>, web_sys::Element); +// impl_from_signal_html_element!(ReadSignal>, web_sys::Element); +// impl_from_signal_html_element!(RwSignal>, web_sys::Element); +// impl_from_signal_html_element!(Memo>, web_sys::Element); +// +// // From Signal> ///////////////////////////////////////// +// +// macro_rules! impl_from_signal_html_element { +// ($signal:ty, $ty:ty) => { +// impl From<$signal> for ElementMaybeSignal<$ty, $ty> +// where +// HtmlEl: ElementDescriptor + std::ops::Deref + Clone, +// { +// fn from(value: $signal) -> Self { +// Self::Dynamic(Signal::derive(move || { +// let el: Option<$ty> = value.get().map(|el| el.deref().clone()); +// el +// })) +// } +// } +// }; +// } +// +// impl_from_signal_html_element!(Signal>>, web_sys::EventTarget); +// impl_from_signal_html_element!( +// ReadSignal>>, +// web_sys::EventTarget +// ); +// impl_from_signal_html_element!(RwSignal>>, web_sys::EventTarget); +// impl_from_signal_html_element!(Memo>>, web_sys::EventTarget); +// +// impl_from_signal_html_element!(Signal>>, web_sys::Element); +// impl_from_signal_html_element!(ReadSignal>>, web_sys::Element); +// impl_from_signal_html_element!(RwSignal>>, web_sys::Element); +// impl_from_signal_html_element!(Memo>>, web_sys::Element); +// +// impl_from_signal_html_element!(Signal>>, web_sys::HtmlElement); +// impl_from_signal_html_element!( +// ReadSignal>>, +// web_sys::HtmlElement +// ); +// impl_from_signal_html_element!(RwSignal>>, web_sys::HtmlElement); +// impl_from_signal_html_element!(Memo>>, web_sys::HtmlElement); diff --git a/src/core/elements_maybe_signal.rs b/src/core/elements_maybe_signal.rs index 931c14a..26ef88c 100644 --- a/src/core/elements_maybe_signal.rs +++ b/src/core/elements_maybe_signal.rs @@ -1,11 +1,12 @@ use crate::core::ElementMaybeSignal; use crate::{UseDocument, UseWindow}; use cfg_if::cfg_if; -use leptos::html::ElementDescriptor; +use leptos::html::ElementType; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; +use send_wrapper::SendWrapper; use std::marker::PhantomData; -use std::ops::Deref; +use wasm_bindgen::JsCast; /// Used as an argument type to make it easily possible to pass either /// @@ -20,9 +21,9 @@ pub enum ElementsMaybeSignal where T: Into + Clone + 'static, { - Static(Vec>), - Dynamic(Signal>>), - _Phantom(PhantomData), + Static(SendWrapper>>), + Dynamic(Signal>, LocalStorage>), + _Phantom(PhantomData E>), } impl Default for ElementsMaybeSignal @@ -30,7 +31,7 @@ where T: Into + Clone + 'static, { fn default() -> Self { - Self::Static(vec![]) + Self::Static(SendWrapper::new(vec![])) } } @@ -109,7 +110,7 @@ where T: Into + Clone + 'static, { fn from(value: T) -> Self { - ElementsMaybeSignal::Static(vec![Some(value)]) + ElementsMaybeSignal::Static(SendWrapper::new(vec![Some(value)])) } } @@ -118,7 +119,7 @@ where T: Into + Clone + 'static, { fn from(target: Option) -> Self { - ElementsMaybeSignal::Static(vec![target]) + ElementsMaybeSignal::Static(SendWrapper::new(vec![target])) } } @@ -129,7 +130,7 @@ macro_rules! impl_from_deref_option { E: From<$ty2> + 'static, { fn from(value: $ty) -> Self { - Self::Static(vec![(*value).clone()]) + Self::Static(SendWrapper::new(vec![(*value).clone()])) } } }; @@ -147,7 +148,7 @@ where fn from(target: &'a str) -> Self { cfg_if! { if #[cfg(feature = "ssr")] { let _ = target; - Self::Static(vec![]) + Self::Static(SendWrapper::new(vec![])) } else { if let Ok(node_list) = document().query_selector_all(target) { let mut list = Vec::with_capacity(node_list.length() as usize); @@ -156,9 +157,9 @@ where list.push(Some(node)); } - Self::Static(list) + Self::Static(SendWrapper::new(list)) } else { - Self::Static(vec![]) + Self::Static(SendWrapper::new(vec![])) } }} } @@ -182,7 +183,7 @@ macro_rules! impl_from_signal_string { fn from(signal: $ty) -> Self { cfg_if! { if #[cfg(feature = "ssr")] { Self::Dynamic( - Signal::derive(move || { + Signal::derive_local(move || { if let Ok(node_list) = document().query_selector_all(&signal.get()) { let mut list = Vec::with_capacity(node_list.length() as usize); for i in 0..node_list.length() { @@ -197,7 +198,7 @@ macro_rules! impl_from_signal_string { ) } else { let _ = signal; - Self::Dynamic(Signal::derive(Vec::new)) + Self::Dynamic(Signal::derive_local(Vec::new)) }} } } @@ -209,10 +210,10 @@ impl_from_signal_string!(ReadSignal); impl_from_signal_string!(RwSignal); impl_from_signal_string!(Memo); -impl_from_signal_string!(Signal<&str>); -impl_from_signal_string!(ReadSignal<&str>); -impl_from_signal_string!(RwSignal<&str>); -impl_from_signal_string!(Memo<&str>); +impl_from_signal_string!(Signal<&'static str>); +impl_from_signal_string!(ReadSignal<&'static str>); +impl_from_signal_string!(RwSignal<&'static str>); +impl_from_signal_string!(Memo<&'static str>); // From single signal /////////////////////////////////////////////////////////////// @@ -223,16 +224,16 @@ macro_rules! impl_from_signal_option { T: Into + Clone + 'static, { fn from(signal: $ty) -> Self { - Self::Dynamic(Signal::derive(move || vec![signal.get()])) + Self::Dynamic(Signal::derive_local(move || vec![signal.get()])) } } }; } -impl_from_signal_option!(Signal>); -impl_from_signal_option!(ReadSignal>); -impl_from_signal_option!(RwSignal>); -impl_from_signal_option!(Memo>); +impl_from_signal_option!(Signal, LocalStorage>); +impl_from_signal_option!(ReadSignal, LocalStorage>); +impl_from_signal_option!(RwSignal, LocalStorage>); +impl_from_signal_option!(Memo, LocalStorage>); macro_rules! impl_from_signal { ($ty:ty) => { @@ -241,16 +242,16 @@ macro_rules! impl_from_signal { T: Into + Clone + 'static, { fn from(signal: $ty) -> Self { - Self::Dynamic(Signal::derive(move || vec![Some(signal.get())])) + Self::Dynamic(Signal::derive_local(move || vec![Some(signal.get())])) } } }; } -impl_from_signal!(Signal); -impl_from_signal!(ReadSignal); -impl_from_signal!(RwSignal); -impl_from_signal!(Memo); +impl_from_signal!(Signal); +impl_from_signal!(ReadSignal); +impl_from_signal!(RwSignal); +impl_from_signal!(Memo); // From single NodeRef ////////////////////////////////////////////////////////////// @@ -258,13 +259,13 @@ macro_rules! impl_from_node_ref { ($ty:ty) => { impl From> for ElementsMaybeSignal<$ty, $ty> where - R: ElementDescriptor + Clone + 'static, + R: ElementType + Clone + 'static, + R::Output: JsCast + Into<$ty> + Clone + 'static, { fn from(node_ref: NodeRef) -> Self { - Self::Dynamic(Signal::derive(move || { + Self::Dynamic(Signal::derive_local(move || { vec![node_ref.get().map(move |el| { - let el = el.into_any(); - let el: $ty = el.deref().clone().into(); + let el: $ty = el.clone().into(); el })] })) @@ -278,22 +279,23 @@ impl_from_node_ref!(web_sys::Element); // From single leptos::html::HTMLElement /////////////////////////////////////////// -macro_rules! impl_from_html_element { - ($ty:ty) => { - impl From> for ElementsMaybeSignal<$ty, $ty> - where - HtmlEl: ElementDescriptor + std::ops::Deref, - { - fn from(value: HtmlElement) -> Self { - let el: &$ty = value.deref(); - Self::Static(vec![Some(el.clone())]) - } - } - }; -} - -impl_from_html_element!(web_sys::EventTarget); -impl_from_html_element!(web_sys::Element); +// macro_rules! impl_from_html_element { +// ($ty:ty) => { +// impl From> for ElementsMaybeSignal<$ty, $ty> +// where +// E: ElementType, +// E::Output: std::ops::Deref, +// { +// fn from(value: HtmlElement) -> Self { +// let el: &$ty = value.deref(); +// Self::Static(vec![Some(el.clone())]) +// } +// } +// }; +// } +// +// impl_from_html_element!(web_sys::EventTarget); +// impl_from_html_element!(web_sys::Element); // From multiple static elements ////////////////////////////////////////////////////// @@ -302,7 +304,9 @@ where T: Into + Clone + 'static, { fn from(target: &[T]) -> Self { - Self::Static(target.iter().map(|t| Some(t.clone())).collect()) + Self::Static(SendWrapper::new( + target.iter().map(|t| Some(t.clone())).collect(), + )) } } @@ -311,7 +315,7 @@ where T: Into + Clone + 'static, { fn from(target: &[Option]) -> Self { - Self::Static(target.to_vec()) + Self::Static(SendWrapper::new(target.iter().map(|t| t.clone()).collect())) } } @@ -320,7 +324,9 @@ where T: Into + Clone + 'static, { fn from(target: Vec) -> Self { - Self::Static(target.iter().map(|t| Some(t.clone())).collect()) + Self::Static(SendWrapper::new( + target.iter().map(|t| Some(t.clone())).collect(), + )) } } @@ -329,7 +335,7 @@ where T: Into + Clone + 'static, { fn from(target: Vec>) -> Self { - Self::Static(target.to_vec()) + Self::Static(SendWrapper::new(target.into_iter().map(|t| t).collect())) } } @@ -338,7 +344,9 @@ where T: Into + Clone + 'static, { fn from(target: [T; C]) -> Self { - Self::Static(target.iter().map(|t| Some(t.clone())).collect()) + Self::Static(SendWrapper::new( + target.into_iter().map(|t| Some(t)).collect(), + )) } } @@ -347,7 +355,7 @@ where T: Into + Clone + 'static, { fn from(target: [Option; C]) -> Self { - Self::Static(target.to_vec()) + Self::Static(SendWrapper::new(target.into_iter().collect())) } } @@ -356,30 +364,32 @@ where macro_rules! impl_from_strings_inner { ($el_ty:ty, $str_ty:ty, $target:ident) => { Self::Static( - $target - .iter() - .filter_map(|sel: &$str_ty| -> Option>> { - cfg_if! { if #[cfg(feature = "ssr")] { - let _ = sel; - None - } else { - use wasm_bindgen::JsCast; - - if let Ok(node_list) = document().query_selector_all(sel) { - let mut list = Vec::with_capacity(node_list.length() as usize); - for i in 0..node_list.length() { - let node: $el_ty = node_list.get(i).expect("checked the range").unchecked_into(); - list.push(Some(node)); - } - - Some(list) - } else { + SendWrapper::new( + $target + .iter() + .filter_map(|sel: &$str_ty| -> Option>> { + cfg_if! { if #[cfg(feature = "ssr")] { + let _ = sel; None - } - }} - }) - .flatten() - .collect(), + } else { + use wasm_bindgen::JsCast; + + if let Ok(node_list) = document().query_selector_all(sel) { + let mut list = Vec::with_capacity(node_list.length() as usize); + for i in 0..node_list.length() { + let node: $el_ty = node_list.get(i).expect("checked the range").unchecked_into(); + list.push(Some(node)); + } + + Some(list) + } else { + None + } + }} + }) + .flatten() + .collect(), + ) ) }; } @@ -418,101 +428,101 @@ impl_from_strings!(web_sys::EventTarget, String); // From signal of vec //////////////////////////////////////////////////////////////// -impl From>> for ElementsMaybeSignal +impl From, LocalStorage>> for ElementsMaybeSignal where T: Into + Clone + 'static, { - fn from(signal: Signal>) -> Self { - Self::Dynamic(Signal::derive(move || { + fn from(signal: Signal, LocalStorage>) -> Self { + Self::Dynamic(Signal::derive_local(move || { signal.get().into_iter().map(|t| Some(t)).collect() })) } } -impl From>>> for ElementsMaybeSignal +impl From>, LocalStorage>> for ElementsMaybeSignal where T: Into + Clone + 'static, { - fn from(target: Signal>>) -> Self { + fn from(target: Signal>, LocalStorage>) -> Self { Self::Dynamic(target) } } // From multiple signals ////////////////////////////////////////////////////////////// -impl From<&[Signal]> for ElementsMaybeSignal +impl From<&[Signal]> for ElementsMaybeSignal where T: Into + Clone + 'static, { - fn from(list: &[Signal]) -> Self { + fn from(list: &[Signal]) -> Self { let list = list.to_vec(); - Self::Dynamic(Signal::derive(move || { + Self::Dynamic(Signal::derive_local(move || { list.iter().map(|t| Some(t.get())).collect() })) } } -impl From<&[Signal>]> for ElementsMaybeSignal +impl From<&[Signal, LocalStorage>]> for ElementsMaybeSignal where T: Into + Clone + 'static, { - fn from(list: &[Signal>]) -> Self { + fn from(list: &[Signal, LocalStorage>]) -> Self { let list = list.to_vec(); - Self::Dynamic(Signal::derive(move || { + Self::Dynamic(Signal::derive_local(move || { list.iter().map(|t| t.get()).collect() })) } } -impl From>> for ElementsMaybeSignal +impl From>> for ElementsMaybeSignal where T: Into + Clone + 'static, { - fn from(list: Vec>) -> Self { + fn from(list: Vec>) -> Self { let list = list.clone(); - Self::Dynamic(Signal::derive(move || { + Self::Dynamic(Signal::derive_local(move || { list.iter().map(|t| Some(t.get())).collect() })) } } -impl From>>> for ElementsMaybeSignal +impl From, LocalStorage>>> for ElementsMaybeSignal where T: Into + Clone + 'static, { - fn from(list: Vec>>) -> Self { + fn from(list: Vec, LocalStorage>>) -> Self { let list = list.clone(); - Self::Dynamic(Signal::derive(move || { + Self::Dynamic(Signal::derive_local(move || { list.iter().map(|t| t.get()).collect() })) } } -impl From<[Signal; C]> for ElementsMaybeSignal +impl From<[Signal; C]> for ElementsMaybeSignal where T: Into + Clone + 'static, { - fn from(list: [Signal; C]) -> Self { + fn from(list: [Signal; C]) -> Self { let list = list.to_vec(); - Self::Dynamic(Signal::derive(move || { + Self::Dynamic(Signal::derive_local(move || { list.iter().map(|t| Some(t.get())).collect() })) } } -impl From<[Signal>; C]> for ElementsMaybeSignal +impl From<[Signal, LocalStorage>; C]> for ElementsMaybeSignal where T: Into + Clone + 'static, { - fn from(list: [Signal>; C]) -> Self { + fn from(list: [Signal, LocalStorage>; C]) -> Self { let list = list.to_vec(); - Self::Dynamic(Signal::derive(move || { + Self::Dynamic(Signal::derive_local(move || { list.iter().map(|t| t.get()).collect() })) } @@ -522,13 +532,12 @@ where macro_rules! impl_from_multi_node_ref_inner { ($ty:ty, $node_refs:ident) => { - Self::Dynamic(Signal::derive(move || { + Self::Dynamic(Signal::derive_local(move || { $node_refs .iter() .map(|node_ref| { node_ref.get().map(move |el| { - let el = el.into_any(); - let el: $ty = el.deref().clone().into(); + let el: $ty = el.clone().into(); el }) }) @@ -541,7 +550,8 @@ macro_rules! impl_from_multi_node_ref { ($ty:ty) => { impl From<&[NodeRef]> for ElementsMaybeSignal<$ty, $ty> where - R: ElementDescriptor + Clone + 'static, + R: ElementType + Clone + 'static, + R::Output: JsCast + Into<$ty> + Clone + 'static, { fn from(node_refs: &[NodeRef]) -> Self { let node_refs = node_refs.to_vec(); @@ -551,7 +561,8 @@ macro_rules! impl_from_multi_node_ref { impl From<[NodeRef; C]> for ElementsMaybeSignal<$ty, $ty> where - R: ElementDescriptor + Clone + 'static, + R: ElementType + Clone + 'static, + R::Output: JsCast + Into<$ty> + Clone + 'static, { fn from(node_refs: [NodeRef; C]) -> Self { let node_refs = node_refs.to_vec(); @@ -561,7 +572,8 @@ macro_rules! impl_from_multi_node_ref { impl From>> for ElementsMaybeSignal<$ty, $ty> where - R: ElementDescriptor + Clone + 'static, + R: ElementType + Clone + 'static, + R::Output: JsCast + Into<$ty> + Clone + 'static, { fn from(node_refs: Vec>) -> Self { let node_refs = node_refs.clone(); @@ -574,66 +586,71 @@ macro_rules! impl_from_multi_node_ref { impl_from_multi_node_ref!(web_sys::EventTarget); impl_from_multi_node_ref!(web_sys::Element); -// From multiple leptos::html::HTMLElement ///////////////////////////////////////// - -macro_rules! impl_from_multi_html_element { - ($ty:ty) => { - impl From<&[HtmlElement]> for ElementsMaybeSignal<$ty, $ty> - where - HtmlEl: ElementDescriptor + std::ops::Deref, - { - fn from(value: &[HtmlElement]) -> Self { - Self::Static( - value - .iter() - .map(|el| { - let el: &$ty = el.deref(); - Some(el.clone()) - }) - .collect(), - ) - } - } - - impl From<[HtmlElement; C]> - for ElementsMaybeSignal<$ty, $ty> - where - HtmlEl: ElementDescriptor + std::ops::Deref, - { - fn from(value: [HtmlElement; C]) -> Self { - Self::Static( - value - .iter() - .map(|el| { - let el: &$ty = el.deref(); - Some(el.clone()) - }) - .collect(), - ) - } - } - - impl From>> for ElementsMaybeSignal<$ty, $ty> - where - HtmlEl: ElementDescriptor + std::ops::Deref, - { - fn from(value: Vec>) -> Self { - Self::Static( - value - .iter() - .map(|el| { - let el: &$ty = el.deref(); - Some(el.clone()) - }) - .collect(), - ) - } - } - }; -} - -impl_from_multi_html_element!(web_sys::EventTarget); -impl_from_multi_html_element!(web_sys::Element); +// // From multiple leptos::html::HTMLElement ///////////////////////////////////////// +// +// macro_rules! impl_from_multi_html_element { +// ($ty:ty) => { +// impl From<&[HtmlElement]> +// for ElementsMaybeSignal<$ty, $ty> +// where +// E: ElementType, +// E::Output: std::ops::Deref, +// { +// fn from(value: &[HtmlElement]) -> Self { +// Self::Static( +// value +// .iter() +// .map(|el| { +// let el: &$ty = el.deref(); +// Some(el.clone()) +// }) +// .collect(), +// ) +// } +// } +// +// impl From<[HtmlElement; C]> +// for ElementsMaybeSignal<$ty, $ty> +// where +// E: ElementType, +// E::Output: std::ops::Deref, +// { +// fn from(value: [HtmlElement; C]) -> Self { +// Self::Static( +// value +// .iter() +// .map(|el| { +// let el: &$ty = el.deref(); +// Some(el.clone()) +// }) +// .collect(), +// ) +// } +// } +// +// impl From>> +// for ElementsMaybeSignal<$ty, $ty> +// where +// E: ElementType, +// E::Output: std::ops::Deref, +// { +// fn from(value: Vec>) -> Self { +// Self::Static( +// value +// .iter() +// .map(|el| { +// let el: &$ty = el.deref(); +// Some(el.clone()) +// }) +// .collect(), +// ) +// } +// } +// }; +// } +// +// impl_from_multi_html_element!(web_sys::EventTarget); +// impl_from_multi_html_element!(web_sys::Element); // From ElementMaybeSignal ////////////////////////////////////////////////////////////// @@ -644,9 +661,11 @@ where fn from(signal: ElementMaybeSignal) -> Self { match signal { ElementMaybeSignal::Dynamic(signal) => { - Self::Dynamic(Signal::derive(move || vec![signal.get()])) + Self::Dynamic(Signal::derive_local(move || vec![signal.get()])) + } + ElementMaybeSignal::Static(el) => { + Self::Static(SendWrapper::new(vec![SendWrapper::take(el)])) } - ElementMaybeSignal::Static(el) => Self::Static(vec![el]), ElementMaybeSignal::_Phantom(_) => unreachable!(), } } diff --git a/src/core/maybe_rw_signal.rs b/src/core/maybe_rw_signal.rs index cc7cbd0..c539d70 100644 --- a/src/core/maybe_rw_signal.rs +++ b/src/core/maybe_rw_signal.rs @@ -1,16 +1,20 @@ use leptos::prelude::*; use std::fmt::Debug; -pub enum MaybeRwSignal +pub enum MaybeRwSignal where T: 'static, + S: Storage, { Static(T), - DynamicRw(Signal, WriteSignal), - DynamicRead(Signal), + DynamicRw(Signal, WriteSignal), + DynamicRead(Signal), } -impl Clone for MaybeRwSignal { +impl Clone for MaybeRwSignal +where + S: Storage, +{ fn clone(&self) -> Self { match self { Self::Static(t) => Self::Static(t.clone()), @@ -20,21 +24,21 @@ impl Clone for MaybeRwSignal { } } -impl Copy for MaybeRwSignal {} +impl Copy for MaybeRwSignal where S: Storage {} -impl From for MaybeRwSignal { - fn from(t: T) -> Self { - Self::Static(t) - } -} - -impl Default for MaybeRwSignal { +impl Default for MaybeRwSignal +where + S: Storage, +{ fn default() -> Self { Self::Static(T::default()) } } -impl Debug for MaybeRwSignal { +impl Debug for MaybeRwSignal +where + S: Storage + Debug, +{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Static(t) => f.debug_tuple("Static").field(t).finish(), @@ -44,50 +48,172 @@ impl Debug for MaybeRwSignal { } } -impl From> for MaybeRwSignal { +impl From for MaybeRwSignal +where + SyncStorage: Storage, +{ + fn from(t: T) -> Self { + Self::Static(t) + } +} + +impl FromLocal for MaybeRwSignal +where + LocalStorage: Storage, +{ + fn from_local(value: T) -> Self { + Self::Static(value) + } +} + +impl From> for MaybeRwSignal +where + SyncStorage: Storage, +{ fn from(s: Signal) -> Self { Self::DynamicRead(s) } } -impl From> for MaybeRwSignal { +impl FromLocal> for MaybeRwSignal +where + LocalStorage: Storage, +{ + fn from_local(s: Signal) -> Self { + Self::DynamicRead(s) + } +} + +impl From> for MaybeRwSignal +where + T: Send + Sync, +{ fn from(s: ReadSignal) -> Self { Self::DynamicRead(s.into()) } } -impl From> for MaybeRwSignal { +impl FromLocal> for MaybeRwSignal +where + LocalStorage: Storage, +{ + fn from_local(s: ReadSignal) -> Self { + Self::DynamicRead(s.into()) + } +} + +impl From> for MaybeRwSignal +where + T: Send + Sync, +{ fn from(s: Memo) -> Self { Self::DynamicRead(s.into()) } } -impl From> for MaybeRwSignal { +impl FromLocal> for MaybeRwSignal +where + LocalStorage: Storage, +{ + fn from_local(s: Memo) -> Self { + Self::DynamicRead(s.into()) + } +} + +impl From> for MaybeRwSignal +where + T: Send + Sync, +{ fn from(s: RwSignal) -> Self { let (r, w) = s.split(); Self::DynamicRw(r.into(), w) } } -impl From<(ReadSignal, WriteSignal)> for MaybeRwSignal { +impl FromLocal> for MaybeRwSignal +where + LocalStorage: Storage, +{ + fn from_local(s: RwSignal) -> Self { + let (r, w) = s.split(); + Self::DynamicRw(r.into(), w) + } +} + +impl From<(ReadSignal, WriteSignal)> for MaybeRwSignal +where + T: Send + Sync, +{ fn from(s: (ReadSignal, WriteSignal)) -> Self { Self::DynamicRw(s.0.into(), s.1) } } -impl From<(Signal, WriteSignal)> for MaybeRwSignal { +impl FromLocal<(ReadSignal, WriteSignal)> + for MaybeRwSignal +where + LocalStorage: Storage, +{ + fn from_local(s: (ReadSignal, WriteSignal)) -> Self { + Self::DynamicRw(s.0.into(), s.1) + } +} + +impl From<(Signal, WriteSignal)> for MaybeRwSignal +where + T: Send + Sync, +{ fn from(s: (Signal, WriteSignal)) -> Self { Self::DynamicRw(s.0, s.1) } } -impl From<&str> for MaybeRwSignal { +impl FromLocal<(Signal, WriteSignal)> + for MaybeRwSignal +where + LocalStorage: Storage, +{ + fn from_local(s: (Signal, WriteSignal)) -> Self { + Self::DynamicRw(s.0, s.1) + } +} + +impl From<&str> for MaybeRwSignal +where + S: Storage, +{ fn from(s: &str) -> Self { Self::Static(s.to_string()) } } -impl MaybeRwSignal { +impl MaybeRwSignal { + pub fn into_signal(self) -> (Signal, WriteSignal) { + match self { + Self::DynamicRead(s) => { + let (r, w) = signal_local(s.get_untracked()); + + Effect::::new(move |_| { + w.update(move |w| { + *w = s.get(); + }); + }); + + (r.into(), w) + } + Self::DynamicRw(r, w) => (r, w), + Self::Static(v) => { + let (r, w) = signal_local(v.clone()); + (Signal::from(r), w) + } + } + } +} + +impl MaybeRwSignal +where + T: Send + Sync, +{ pub fn into_signal(self) -> (Signal, WriteSignal) { match self { Self::DynamicRead(s) => { diff --git a/src/core/use_rw_signal.rs b/src/core/use_rw_signal.rs index a57ec23..c86e722 100644 --- a/src/core/use_rw_signal.rs +++ b/src/core/use_rw_signal.rs @@ -1,26 +1,42 @@ use leptos::prelude::*; -pub enum UseRwSignal { - Separate(Signal, WriteSignal), - Combined(RwSignal), +pub enum UseRwSignal +where + S: Storage, +{ + Separate(Signal, WriteSignal), + Combined(RwSignal), } -impl From> for UseRwSignal { - fn from(s: RwSignal) -> Self { +impl From> for UseRwSignal +where + S: Storage, +{ + fn from(s: RwSignal) -> Self { Self::Combined(s) } } -impl From<(RS, WriteSignal)> for UseRwSignal +impl From<(RS, WriteSignal)> for UseRwSignal where - RS: Into>, + RS: Into>, + S: Storage, { - fn from(s: (RS, WriteSignal)) -> Self { + fn from(s: (RS, WriteSignal)) -> Self { Self::Separate(s.0.into(), s.1) } } impl Default for UseRwSignal +where + T: Default + Send + Sync, +{ + fn default() -> Self { + Self::Combined(Default::default()) + } +} + +impl Default for UseRwSignal where T: Default, { @@ -29,15 +45,21 @@ where } } -impl Clone for UseRwSignal { +impl Clone for UseRwSignal +where + S: Storage, +{ fn clone(&self) -> Self { *self } } -impl Copy for UseRwSignal {} +impl Copy for UseRwSignal where S: Storage {} -impl DefinedAt for UseRwSignal { +impl DefinedAt for UseRwSignal +where + S: Storage, +{ fn defined_at(&self) -> Option<&'static std::panic::Location<'static>> { match self { Self::Combined(s) => s.defined_at(), @@ -47,7 +69,13 @@ impl DefinedAt for UseRwSignal { } } -impl With for UseRwSignal { +impl With for UseRwSignal +where + RwSignal: With, + Signal: With, + ReadSignal: With, + S: Storage, +{ type Value = T; fn with(&self, f: impl FnOnce(&T) -> R) -> R { @@ -65,7 +93,13 @@ impl With for UseRwSignal { } } -impl WithUntracked for UseRwSignal { +impl WithUntracked for UseRwSignal +where + RwSignal: WithUntracked, + Signal: WithUntracked, + ReadSignal: WithUntracked, + S: Storage, +{ type Value = T; fn with_untracked(&self, f: impl FnOnce(&T) -> R) -> R { @@ -83,7 +117,12 @@ impl WithUntracked for UseRwSignal { } } -impl Set for UseRwSignal { +impl Set for UseRwSignal +where + RwSignal: Set, + WriteSignal: Set, + S: Storage, +{ type Value = T; fn set(&self, new_value: T) { @@ -101,7 +140,12 @@ impl Set for UseRwSignal { } } -impl Update for UseRwSignal { +impl Update for UseRwSignal +where + RwSignal: Update, + WriteSignal: Update, + S: Storage, +{ type Value = T; fn update(&self, f: impl FnOnce(&mut T)) { diff --git a/src/lib.rs b/src/lib.rs index efcf708..6e85934 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,7 +28,7 @@ mod on_click_outside; mod signal_debounced; mod signal_throttled; mod sync_signal; -mod use_active_element; +// mod use_active_element; mod use_breakpoints; mod use_broadcast_channel; mod use_color_mode; @@ -94,7 +94,7 @@ pub use on_click_outside::*; pub use signal_debounced::*; pub use signal_throttled::*; pub use sync_signal::*; -pub use use_active_element::*; +// pub use use_active_element::*; pub use use_breakpoints::*; pub use use_broadcast_channel::*; pub use use_color_mode::*; @@ -140,7 +140,6 @@ pub use use_throttle_fn::*; pub use use_timeout_fn::*; pub use use_timestamp::*; pub use use_to_string::*; -pub use use_user_media::*; pub use use_web_notification::*; pub use use_websocket::*; pub use use_window::*; diff --git a/src/math/shared.rs b/src/math/shared.rs index 3d96dcd..1b6e231 100644 --- a/src/math/shared.rs +++ b/src/math/shared.rs @@ -7,9 +7,9 @@ macro_rules! use_partial_cmp { pub fn $fn_name(container: S) -> Signal> where S: Into>, - C: 'static, + C: Send + Sync + 'static, for<'a> &'a C: IntoIterator, - N: PartialOrd + Clone, + N: PartialOrd + Clone + Send + Sync, { let container = container.into(); @@ -47,8 +47,8 @@ macro_rules! use_simple_math { $(#[$outer])* pub fn [](x: S) -> Signal where - S: Into>, - N: Float, + S: Into> + Send + Sync, + N: Float + Send + Sync, { let x = x.into(); Signal::derive(move || x.get().$fn_name()) diff --git a/src/storage/use_local_storage.rs b/src/storage/use_local_storage.rs index 7305606..8886be5 100644 --- a/src/storage/use_local_storage.rs +++ b/src/storage/use_local_storage.rs @@ -20,7 +20,7 @@ pub fn use_local_storage( key: impl AsRef, ) -> (Signal, WriteSignal, impl Fn() + Clone) where - T: Clone + Default + PartialEq + Send + Sync, + T: Clone + Default + PartialEq + Send + Sync + 'static, C: Encoder + Decoder, { use_storage_with_options::( diff --git a/src/storage/use_session_storage.rs b/src/storage/use_session_storage.rs index 9fa2767..451bea8 100644 --- a/src/storage/use_session_storage.rs +++ b/src/storage/use_session_storage.rs @@ -14,7 +14,7 @@ pub fn use_session_storage( key: impl AsRef, ) -> (Signal, WriteSignal, impl Fn() + Clone) where - T: Clone + Default + PartialEq + Send + Sync, + T: Clone + Default + PartialEq + Send + Sync + 'static, C: Encoder + Decoder, { use_storage_with_options::( diff --git a/src/storage/use_storage.rs b/src/storage/use_storage.rs index a941eb3..fb80b93 100644 --- a/src/storage/use_storage.rs +++ b/src/storage/use_storage.rs @@ -6,6 +6,7 @@ use codee::{CodecError, Decoder, Encoder}; use default_struct_builder::DefaultBuilder; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; +use send_wrapper::SendWrapper; use std::sync::Arc; use thiserror::Error; use wasm_bindgen::JsValue; @@ -151,7 +152,7 @@ pub fn use_storage( key: impl AsRef, ) -> (Signal, WriteSignal, impl Fn() + Clone) where - T: Default + Clone + PartialEq + Send + Sync, + T: Default + Clone + PartialEq + Send + Sync + 'static, C: Encoder + Decoder, { use_storage_with_options::(storage_type, key, UseStorageOptions::default()) @@ -238,7 +239,7 @@ where let key = key.as_ref().to_owned(); let on_error = on_error.to_owned(); - move || { + SendWrapper::new(move || { let fetched = storage .to_owned() .and_then(|storage| { @@ -270,14 +271,15 @@ where // Revert to default None => set_data.set(default.clone()), }; - } + }) }; // Fires when storage needs to be fetched - let notify = Trigger::new(); + let notify = ArcTrigger::new(); // Refetch from storage. Keeps track of how many times we've been notified. Does not increment for calls to set_data let notify_id = Memo::::new({ + let notify = notify.clone(); let fetch_from_storage = fetch_from_storage.clone(); move |prev| { @@ -327,31 +329,43 @@ where ); } - // Fetch initial value - if delay_during_hydration && leptos::leptos_dom::HydrationCtx::is_hydrating() { - request_animation_frame(fetch_from_storage.clone()); + if delay_during_hydration + && Owner::current_shared_context() + .map(|sc| sc.during_hydration()) + .unwrap_or_default() + { + request_animation_frame({ + let fetch_from_storage = fetch_from_storage.clone(); + #[allow(clippy::redundant_closure)] + move || fetch_from_storage() + }); } else { fetch_from_storage(); } if listen_to_storage_changes { let check_key = key.as_ref().to_owned(); + let storage_notify = notify.clone(); + let custom_notify = notify.clone(); + // Listen to global storage events let _ = use_event_listener(use_window(), leptos::ev::storage, move |ev| { let ev_key = ev.key(); // Key matches or all keys deleted (None) if ev_key == Some(check_key.clone()) || ev_key.is_none() { - notify.notify() + storage_notify.trigger() } }); // Listen to internal storage events let check_key = key.as_ref().to_owned(); let _ = use_event_listener( use_window(), - ev::Custom::new(INTERNAL_STORAGE_EVENT), - move |ev: web_sys::CustomEvent| { - if Some(check_key.clone()) == ev.detail().as_string() { - notify.notify() + leptos::ev::Custom::new(INTERNAL_STORAGE_EVENT), + { + move |ev: web_sys::CustomEvent| { + if Some(check_key.clone()) == ev.detail().as_string() { + custom_notify.trigger() + } } }, ); @@ -365,9 +379,9 @@ where // Delete directly from storage let result = storage .remove_item(&key) - .map_err(UseStorageError::RemoveItemFailed); + .map_err(|e| UseStorageError::RemoveItemFailed(e)); let _ = handle_error(&on_error, result); - notify.notify(); + notify.trigger(); dispatch_storage_event(); }); } @@ -400,11 +414,11 @@ pub enum UseStorageError { #[derive(DefaultBuilder)] pub struct UseStorageOptions where - T: 'static, + T: Send + Sync + 'static, { // Callback for when an error occurs #[builder(skip)] - on_error: Arc)>, + on_error: Arc) + Send + Sync>, // Whether to continuously listen to changes from browser storage listen_to_storage_changes: bool, // Initial value to use when the storage key is not set @@ -422,13 +436,16 @@ where /// Calls the on_error callback with the given error. Removes the error from the Result to avoid double error handling. #[cfg(not(feature = "ssr"))] fn handle_error( - on_error: &Arc)>, + on_error: &Arc) + Send + Sync>, result: Result>, ) -> Result { result.map_err(|err| (on_error)(err)) } -impl Default for UseStorageOptions { +impl Default for UseStorageOptions +where + T: Send + Sync + 'static, +{ fn default() -> Self { Self { on_error: Arc::new(|_err| ()), @@ -440,9 +457,15 @@ impl Default for UseStorageOptions { } } -impl UseStorageOptions { +impl UseStorageOptions +where + T: Send + Sync + 'static, +{ /// Optional callback whenever an error occurs. - pub fn on_error(self, on_error: impl Fn(UseStorageError) + 'static) -> Self { + pub fn on_error( + self, + on_error: impl Fn(UseStorageError) + Send + Sync + 'static, + ) -> Self { Self { on_error: Arc::new(on_error), ..self diff --git a/src/sync_signal.rs b/src/sync_signal.rs index 0595ffe..0887624 100644 --- a/src/sync_signal.rs +++ b/src/sync_signal.rs @@ -148,7 +148,7 @@ pub fn sync_signal( right: impl Into>, ) -> impl Fn() + Clone where - T: Clone + PartialEq + 'static, + T: Clone + PartialEq + Send + Sync + 'static, { sync_signal_with_options(left, right, SyncSignalOptions::default()) } @@ -160,8 +160,8 @@ pub fn sync_signal_with_options( options: SyncSignalOptions, ) -> impl Fn() + Clone where - L: Clone + PartialEq + 'static, - R: Clone + PartialEq + 'static, + L: Clone + PartialEq + Send + Sync + 'static, + R: Clone + PartialEq + Send + Sync + 'static, { let SyncSignalOptions { immediate, diff --git a/src/use_breakpoints.rs b/src/use_breakpoints.rs index 3b8e838..98719d5 100644 --- a/src/use_breakpoints.rs +++ b/src/use_breakpoints.rs @@ -111,7 +111,7 @@ use std::hash::Hash; /// /// Since internally this uses [`fn@crate::use_media_query`], which returns always `false` on the server, /// the returned methods also will return `false`. -pub fn use_breakpoints( +pub fn use_breakpoints( breakpoints: HashMap, ) -> UseBreakpointsReturn { UseBreakpointsReturn { breakpoints } @@ -119,7 +119,7 @@ pub fn use_breakpoints( /// Return type of [`use_breakpoints`] #[derive(Clone)] -pub struct UseBreakpointsReturn { +pub struct UseBreakpointsReturn { breakpoints: HashMap, } @@ -185,7 +185,10 @@ macro_rules! impl_cmp_reactively { }; } -impl UseBreakpointsReturn { +impl UseBreakpointsReturn +where + K: Eq + Hash + Debug + Clone + Send + Sync + 'static, +{ fn match_(query: &str) -> bool { if let Ok(Some(query_list)) = use_window().match_media(query) { return query_list.matches(); diff --git a/src/use_broadcast_channel.rs b/src/use_broadcast_channel.rs index fbfa7f6..1c549ca 100644 --- a/src/use_broadcast_channel.rs +++ b/src/use_broadcast_channel.rs @@ -80,14 +80,17 @@ pub fn use_broadcast_channel( >::Error, > where + T: Send + Sync, C: Encoder + Decoder, + >::Error: Send + Sync, + >::Error: Send + Sync, { let is_supported = use_supported(|| js!("BroadcastChannel" in &window())); let (is_closed, set_closed) = signal(false); - let (channel, set_channel) = signal(None::); + let (channel, set_channel) = signal_local(None::); let (message, set_message) = signal(None::); - let (error, set_error) = signal( + let (error, set_error) = signal_local( None::>::Error, >::Error>>, ); @@ -178,17 +181,17 @@ where /// Return type of [`use_broadcast_channel`]. pub struct UseBroadcastChannelReturn where - T: 'static, + T: Send + Sync + 'static, PFn: Fn(&T) + Clone, CFn: Fn() + Clone, - E: 'static, - D: 'static, + E: Send + Sync + 'static, + D: Send + Sync + 'static, { /// `true` if this browser supports `BroadcastChannel`s. pub is_supported: Signal, /// The broadcast channel that is wrapped by this function - pub channel: Signal>, + pub channel: Signal, LocalStorage>, /// Latest message received from the channel pub message: Signal>, @@ -200,7 +203,7 @@ where pub close: CFn, /// Latest error as reported by the `messageerror` event. - pub error: Signal>>, + pub error: Signal>, LocalStorage>, /// Wether the channel is closed pub is_closed: Signal, diff --git a/src/use_clipboard.rs b/src/use_clipboard.rs index 42ffc5a..56cf77a 100644 --- a/src/use_clipboard.rs +++ b/src/use_clipboard.rs @@ -79,7 +79,7 @@ pub fn use_clipboard_with_options( let update_text = move |_| { if is_supported.get() { - spawn_local(async move { + leptos::spawn::spawn_local(async move { if let Some(clipboard) = window().navigator().clipboard() { if let Ok(text) = js_fut!(clipboard.read_text()).await { set_text.set(text.as_string()); @@ -102,7 +102,7 @@ pub fn use_clipboard_with_options( let start = start.clone(); let value = value.to_owned(); - spawn_local(async move { + leptos::spawn::spawn_local(async move { if let Some(clipboard) = window().navigator().clipboard() { if js_fut!(clipboard.write_text(&value)).await.is_ok() { set_text.set(Some(value)); diff --git a/src/use_color_mode.rs b/src/use_color_mode.rs index fca38fc..04bf944 100644 --- a/src/use_color_mode.rs +++ b/src/use_color_mode.rs @@ -9,8 +9,8 @@ use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; use std::fmt::{Display, Formatter}; use std::marker::PhantomData; -use std::rc::Rc; use std::str::FromStr; +use std::sync::Arc; use wasm_bindgen::JsCast; /// Reactive color mode (dark / light / customs) with auto data persistence. @@ -209,7 +209,7 @@ where if initial_value_from_url_param_to_storage { set_store.set(value); } else { - set_store.set_untracked(value); + *set_store.write_untracked() = value; } } @@ -279,7 +279,7 @@ where }; let on_changed = move |mode: ColorMode| { - on_changed(mode, Rc::new(default_on_changed.clone())); + on_changed(mode, Arc::new(default_on_changed.clone())); }; Effect::new({ @@ -427,7 +427,7 @@ where /// To get the default behaviour back you can call the provided `default_handler` function. /// It takes two parameters: /// - `mode: ColorMode`: The color mode to change to. - /// - `default_handler: Rc`: The default handler that would have been called if the `on_changed` handler had not been specified. + /// -`default_handler: Arc`: The default handler that would have been called if the `on_changed` handler had not been specified. on_changed: OnChangedFn, /// When provided, `useStorage` will be skipped. @@ -476,7 +476,7 @@ where _marker: PhantomData, } -type OnChangedFn = Rc)>; +type OnChangedFn = Arc) + Send + Sync>; impl Default for UseColorModeOptions<&'static str, web_sys::Element> { fn default() -> Self { @@ -487,7 +487,7 @@ impl Default for UseColorModeOptions<&'static str, web_sys::Element> { initial_value_from_url_param: None, initial_value_from_url_param_to_storage: false, custom_modes: vec![], - on_changed: Rc::new(move |mode, default_handler| (default_handler)(mode)), + on_changed: Arc::new(move |mode, default_handler| (default_handler)(mode)), storage_signal: None, storage_key: "leptos-use-color-scheme".into(), storage: StorageType::default(), diff --git a/src/use_cookie.rs b/src/use_cookie.rs index 4aa1138..ca33237 100644 --- a/src/use_cookie.rs +++ b/src/use_cookie.rs @@ -7,7 +7,7 @@ pub use cookie::SameSite; use cookie::{Cookie, CookieJar}; use default_struct_builder::DefaultBuilder; use leptos::prelude::*; -use std::rc::Rc; +use std::sync::Arc; /// SSR-friendly and reactive cookie access. /// @@ -139,7 +139,7 @@ use std::rc::Rc; pub fn use_cookie(cookie_name: &str) -> (Signal>, WriteSignal>) where C: Encoder + Decoder, - T: Clone, + T: Clone + Send + Sync + 'static, { use_cookie_with_options::(cookie_name, UseCookieOptions::default()) } @@ -151,7 +151,7 @@ pub fn use_cookie_with_options( ) -> (Signal>, WriteSignal>) where C: Encoder + Decoder, - T: Clone, + T: Clone + Send + Sync + 'static, { let UseCookieOptions { max_age, @@ -185,7 +185,7 @@ where let jar = StoredValue::new(CookieJar::new()); if !has_expired { - let ssr_cookies_header_getter = Rc::clone(&ssr_cookies_header_getter); + let ssr_cookies_header_getter = Arc::clone(&ssr_cookies_header_getter); jar.update_value(|jar| { if let Some(new_jar) = load_and_parse_cookie_jar(ssr_cookies_header_getter) { @@ -225,8 +225,8 @@ where let on_cookie_change = { let cookie_name = cookie_name.to_owned(); - let ssr_cookies_header_getter = Rc::clone(&ssr_cookies_header_getter); - let on_error = Rc::clone(&on_error); + let ssr_cookies_header_getter = Arc::clone(&ssr_cookies_header_getter); + let on_error = Arc::clone(&on_error); let domain = domain.clone(); let path = path.clone(); @@ -261,7 +261,7 @@ where same_site, secure, http_only, - Rc::clone(&ssr_cookies_header_getter), + Arc::clone(&ssr_cookies_header_getter), ); }); @@ -284,7 +284,7 @@ where // listen to cookie changes from the broadcast channel Effect::new({ - let ssr_cookies_header_getter = Rc::clone(&ssr_cookies_header_getter); + let ssr_cookies_header_getter = Arc::clone(&ssr_cookies_header_getter); let cookie_name = cookie_name.to_owned(); move |_| { @@ -295,7 +295,7 @@ where match C::decode(&message) { Ok(value) => { let ssr_cookies_header_getter = - Rc::clone(&ssr_cookies_header_getter); + Arc::clone(&ssr_cookies_header_getter); jar.update_value(|jar| { update_client_cookie_jar( @@ -321,7 +321,7 @@ where } } else { let cookie_name = cookie_name.clone(); - let ssr_cookies_header_getter = Rc::clone(&ssr_cookies_header_getter); + let ssr_cookies_header_getter = Arc::clone(&ssr_cookies_header_getter); jar.update_value(|jar| { update_client_cookie_jar( @@ -359,25 +359,24 @@ where #[cfg(feature = "ssr")] { if !readonly { - let cookie_name = cookie_name.to_owned(); + Effect::new_isomorphic({ + let cookie_name = cookie_name.to_owned(); + let ssr_set_cookie = Arc::clone(&ssr_set_cookie); - create_isomorphic_effect(move |_| { - let value = cookie - .with(|cookie| { - cookie.as_ref().map(|cookie| { - C::encode(cookie) - .map_err(|err| on_error(CodecError::Encode(err))) - .ok() - }) - }) - .flatten(); - - jar.update_value({ + move |_| { let domain = domain.clone(); let path = path.clone(); - let ssr_set_cookie = Rc::clone(&ssr_set_cookie); - |jar| { + let value = cookie + .with(|cookie| { + cookie.as_ref().map(|cookie| { + C::encode(cookie) + .map_err(|err| on_error(CodecError::Encode(err))) + .ok() + }) + }) + .flatten(); + jar.update_value(|jar| { write_server_cookie( &cookie_name, value, @@ -389,10 +388,10 @@ where same_site, secure, http_only, - ssr_set_cookie, + Arc::clone(&ssr_set_cookie), ) - } - }); + }); + } }); } } @@ -472,14 +471,14 @@ pub struct UseCookieOptions { /// Getter function to return the string value of the cookie header. /// When you use one of the features `"axum"`, `"actix"` or `"spin"` there's a valid default implementation provided. - ssr_cookies_header_getter: Rc Option>, + ssr_cookies_header_getter: Arc Option + Send + Sync>, /// Function to add a set cookie header to the response on the server. /// When you use one of the features `"axum"`, `"actix"` or `"spin"` there's a valid default implementation provided. - ssr_set_cookie: Rc, + ssr_set_cookie: Arc, /// Callback for encoding/decoding errors. Defaults to logging the error to the console. - on_error: Rc)>, + on_error: Arc) + Send + Sync>, } impl Default for UseCookieOptions { @@ -495,7 +494,7 @@ impl Default for UseCookieOptions { domain: None, path: None, same_site: None, - ssr_cookies_header_getter: Rc::new(move || { + ssr_cookies_header_getter: Arc::new(move || { #[cfg(feature = "ssr")] { #[cfg(all(feature = "actix", feature = "axum"))] @@ -569,7 +568,7 @@ impl Default for UseCookieOptions { #[cfg(not(feature = "ssr"))] None }), - ssr_set_cookie: Rc::new(|cookie: &Cookie| { + ssr_set_cookie: Arc::new(|cookie: &Cookie| { #[cfg(feature = "ssr")] { #[cfg(feature = "actix")] @@ -620,7 +619,7 @@ impl Default for UseCookieOptions { let _ = cookie; }), - on_error: Rc::new(|_| { + on_error: Arc::new(|_| { error!("cookie (de-/)serialization error"); }), } @@ -628,7 +627,7 @@ impl Default for UseCookieOptions { } fn read_cookies_string( - ssr_cookies_header_getter: Rc Option>, + ssr_cookies_header_getter: Arc Option + Send + Sync>, ) -> Option { let cookies; @@ -651,71 +650,80 @@ fn read_cookies_string( cookies } -fn handle_expiration(delay: Option, set_cookie: WriteSignal>) { +fn handle_expiration(delay: Option, set_cookie: WriteSignal>) +where + T: Send + Sync + 'static, +{ if let Some(delay) = delay { #[cfg(not(feature = "ssr"))] { use leptos::leptos_dom::helpers::TimeoutHandle; - use std::cell::Cell; - use std::cell::RefCell; + use std::sync::{atomic::AtomicI32, Mutex}; // The maximum value allowed on a timeout delay. // Reference: https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#maximum_delay_value const MAX_TIMEOUT_DELAY: i64 = 2_147_483_647; - let timeout = Rc::new(Cell::new(None::)); - let elapsed = Rc::new(Cell::new(0)); + let timeout = Arc::new(Mutex::new(None::)); + let elapsed = Arc::new(AtomicI32::new(0)); on_cleanup({ - let timeout = Rc::clone(&timeout); + let timeout = Arc::clone(&timeout); move || { - if let Some(timeout) = timeout.take() { + if let Some(timeout) = timeout.lock().unwrap().take() { timeout.clear(); } } }); - let create_expiration_timeout = Rc::new(RefCell::new(None::>)); + let create_expiration_timeout = + Arc::new(Mutex::new(None::>)); - create_expiration_timeout.replace(Some(Box::new({ - let timeout = Rc::clone(&timeout); - let elapsed = Rc::clone(&elapsed); - let create_expiration_timeout = Rc::clone(&create_expiration_timeout); + *create_expiration_timeout.lock().unwrap() = Some(Box::new({ + let timeout = Arc::clone(&timeout); + let elapsed = Arc::clone(&elapsed); + let create_expiration_timeout = Arc::clone(&create_expiration_timeout); move || { - if let Some(timeout) = timeout.take() { + if let Some(timeout) = timeout.lock().unwrap().take() { timeout.clear(); } - let time_remaining = delay - elapsed.get(); + let time_remaining = + delay - elapsed.load(std::sync::atomic::Ordering::Relaxed) as i64; let timeout_length = time_remaining.min(MAX_TIMEOUT_DELAY); - let elapsed = Rc::clone(&elapsed); - let create_expiration_timeout = Rc::clone(&create_expiration_timeout); + let elapsed = Arc::clone(&elapsed); + let create_expiration_timeout = Arc::clone(&create_expiration_timeout); - timeout.set( - set_timeout_with_handle( - move || { - elapsed.set(elapsed.get() + timeout_length); - if elapsed.get() < delay { - if let Some(create_expiration_timeout) = - &*create_expiration_timeout.borrow() - { - create_expiration_timeout(); - } - return; + *timeout.lock().unwrap() = set_timeout_with_handle( + move || { + let elapsed = elapsed.fetch_add( + timeout_length as i32, + std::sync::atomic::Ordering::Relaxed, + ) as i64 + + timeout_length; + + if elapsed < delay { + if let Some(create_expiration_timeout) = + create_expiration_timeout.lock().unwrap().as_ref() + { + create_expiration_timeout(); } + return; + } - set_cookie.set(None); - }, - std::time::Duration::from_millis(timeout_length as u64), - ) - .ok(), - ); + set_cookie.set(None); + }, + std::time::Duration::from_millis(timeout_length as u64), + ) + .ok(); } - }))); + })); - if let Some(create_expiration_timeout) = &*create_expiration_timeout.borrow() { + if let Some(create_expiration_timeout) = + create_expiration_timeout.lock().unwrap().as_ref() + { create_expiration_timeout(); }; } @@ -740,7 +748,7 @@ fn write_client_cookie( same_site: Option, secure: bool, http_only: bool, - ssr_cookies_header_getter: Rc Option>, + ssr_cookies_header_getter: Arc Option + Send + Sync>, ) { use wasm_bindgen::JsCast; @@ -776,7 +784,7 @@ fn update_client_cookie_jar( same_site: Option, secure: bool, http_only: bool, - ssr_cookies_header_getter: Rc Option>, + ssr_cookies_header_getter: Arc Option + Send + Sync>, ) { if let Some(new_jar) = load_and_parse_cookie_jar(ssr_cookies_header_getter) { *jar = new_jar; @@ -864,7 +872,7 @@ fn write_server_cookie( same_site: Option, secure: bool, http_only: bool, - ssr_set_cookie: Rc, + ssr_set_cookie: Arc, ) { if let Some(value) = value { let cookie: Cookie = build_cookie_from_options( @@ -882,7 +890,7 @@ fn write_server_cookie( } fn load_and_parse_cookie_jar( - ssr_cookies_header_getter: Rc Option>, + ssr_cookies_header_getter: Arc Option + Send + Sync>, ) -> Option { read_cookies_string(ssr_cookies_header_getter).map(|cookies| { let mut jar = CookieJar::new(); diff --git a/src/use_cycle_list.rs b/src/use_cycle_list.rs index b7999c8..5c1d3ce 100644 --- a/src/use_cycle_list.rs +++ b/src/use_cycle_list.rs @@ -1,6 +1,5 @@ use crate::core::MaybeRwSignal; use default_struct_builder::DefaultBuilder; -use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; /// Cycle through a list of items. @@ -156,7 +155,7 @@ where let _ = { let set = set.clone(); - leptos::watch(move || list.get(), move |_, _, _| set(index.get()), false) + watch(move || list.get(), move |_, _, _| set(index.get()), false) }; UseCycleListReturn { @@ -174,7 +173,7 @@ where #[derive(DefaultBuilder)] pub struct UseCycleListOptions where - T: Clone + PartialEq + 'static, + T: Clone + PartialEq + Send + Sync + 'static, { /// The initial value of the state. Can be a Signal. If none is provided the first entry /// of the list will be used. @@ -192,7 +191,7 @@ where impl Default for UseCycleListOptions where - T: Clone + PartialEq + 'static, + T: Clone + PartialEq + Send + Sync + 'static, { fn default() -> Self { Self { @@ -206,7 +205,7 @@ where /// Return type of [`use_cycle_list`]. pub struct UseCycleListReturn where - T: Clone + PartialEq + 'static, + T: Clone + PartialEq + Send + Sync + 'static, SetFn: Fn(usize) -> T + Clone, NextFn: Fn() + Clone, PrevFn: Fn() + Clone, diff --git a/src/use_device_orientation.rs b/src/use_device_orientation.rs index d7b1265..051a10d 100644 --- a/src/use_device_orientation.rs +++ b/src/use_device_orientation.rs @@ -1,5 +1,6 @@ use cfg_if::cfg_if; use leptos::prelude::wrappers::read::Signal; +use send_wrapper::SendWrapper; /// Reactive [DeviceOrientationEvent](https://developer.mozilla.org/en-US/docs/Web/API/DeviceOrientationEvent). /// Provide web developers with information from the physical orientation of @@ -36,10 +37,10 @@ use leptos::prelude::wrappers::read::Signal; pub fn use_device_orientation() -> UseDeviceOrientationReturn { cfg_if! { if #[cfg(feature = "ssr")] { let is_supported = Signal::derive(|| false); - let absolute = || false; - let alpha = || None; - let beta = || None; - let gamma = || None; + let absolute = Signal::derive(|| false); + let alpha = Signal::derive(|| None); + let beta = Signal::derive(|| None); + let gamma = Signal::derive(|| None); } else { use leptos::prelude::*; use crate::{use_event_listener_with_options, UseEventListenerOptions, use_supported, js}; @@ -67,7 +68,10 @@ pub fn use_device_orientation() -> UseDeviceOrientationReturn { .once(false), ); - on_cleanup(cleanup); + on_cleanup({ + let cleanup = SendWrapper::new(cleanup); + move || cleanup() + }); } }} diff --git a/src/use_display_media.rs b/src/use_display_media.rs index a732f86..32db705 100644 --- a/src/use_display_media.rs +++ b/src/use_display_media.rs @@ -3,7 +3,6 @@ use cfg_if::cfg_if; use default_struct_builder::DefaultBuilder; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; -use send_wrapper::SendWrapper; use wasm_bindgen::{JsCast, JsValue}; /// Reactive [`mediaDevices.getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) streaming. @@ -56,8 +55,7 @@ pub fn use_display_media_with_options( let (enabled, set_enabled) = enabled.into_signal(); - let (stream, set_stream) = - signal(None::, SendWrapper>>); + let (stream, set_stream) = signal_local(None::>); let _start = move || async move { cfg_if! { if #[cfg(not(feature = "ssr"))] { @@ -65,10 +63,7 @@ pub fn use_display_media_with_options( return; } - let stream = create_media(audio) - .await - .map(SendWrapper::new) - .map_err(SendWrapper::new); + let stream = create_media(audio).await; set_stream.update(|s| *s = Some(stream)); } else { @@ -181,7 +176,7 @@ where /// Initially this is `None` until `start` resolved successfully. /// In case the stream couldn't be started, for example because the user didn't grant permission, /// this has the value `Some(Err(...))`. - pub stream: Signal, SendWrapper>>>, + pub stream: Signal>, LocalStorage>, /// Starts the screen streaming. Triggers the ask for permission if not already granted. pub start: StartFn, diff --git a/src/use_draggable.rs b/src/use_draggable.rs index 796ba51..e0d0d72 100644 --- a/src/use_draggable.rs +++ b/src/use_draggable.rs @@ -6,7 +6,7 @@ use leptos::prelude::diagnostics::SpecialNonReactiveZone; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; use std::marker::PhantomData; -use std::rc::Rc; +use std::sync::Arc; use wasm_bindgen::JsCast; use web_sys::PointerEvent; @@ -92,11 +92,11 @@ where let target = target.into(); let dragging_handle = if let Some(handle) = handle { - let handle = (handle).into(); - Signal::derive(move || handle.get().map(|handle| handle.into())) + let handle: ElementMaybeSignal<_, _> = handle.into(); + Signal::derive_local(move || handle.get().map(|handle| handle.into())) } else { let target = target.clone(); - Signal::derive(move || target.get().map(|target| target.into())) + Signal::derive_local(move || target.get().map(|target| target.into())) }; let (position, set_position) = initial_value.into_signal(); @@ -280,13 +280,13 @@ where initial_value: MaybeRwSignal, /// Callback when the dragging starts. Return `false` to prevent dragging. - on_start: Rc bool>, + on_start: Arc bool + Send + Sync>, /// Callback during dragging. - on_move: Rc, + on_move: Arc, /// Callback when dragging end. - on_end: Rc, + on_end: Arc, #[builder(skip)] _marker1: PhantomData, @@ -306,9 +306,9 @@ impl Default handle: None, pointer_types: vec![PointerType::Mouse, PointerType::Touch, PointerType::Pen], initial_value: MaybeRwSignal::default(), - on_start: Rc::new(|_| true), - on_move: Rc::new(|_| {}), - on_end: Rc::new(|_| {}), + on_start: Arc::new(|_| true), + on_move: Arc::new(|_| {}), + on_end: Arc::new(|_| {}), _marker1: PhantomData, _marker2: PhantomData, } diff --git a/src/use_drop_zone.rs b/src/use_drop_zone.rs index 6756866..d64a907 100644 --- a/src/use_drop_zone.rs +++ b/src/use_drop_zone.rs @@ -4,7 +4,7 @@ use default_struct_builder::DefaultBuilder; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; use std::fmt::{Debug, Formatter}; -use std::rc::Rc; +use std::sync::Arc; cfg_if! { if #[cfg(not(feature = "ssr"))] { use crate::use_event_listener; @@ -73,7 +73,7 @@ where T: Into + Clone + 'static, { let (is_over_drop_zone, set_over_drop_zone) = signal(false); - let (files, set_files) = signal(Vec::::new()); + let (files, set_files) = signal_local(Vec::::new()); #[cfg(not(feature = "ssr"))] { @@ -89,7 +89,7 @@ where let update_files = move |event: &web_sys::DragEvent| { if let Some(data_transfer) = event.data_transfer() { - let files: Vec = data_transfer + let files: Vec<_> = data_transfer .files() .map(|f| js_sys::Array::from(&f).to_vec()) .unwrap_or_default() @@ -112,7 +112,7 @@ where let _z = SpecialNonReactiveZone::enter(); on_enter(UseDropZoneEvent { - files: files.get_untracked(), + files: files.get_untracked().into_iter().collect(), event, }); }); @@ -125,7 +125,7 @@ where let _z = SpecialNonReactiveZone::enter(); on_over(UseDropZoneEvent { - files: files.get_untracked(), + files: files.get_untracked().into_iter().collect(), event, }); }); @@ -143,7 +143,7 @@ where let _z = SpecialNonReactiveZone::enter(); on_leave(UseDropZoneEvent { - files: files.get_untracked(), + files: files.get_untracked().into_iter().collect(), event, }); }); @@ -159,7 +159,7 @@ where let _z = SpecialNonReactiveZone::enter(); on_drop(UseDropZoneEvent { - files: files.get_untracked(), + files: files.get_untracked().into_iter().collect(), event, }); }); @@ -176,22 +176,22 @@ where #[cfg_attr(feature = "ssr", allow(dead_code))] pub struct UseDropZoneOptions { /// Event handler for the [`drop`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/drop_event) event - on_drop: Rc, + on_drop: Arc, /// Event handler for the [`dragenter`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragenter_event) event - on_enter: Rc, + on_enter: Arc, /// Event handler for the [`dragleave`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragleave_event) event - on_leave: Rc, + on_leave: Arc, /// Event handler for the [`dragover`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragover_event) event - on_over: Rc, + on_over: Arc, } impl Default for UseDropZoneOptions { fn default() -> Self { Self { - on_drop: Rc::new(|_| {}), - on_enter: Rc::new(|_| {}), - on_leave: Rc::new(|_| {}), - on_over: Rc::new(|_| {}), + on_drop: Arc::new(|_| {}), + on_enter: Arc::new(|_| {}), + on_leave: Arc::new(|_| {}), + on_over: Arc::new(|_| {}), } } } @@ -214,7 +214,7 @@ pub struct UseDropZoneEvent { /// Return type of [`use_drop_zone`]. pub struct UseDropZoneReturn { /// Files being handled - pub files: Signal>, + pub files: Signal, LocalStorage>, /// Whether the files (dragged by the pointer) are over the drop zone pub is_over_drop_zone: Signal, } diff --git a/src/use_event_listener.rs b/src/use_event_listener.rs index 7dbc150..463cc76 100644 --- a/src/use_event_listener.rs +++ b/src/use_event_listener.rs @@ -188,8 +188,10 @@ where cleanup_prev_element(); }; - let cleanup_stop = SendWrapper::new(stop.clone()); - on_cleanup(move || cleanup_stop()); + on_cleanup({ + let stop = SendWrapper::new(stop.clone()); + move || stop() + }); stop } diff --git a/src/use_event_source.rs b/src/use_event_source.rs index 1583c97..438602d 100644 --- a/src/use_event_source.rs +++ b/src/use_event_source.rs @@ -4,9 +4,8 @@ use codee::Decoder; use default_struct_builder::DefaultBuilder; use leptos::prelude::diagnostics::SpecialNonReactiveZone; use leptos::prelude::*; -use send_wrapper::SendWrapper; -use std::cell::Cell; use std::marker::PhantomData; +use std::sync::atomic::{AtomicBool, AtomicU32}; use std::sync::Arc; use std::time::Duration; use thiserror::Error; @@ -143,14 +142,14 @@ where let url = url.to_owned(); - let (event, set_event) = signal(None::>); + let (event, set_event) = signal_local(None::); let (data, set_data) = signal(None::); let (ready_state, set_ready_state) = signal(ConnectionReadyState::Closed); - let (event_source, set_event_source) = signal(None::>); - let (error, set_error) = signal(None::>); + let (event_source, set_event_source) = signal_local(None::); + let (error, set_error) = signal_local(None::>); - let explicitly_closed = Arc::new(Cell::new(false)); - let retried = Arc::new(Cell::new(0)); + let explicitly_closed = Arc::new(AtomicBool::new(false)); + let retried = Arc::new(AtomicU32::new(0)); let set_data_from_string = move |data_string: Option| { if let Some(data_string) = data_string { @@ -169,7 +168,7 @@ where event_source.close(); set_event_source.set(None); set_ready_state.set(ConnectionReadyState::Closed); - explicitly_closed.set(true); + explicitly_closed.store(true, std::sync::atomic::Ordering::Relaxed); } } }; @@ -183,7 +182,7 @@ where move || { use wasm_bindgen::prelude::*; - if explicitly_closed.get() { + if explicitly_closed.load(std::sync::atomic::Ordering::Relaxed) { return; } @@ -195,7 +194,7 @@ where set_ready_state.set(ConnectionReadyState::Connecting); - set_event_source.set(Some(SendWrapper::new(es.clone()))); + set_event_source.set(Some(es.clone())); let on_open = Closure::wrap(Box::new(move |_: web_sys::Event| { set_ready_state.set(ConnectionReadyState::Open); @@ -212,19 +211,20 @@ where move |e: web_sys::Event| { set_ready_state.set(ConnectionReadyState::Closed); - set_error.set(Some(UseEventSourceError::Event(SendWrapper::new(e)))); + set_error.set(Some(UseEventSourceError::Event(e))); // only reconnect if EventSource isn't reconnecting by itself // this is the case when the connection is closed (readyState is 2) if es.ready_state() == 2 - && !explicitly_closed.get() + && !explicitly_closed.load(std::sync::atomic::Ordering::Relaxed) && matches!(reconnect_limit, ReconnectLimit::Limited(_)) { es.close(); - retried.set(retried.get() + 1); + let retried_value = + retried.fetch_add(1, std::sync::atomic::Ordering::Relaxed) + 1; - if reconnect_limit.is_exceeded_by(retried.get()) { + if reconnect_limit.is_exceeded_by(retried_value as u64) { set_timeout( move || { if let Some(init) = init.get_value() { @@ -254,7 +254,7 @@ where for event_name in named_events.clone() { let _ = use_event_listener( es.clone(), - leptos::ev::Custom::::new(event_name), + leptos::ev::Custom::::new(event_name), move |e| { set_event.set(Some(e.clone())); let data_string = js!(e["data"]).ok().and_then(|d| d.as_string()); @@ -276,8 +276,8 @@ where move || { close(); - explicitly_closed.set(false); - retried.set(0); + explicitly_closed.store(false, std::sync::atomic::Ordering::Relaxed); + retried.store(0, std::sync::atomic::Ordering::Relaxed); if let Some(init) = init.get_value() { init(); } @@ -321,7 +321,7 @@ where reconnect_interval: u64, /// On maximum retry times reached. - on_failed: Arc, + on_failed: Arc, /// If `true` the `EventSource` connection will immediately be opened when calling this function. /// If `false` you have to manually call the `open` function. @@ -367,10 +367,10 @@ where pub ready_state: Signal, /// The latest named event - pub event: Signal>>, + pub event: Signal, LocalStorage>, /// The current error - pub error: Signal>>, + pub error: Signal>, LocalStorage>, /// (Re-)Opens the `EventSource` connection /// If the current one is active, will close it before opening a new one. @@ -380,13 +380,13 @@ where pub close: CloseFn, /// The `EventSource` instance - pub event_source: Signal>>, + pub event_source: Signal, LocalStorage>, } #[derive(Error, Debug)] pub enum UseEventSourceError { #[error("Error event: {0:?}")] - Event(SendWrapper), + Event(web_sys::Event), #[error("Error decoding value")] Deserialize(Err), diff --git a/src/use_geolocation.rs b/src/use_geolocation.rs index 5fbe920..8b6ff05 100644 --- a/src/use_geolocation.rs +++ b/src/use_geolocation.rs @@ -2,7 +2,6 @@ use cfg_if::cfg_if; use default_struct_builder::DefaultBuilder; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; -use send_wrapper::SendWrapper; /// Reactive [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API). /// It allows the user to provide their location to web applications if they so desire. For privacy reasons, @@ -44,8 +43,8 @@ pub fn use_geolocation_with_options( options: UseGeolocationOptions, ) -> UseGeolocationReturn { let (located_at, set_located_at) = signal(None::); - let (error, set_error) = signal(None::>); - let (coords, set_coords) = signal(None::>); + let (error, set_error) = signal_local(None::); + let (coords, set_coords) = signal_local(None::); cfg_if! { if #[cfg(feature = "ssr")] { let resume = || (); @@ -62,12 +61,12 @@ pub fn use_geolocation_with_options( let update_position = move |position: web_sys::Position| { set_located_at.set(Some(position.timestamp())); - set_coords.set(Some(SendWrapper::new(position.coords()))); + set_coords.set(Some(position.coords())); set_error.set(None); }; let on_error = move |err: web_sys::PositionError| { - set_error.set(Some(SendWrapper::new(err))); + set_error.set(Some(err)); }; let watch_handle = Arc::new(Mutex::new(None::)); @@ -203,13 +202,13 @@ where { /// The coordinates of the current device like latitude and longitude. /// See [`GeolocationCoordinates`](https://developer.mozilla.org/en-US/docs/Web/API/GeolocationCoordinates).. - pub coords: Signal>>, + pub coords: Signal, LocalStorage>, /// The timestamp of the current coordinates. pub located_at: Signal>, /// The last error received from `navigator.geolocation`. - pub error: Signal>>, + pub error: Signal, LocalStorage>, /// Resume the geolocation watch. pub resume: ResumeFn, diff --git a/src/use_infinite_scroll.rs b/src/use_infinite_scroll.rs index 3239ac0..e55642f 100644 --- a/src/use_infinite_scroll.rs +++ b/src/use_infinite_scroll.rs @@ -10,7 +10,7 @@ use leptos::prelude::diagnostics::SpecialNonReactiveZone; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; use std::future::Future; -use std::rc::Rc; +use std::sync::Arc; use std::time::Duration; use wasm_bindgen::JsCast; @@ -55,7 +55,7 @@ pub fn use_infinite_scroll(el: El, on_load_more: LFn) -> Signa where El: Into> + Clone + 'static, T: Into + Clone + 'static, - LFn: Fn(ScrollState) -> LFut + 'static, + LFn: Fn(ScrollState) -> LFut + Send + Sync + 'static, LFut: Future, { use_infinite_scroll_with_options(el, on_load_more, UseInfiniteScrollOptions::default()) @@ -70,7 +70,7 @@ pub fn use_infinite_scroll_with_options( where El: Into> + Clone + 'static, T: Into + Clone + 'static, - LFn: Fn(ScrollState) -> LFut + 'static, + LFn: Fn(ScrollState) -> LFut + Send + Sync + 'static, LFut: Future, { let UseInfiniteScrollOptions { @@ -110,7 +110,7 @@ where let (is_loading, set_loading) = signal(false); let el = el.into(); - let observed_element = Signal::derive(move || { + let observed_element = Signal::derive_local(move || { let el = el.get(); el.map(|el| { @@ -128,9 +128,9 @@ where let is_element_visible = use_element_visibility(observed_element); - let check_and_load = StoredValue::new(None::>); + let check_and_load = StoredValue::new(None::>); - check_and_load.set_value(Some(Rc::new({ + check_and_load.set_value(Some(Arc::new({ let measure = measure.clone(); move || { @@ -215,7 +215,7 @@ where #[derive(DefaultBuilder)] pub struct UseInfiniteScrollOptions { /// Callback when scrolling is happening. - on_scroll: Rc, + on_scroll: Arc, /// Options passed to the `addEventListener("scroll", ...)` call event_listener_options: UseEventListenerOptions, @@ -233,7 +233,7 @@ pub struct UseInfiniteScrollOptions { impl Default for UseInfiniteScrollOptions { fn default() -> Self { Self { - on_scroll: Rc::new(|_| {}), + on_scroll: Arc::new(|_| {}), event_listener_options: Default::default(), distance: 0.0, direction: Direction::Bottom, diff --git a/src/use_intersection_observer.rs b/src/use_intersection_observer.rs index 7aaaad5..ef76eee 100644 --- a/src/use_intersection_observer.rs +++ b/src/use_intersection_observer.rs @@ -3,12 +3,14 @@ use cfg_if::cfg_if; use default_struct_builder::DefaultBuilder; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; +use send_wrapper::SendWrapper; use std::marker::PhantomData; cfg_if! { if #[cfg(not(feature = "ssr"))] { use crate::{watch_with_options, WatchOptions}; - use std::cell::RefCell; - use std::rc::Rc; + // use std::cell::RefCell; + // use std::rc::Rc; + use std::sync::{Arc, Mutex}; use wasm_bindgen::prelude::*; }} @@ -116,14 +118,14 @@ where ) .into_js_value(); - let observer: Rc>> = - Rc::new(RefCell::new(None)); + let observer: Arc>>> = + Arc::new(Mutex::new(None)); let cleanup = { - let obsserver = Rc::clone(&observer); + let observer = Arc::clone(&observer); move || { - if let Some(o) = obsserver.take() { + if let Some(o) = observer.lock().unwrap().take() { o.disconnect(); } } @@ -177,7 +179,7 @@ where obs.observe(&target); } - observer.replace(Some(obs)); + *observer.lock().unwrap() = Some(SendWrapper::new(obs)); }, WatchOptions::default().immediate(immediate), ) diff --git a/src/use_interval_fn.rs b/src/use_interval_fn.rs index b34e752..e21fed4 100644 --- a/src/use_interval_fn.rs +++ b/src/use_interval_fn.rs @@ -5,6 +5,7 @@ use default_struct_builder::DefaultBuilder; use leptos::leptos_dom::helpers::IntervalHandle; use leptos::prelude::diagnostics::SpecialNonReactiveZone; use leptos::prelude::*; +use send_wrapper::SendWrapper; use std::cell::Cell; use std::rc::Rc; use std::time::Duration; @@ -140,7 +141,10 @@ where on_cleanup(stop_watch); } - on_cleanup(pause.clone()); + on_cleanup({ + let pause = SendWrapper::new(pause.clone()); + move || pause() + }); Pausable { is_active: is_active.into(), diff --git a/src/use_intl_number_format.rs b/src/use_intl_number_format.rs index 3bc0a43..f11af81 100644 --- a/src/use_intl_number_format.rs +++ b/src/use_intl_number_format.rs @@ -775,21 +775,21 @@ cfg_if! { if #[cfg(feature = "ssr")] { impl UseIntlNumberFormatReturn { /// Formats a number according to the [locale and formatting options](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#parameters) of this `Intl.NumberFormat` object. /// See [`use_intl_number_format`] for more information. - pub fn format(&self, number: impl Into>) -> Signal + pub fn format(&self, number: impl Into>) -> Signal where - N: Clone + Display + 'static, + N: Clone + Display + Send + Sync + 'static, js_sys::Number: From, { let number = number.into(); cfg_if! { if #[cfg(feature = "ssr")] { - Signal::derive(move || { + Signal::derive_local(move || { format!("{}", number.get()) }) } else { let number_format = self.js_intl_number_format.clone(); - Signal::derive(move || { + Signal::derive_local(move || { if let Ok(result) = number_format .format() .call1(&number_format, &js_sys::Number::from(number.get()).into()) @@ -852,10 +852,10 @@ impl UseIntlNumberFormatReturn { &self, start: impl Into>, end: impl Into>, - ) -> Signal + ) -> Signal where - NStart: Clone + Display + 'static, - NEnd: Clone + Display + 'static, + NStart: Clone + Display + Send + Sync + 'static, + NEnd: Clone + Display + Send + Sync + 'static, js_sys::Number: From, js_sys::Number: From, { @@ -863,13 +863,13 @@ impl UseIntlNumberFormatReturn { let end = end.into(); cfg_if! { if #[cfg(feature = "ssr")] { - Signal::derive(move || { + Signal::derive_local(move || { format!("{} - {}", start.get(), end.get()) }) } else { let number_format = self.js_intl_number_format.clone(); - Signal::derive(move || { + Signal::derive_local(move || { if let Ok(function) = js!(number_format["formatRange"]) { let function = function.unchecked_into::(); diff --git a/src/use_media_query.rs b/src/use_media_query.rs index 17e3c46..7ddf1f0 100644 --- a/src/use_media_query.rs +++ b/src/use_media_query.rs @@ -93,7 +93,10 @@ pub fn use_media_query(query: impl Into>) -> Signal { Effect::new(move |_| update()); - on_cleanup(cleanup); + on_cleanup({ + let cleanup = send_wrapper::SendWrapper::new(cleanup); + move || cleanup() + }); }} matches.into() diff --git a/src/use_mutation_observer.rs b/src/use_mutation_observer.rs index cd723b0..8f223c4 100644 --- a/src/use_mutation_observer.rs +++ b/src/use_mutation_observer.rs @@ -2,6 +2,7 @@ use crate::core::ElementsMaybeSignal; use cfg_if::cfg_if; use default_struct_builder::DefaultBuilder; use leptos::prelude::wrappers::read::Signal; +use send_wrapper::SendWrapper; use wasm_bindgen::prelude::*; cfg_if! { if #[cfg(not(feature = "ssr"))] { @@ -124,7 +125,7 @@ where let stop_watch = { let cleanup = cleanup.clone(); - leptos::watch( + leptos::prelude::watch( move || targets.get(), move |targets, _, _| { cleanup(); @@ -151,7 +152,10 @@ where stop_watch(); }; - on_cleanup(stop.clone()); + on_cleanup({ + let stop = SendWrapper::new(stop.clone()); + move || stop() + }); UseMutationObserverReturn { is_supported, stop } } diff --git a/src/use_raf_fn.rs b/src/use_raf_fn.rs index 0cbb66a..0568caf 100644 --- a/src/use_raf_fn.rs +++ b/src/use_raf_fn.rs @@ -138,8 +138,10 @@ pub fn use_raf_fn_with_options( resume(); } - let pause_cleanup = send_wrapper::SendWrapper::new(pause.clone()); - on_cleanup(move || pause_cleanup()); + on_cleanup({ + let pause = send_wrapper::SendWrapper::new(pause.clone()); + move || pause() + }); Pausable { resume, diff --git a/src/use_resize_observer.rs b/src/use_resize_observer.rs index 04017af..4bdb478 100644 --- a/src/use_resize_observer.rs +++ b/src/use_resize_observer.rs @@ -153,7 +153,10 @@ where stop_watch(); }; - on_cleanup(stop.clone()); + on_cleanup({ + let stop = send_wrapper::SendWrapper::new(stop.clone()); + move || stop() + }); UseResizeObserverReturn { is_supported, stop } } diff --git a/src/use_scroll.rs b/src/use_scroll.rs index d2ac791..a1f28c6 100644 --- a/src/use_scroll.rs +++ b/src/use_scroll.rs @@ -370,7 +370,7 @@ where let target = { let signal = signal.clone(); - Signal::derive(move || { + Signal::derive_local(move || { let element = signal.get(); element.map(|element| element.into().unchecked_into::()) }) @@ -392,14 +392,14 @@ where let _ = use_event_listener_with_options::< _, - Signal>, + Signal, LocalStorage>, web_sys::EventTarget, _, >(target, ev::scroll, handler, options.event_listener_options); } else { let _ = use_event_listener_with_options::< _, - Signal>, + Signal, LocalStorage>, web_sys::EventTarget, _, >( @@ -412,7 +412,7 @@ where let _ = use_event_listener_with_options::< _, - Signal>, + Signal, LocalStorage>, web_sys::EventTarget, _, >( diff --git a/src/use_service_worker.rs b/src/use_service_worker.rs index 508b3d6..4fed646 100644 --- a/src/use_service_worker.rs +++ b/src/use_service_worker.rs @@ -146,7 +146,7 @@ pub fn use_service_worker_with_options( check_for_update: move || { registration.with(|reg| { if let Ok(reg) = reg { - update_sw.dispatch(reg.clone()) + update_sw.dispatch(reg.clone()); } }) }, @@ -246,7 +246,7 @@ fn create_action_update() -> Action< SendWrapper, Result, SendWrapper>, > { - Action::new( + Action::new_unsync( move |registration: &SendWrapper| { let registration = registration.clone(); async move { @@ -256,7 +256,7 @@ fn create_action_update() -> Action< .and_then(|ok| ok.dyn_into::()) .map(SendWrapper::new) .map_err(SendWrapper::new), - Err(err) => Err(err), + Err(err) => Err(SendWrapper::new(err)), } } }, @@ -268,15 +268,17 @@ fn create_action_create_or_update_registration() -> Action< ServiceWorkerScriptUrl, Result, SendWrapper>, > { - Action::new(move |script_url: &ServiceWorkerScriptUrl| { + Action::new_unsync(move |script_url: &ServiceWorkerScriptUrl| { let script_url = script_url.0.to_owned(); async move { if let Some(navigator) = use_window().navigator() { js_fut!(navigator.service_worker().register(script_url.as_str())) .await .and_then(|ok| ok.dyn_into::()) + .map(SendWrapper::new) + .map_err(SendWrapper::new) } else { - Err(JsValue::from_str("no navigator")) + Err(SendWrapper::new(JsValue::from_str("no navigator"))) } } }) @@ -285,7 +287,7 @@ fn create_action_create_or_update_registration() -> Action< /// A leptos action which asynchronously fetches the current ServiceWorkerRegistration. fn create_action_get_registration( ) -> Action<(), Result, SendWrapper>> { - Action::new(move |(): &()| async move { + Action::new_unsync(move |(): &()| async move { if let Some(navigator) = use_window().navigator() { js_fut!(navigator.service_worker().get_registration()) .await diff --git a/src/use_sorted.rs b/src/use_sorted.rs index 02436ef..eea7202 100644 --- a/src/use_sorted.rs +++ b/src/use_sorted.rs @@ -78,7 +78,7 @@ pub fn use_sorted(iterable: S) -> Signal where S: Into>, T: Ord, - I: DerefMut + Clone + PartialEq, + I: DerefMut + Clone + PartialEq + Send + Sync + 'static, { let iterable = iterable.into(); @@ -93,8 +93,8 @@ where pub fn use_sorted_by(iterable: S, cmp_fn: F) -> Signal where S: Into>, - I: DerefMut + Clone + PartialEq, - F: FnMut(&T, &T) -> Ordering + Clone + 'static, + I: DerefMut + Clone + PartialEq + Send + Sync + 'static, + F: FnMut(&T, &T) -> Ordering + Clone + Send + Sync + 'static, { let iterable = iterable.into(); @@ -109,9 +109,9 @@ where pub fn use_sorted_by_key(iterable: S, key_fn: F) -> Signal where S: Into>, - I: DerefMut + Clone + PartialEq, + I: DerefMut + Clone + PartialEq + Send + Sync + 'static, K: Ord, - F: FnMut(&T) -> K + Clone + 'static, + F: FnMut(&T) -> K + Clone + Send + Sync + 'static, { let iterable = iterable.into(); diff --git a/src/use_supported.rs b/src/use_supported.rs index b121e49..4da5ca3 100644 --- a/src/use_supported.rs +++ b/src/use_supported.rs @@ -20,7 +20,7 @@ use leptos::prelude::*; /// # view! { } /// # } /// ``` -pub fn use_supported(callback: impl Fn() -> bool + 'static) -> Signal { +pub fn use_supported(callback: impl Fn() -> bool + Send + Sync + 'static) -> Signal { #[cfg(feature = "ssr")] { let _ = callback; diff --git a/src/use_user_media.rs b/src/use_user_media.rs index 10d1c14..83ec073 100644 --- a/src/use_user_media.rs +++ b/src/use_user_media.rs @@ -59,7 +59,7 @@ pub fn use_user_media_with_options( let (enabled, set_enabled) = enabled.into_signal(); - let (stream, set_stream) = signal(None::>); + let (stream, set_stream) = signal_local(None::>); let _start = move || async move { cfg_if! { if #[cfg(not(feature = "ssr"))] { @@ -187,7 +187,7 @@ where /// Initially this is `None` until `start` resolved successfully. /// In case the stream couldn't be started, for example because the user didn't grant permission, /// this has the value `Some(Err(...))`. - pub stream: Signal>>, + pub stream: Signal>, LocalStorage>, /// Starts the screen streaming. Triggers the ask for permission if not already granted. pub start: StartFn, diff --git a/src/use_web_notification.rs b/src/use_web_notification.rs index 5d183c3..104c2fd 100644 --- a/src/use_web_notification.rs +++ b/src/use_web_notification.rs @@ -2,7 +2,6 @@ use crate::{use_supported, use_window}; use cfg_if::cfg_if; use default_struct_builder::DefaultBuilder; use leptos::prelude::{wrappers::read::Signal, *}; -use send_wrapper::SendWrapper; use std::rc::Rc; /// Reactive [Notification API](https://developer.mozilla.org/en-US/docs/Web/API/Notification). @@ -52,7 +51,7 @@ pub fn use_web_notification_with_options( ) -> UseWebNotificationReturn { let is_supported = use_supported(browser_supports_notifications); - let (notification, set_notification) = signal(None::>); + let (notification, set_notification) = signal_local(None::); let (permission, set_permission) = signal(NotificationPermission::default()); @@ -462,7 +461,7 @@ where CloseFn: Fn() + Clone, { pub is_supported: Signal, - pub notification: Signal>>, + pub notification: Signal, LocalStorage>, pub show: ShowFn, pub close: CloseFn, pub permission: Signal, diff --git a/src/use_websocket.rs b/src/use_websocket.rs index 37a6a26..e658a81 100644 --- a/src/use_websocket.rs +++ b/src/use_websocket.rs @@ -2,7 +2,6 @@ use cfg_if::cfg_if; use leptos::{leptos_dom::helpers::TimeoutHandle, prelude::*}; -use send_wrapper::SendWrapper; use std::sync::{atomic::AtomicBool, Arc}; use std::time::Duration; use thiserror::Error; @@ -238,7 +237,7 @@ pub fn use_websocket( impl Fn(&T) + Clone + 'static, > where - T: 'static, + T: Send + Sync + 'static, C: Encoder + Decoder, C: IsBinary>::Encoded>, C: HybridDecoder>::Encoded, Error = >::Error>, @@ -263,7 +262,7 @@ pub fn use_websocket_with_options( impl Fn(&T) + Clone + 'static, > where - T: 'static, + T: Send + Sync + 'static, C: Encoder + Decoder, C: IsBinary>::Encoded>, C: HybridDecoder>::Encoded, Error = >::Error>, @@ -286,7 +285,7 @@ where let (ready_state, set_ready_state) = signal(ConnectionReadyState::Closed); let (message, set_message) = signal(None); - let ws_ref: StoredValue>> = StoredValue::new(None); + let ws_ref: StoredValue, _> = StoredValue::new_local(None); let reconnect_timer_ref: StoredValue> = StoredValue::new(None); @@ -305,9 +304,9 @@ where Some(Arc::new(move || { if !manually_closed_ref.get_value() && !reconnect_limit.is_exceeded_by(reconnect_times_ref.get_value()) - && ws_ref.get_value().map_or(false, |ws: SendWrapper| { - ws.ready_state() != WebSocket::OPEN - }) + && ws_ref + .get_value() + .map_or(false, |ws: WebSocket| ws.ready_state() != WebSocket::OPEN) { reconnect_timer_ref.set_value( set_timeout_with_handle( @@ -358,7 +357,7 @@ where let on_open = Arc::clone(&on_open); let onopen_closure = Closure::wrap(Box::new(move |e: Event| { - if unmounted.get() { + if unmounted.load(std::sync::atomic::Ordering::Relaxed) { return; } @@ -387,7 +386,7 @@ where let on_error = Arc::clone(&on_error); let onmessage_closure = Closure::wrap(Box::new(move |e: MessageEvent| { - if unmounted.get() { + if unmounted.load(std::sync::atomic::Ordering::Relaxed) { return; } @@ -409,17 +408,18 @@ where on_message_raw(&txt); #[cfg(debug_assertions)] - SpecialNonReactiveZone::exit(prev); + drop(zone); match C::decode_str(&txt) { Ok(val) => { #[cfg(debug_assertions)] - let prev = SpecialNonReactiveZone::enter(); + let prev = + diagnostics::SpecialNonReactiveZone::enter(); on_message(&val); #[cfg(debug_assertions)] - drop(zone); + drop(prev); set_message.set(Some(val)); } @@ -445,12 +445,12 @@ where match C::decode_bin(array.as_slice()) { Ok(val) => { #[cfg(debug_assertions)] - let prev = SpecialNonReactiveZone::enter(); + let prev = diagnostics::SpecialNonReactiveZone::enter(); on_message(&val); #[cfg(debug_assertions)] - SpecialNonReactiveZone::exit(prev); + drop(prev); set_message.set(Some(val)); } @@ -472,7 +472,7 @@ where let on_error = Arc::clone(&on_error); let onerror_closure = Closure::wrap(Box::new(move |e: Event| { - if unmounted.get() { + if unmounted.load(std::sync::atomic::Ordering::Relaxed) { return; } @@ -501,7 +501,7 @@ where let on_close = Arc::clone(&on_close); let onclose_closure = Closure::wrap(Box::new(move |e: CloseEvent| { - if unmounted.get() { + if unmounted.load(std::sync::atomic::Ordering::Relaxed) { return; } @@ -630,7 +630,7 @@ impl ReconnectLimit { } } -type ArcFnBytes = Arc; +type ArcFnBytes = Arc; /// Options for [`use_websocket_with_options`]. #[derive(DefaultBuilder)] @@ -642,11 +642,11 @@ where on_open: Arc, /// `WebSocket` message callback for typed message decoded by codec. #[builder(skip)] - on_message: Arc, + on_message: Arc, /// `WebSocket` message callback for text. on_message_raw: Arc, /// `WebSocket` message callback for binary. - on_message_raw_bytes: ArcFnBytes + Send + Sync, + on_message_raw_bytes: ArcFnBytes, /// `WebSocket` error callback. #[builder(skip)] on_error: Arc) + Send + Sync>, @@ -669,7 +669,7 @@ impl UseWebSocketOptions { /// `WebSocket` error callback. pub fn on_error(self, handler: F) -> Self where - F: Fn(UseWebSocketError) + 'static, + F: Fn(UseWebSocketError) + Send + Sync + 'static, { Self { on_error: Arc::new(handler), @@ -680,7 +680,7 @@ impl UseWebSocketOptions { /// `WebSocket` message callback for typed message decoded by codec. pub fn on_message(self, handler: F) -> Self where - F: Fn(&T) + 'static, + F: Fn(&T) + Send + Sync + 'static, { Self { on_message: Arc::new(handler), @@ -710,7 +710,7 @@ impl Default for UseWebSocketOptions { #[derive(Clone)] pub struct UseWebSocketReturn where - T: 'static, + T: Send + Sync + 'static, OpenFn: Fn() + Clone + 'static, CloseFn: Fn() + Clone + 'static, SendFn: Fn(&T) + Clone + 'static, @@ -720,7 +720,7 @@ where /// Latest message received from `WebSocket`. pub message: Signal>, /// The `WebSocket` instance. - pub ws: Option>, + pub ws: Option, /// Opens the `WebSocket` connection pub open: OpenFn, /// Closes the `WebSocket` connection diff --git a/src/utils/signal_filtered.rs b/src/utils/signal_filtered.rs index f397e5e..2763e9e 100644 --- a/src/utils/signal_filtered.rs +++ b/src/utils/signal_filtered.rs @@ -15,7 +15,7 @@ macro_rules! signal_filtered { ) -> Signal where S: Into>, - T: Clone + 'static, + T: Clone + Send + Sync + 'static, { [](value, ms, [<$filter_name:camel Options>]::default()) } @@ -36,7 +36,7 @@ macro_rules! signal_filtered { ) -> Signal where S: Into>, - T: Clone + 'static, + T: Clone + Send + Sync + 'static, { let value = value.into(); let ms = ms.into(); diff --git a/src/utils/use_derive_signal.rs b/src/utils/use_derive_signal.rs index 639d100..31fcf59 100644 --- a/src/utils/use_derive_signal.rs +++ b/src/utils/use_derive_signal.rs @@ -11,6 +11,7 @@ macro_rules! use_derive_signal { $(#[$outer])* pub fn $name(value: V) -> Signal<$return_type> where + $inner_signal_type $(< $( $inner_type_param ),+ >)?: Send + Sync, V: Into)?>> $(, $( $type_param $( : $first_bound $(+ $rest_bound)* )? ),+ )? { let value = value.into(); diff --git a/src/watch_with_options.rs b/src/watch_with_options.rs index 690271b..6c9c888 100644 --- a/src/watch_with_options.rs +++ b/src/watch_with_options.rs @@ -129,7 +129,7 @@ where let filtered_callback = create_filter_wrapper(options.filter.filter_fn(), wrapped_callback.clone()); - leptos::watch( + leptos::prelude::watch( deps, move |deps_value, previous_deps_value, did_run_before| { cur_deps_value.replace(Some(deps_value.clone())); @@ -138,7 +138,7 @@ where let callback_value = if options.immediate && did_run_before.is_none() { Some(wrapped_callback()) } else { - filtered_callback().take() + filtered_callback().lock().unwrap().take() }; prev_callback_value.replace(callback_value); @@ -196,5 +196,5 @@ where W: Clone + 'static, T: Clone + 'static, { - leptos::watch(deps, callback, false) + leptos::prelude::watch(deps, callback, false) }