From 3433fc660812ceb40e79e82e3e94c0d85c08561a Mon Sep 17 00:00:00 2001 From: CorvusPrudens Date: Tue, 23 Jul 2024 10:50:20 -0600 Subject: [PATCH 1/6] Reintroduced proper watch --- src/core/element_maybe_signal.rs | 255 ++++++++++++++++-------------- src/core/elements_maybe_signal.rs | 148 ++++++++--------- src/use_cycle_list.rs | 3 +- src/use_interval_fn.rs | 4 +- src/watch_with_options.rs | 6 +- 5 files changed, 224 insertions(+), 192 deletions(-) diff --git a/src/core/element_maybe_signal.rs b/src/core/element_maybe_signal.rs index 27e4e6b..780ed55 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 /// * a `web_sys` element that implements `E` (for example `EventTarget`, `Element` or `HtmlElement`), @@ -17,9 +18,9 @@ pub enum ElementMaybeSignal where T: Into + Clone + 'static, { - Static(Option), - Dynamic(Signal>), - _Phantom(PhantomData), + Static(Option>), + Dynamic(Signal>>), + _Phantom(PhantomData E>), } impl Default for ElementMaybeSignal @@ -61,16 +62,28 @@ 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) => { + let value = t.as_ref().map(|t| t.clone().take()); + f(&value) + } + Self::Dynamic(s) => s.with(|s| { + let value = s.as_ref().map(|s| s.clone().take()); + f(&value) + }), _ => unreachable!(), } } fn try_with(&self, f: impl FnOnce(&Option) -> O) -> Option { match self { - Self::Static(t) => Some(f(t)), - Self::Dynamic(s) => s.try_with(f), + Self::Static(t) => { + let value = t.as_ref().map(|t| t.clone().take()); + Some(f(&value)) + } + Self::Dynamic(s) => s.try_with(|s| { + let value = s.as_ref().map(|s| s.clone().take()); + f(&value) + }), _ => unreachable!(), } } @@ -84,16 +97,28 @@ where fn with_untracked(&self, f: impl FnOnce(&Option) -> O) -> O { match self { - Self::Static(t) => f(t), - Self::Dynamic(s) => s.with_untracked(f), + Self::Static(t) => { + let value = t.as_ref().map(|t| t.clone().take()); + f(&value) + } + Self::Dynamic(s) => s.with_untracked(|s| { + let value = s.as_ref().map(|s| s.clone().take()); + f(&value) + }), _ => unreachable!(), } } fn try_with_untracked(&self, f: impl FnOnce(&Option) -> O) -> Option { match self { - Self::Static(t) => Some(f(t)), - Self::Dynamic(s) => s.try_with_untracked(f), + Self::Static(t) => { + let value = t.as_ref().map(|t| t.clone().take()); + Some(f(&value)) + } + Self::Dynamic(s) => s.try_with_untracked(|s| { + let value = s.as_ref().map(|s| s.clone().take()); + f(&value) + }), _ => unreachable!(), } } @@ -106,7 +131,7 @@ where T: Into + Clone + 'static, { fn from(value: T) -> Self { - ElementMaybeSignal::Static(Some(value)) + ElementMaybeSignal::Static(Some(SendWrapper::new(value))) } } @@ -115,7 +140,7 @@ where T: Into + Clone + 'static, { fn from(target: Option) -> Self { - ElementMaybeSignal::Static(target) + ElementMaybeSignal::Static(target.map(SendWrapper::new)) } } @@ -126,7 +151,7 @@ macro_rules! impl_from_deref_option { E: From<$ty2> + 'static, { fn from(value: $ty) -> Self { - Self::Static((*value).clone()) + Self::Static((*value).clone().map(SendWrapper::new)) } } }; @@ -205,10 +230,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>>); +impl_from_signal_option!(ReadSignal>>); +impl_from_signal_option!(RwSignal>>); +impl_from_signal_option!(Memo>>); macro_rules! impl_from_signal { ($ty:ty) => { @@ -223,10 +248,10 @@ macro_rules! impl_from_signal { }; } -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 ////////////////////////////////////////////////////////////// @@ -234,14 +259,14 @@ 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 || { node_ref.get().map(move |el| { - let el = el.into_any(); - let el: $ty = el.deref().clone().into(); - el + let el: $ty = el.clone().into(); + SendWrapper::new(el) }) })) } @@ -253,90 +278,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 d316944..9902280 100644 --- a/src/core/elements_maybe_signal.rs +++ b/src/core/elements_maybe_signal.rs @@ -1,7 +1,7 @@ use crate::core::ElementMaybeSignal; use crate::{UseDocument, UseWindow}; use cfg_if::cfg_if; -use leptos::html::ElementDescriptor; +use leptos::html::{ElementType, HtmlElement}; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; use std::marker::PhantomData; @@ -18,9 +18,9 @@ pub enum ElementsMaybeSignal where T: Into + Clone + 'static, { - Static(Vec>), - Dynamic(Signal>>), - _Phantom(PhantomData), + Static(Vec>>), + Dynamic(Signal>>>), + _Phantom(PhantomData E>), } impl Default for ElementsMaybeSignal @@ -256,7 +256,7 @@ macro_rules! impl_from_node_ref { ($ty:ty) => { impl From> for ElementsMaybeSignal<$ty, $ty> where - R: ElementDescriptor + Clone + 'static, + R: ElementType + Clone + 'static, { fn from(node_ref: NodeRef) -> Self { Self::Dynamic(Signal::derive(move || { @@ -278,11 +278,12 @@ impl_from_node_ref!(web_sys::Element); macro_rules! impl_from_html_element { ($ty:ty) => { - impl From> for ElementsMaybeSignal<$ty, $ty> + impl From> for ElementsMaybeSignal<$ty, $ty> where - HtmlEl: ElementDescriptor + std::ops::Deref, + E: ElementType, + E::Output: std::ops::Deref, { - fn from(value: HtmlElement) -> Self { + fn from(value: HtmlElement) -> Self { let el: &$ty = value.deref(); Self::Static(vec![Some(el.clone())]) } @@ -539,7 +540,7 @@ 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, { fn from(node_refs: &[NodeRef]) -> Self { let node_refs = node_refs.to_vec(); @@ -549,7 +550,7 @@ macro_rules! impl_from_multi_node_ref { impl From<[NodeRef; C]> for ElementsMaybeSignal<$ty, $ty> where - R: ElementDescriptor + Clone + 'static, + R: ElementType + Clone + 'static, { fn from(node_refs: [NodeRef; C]) -> Self { let node_refs = node_refs.to_vec(); @@ -559,7 +560,7 @@ macro_rules! impl_from_multi_node_ref { impl From>> for ElementsMaybeSignal<$ty, $ty> where - R: ElementDescriptor + Clone + 'static, + R: ElementType + Clone + 'static, { fn from(node_refs: Vec>) -> Self { let node_refs = node_refs.clone(); @@ -572,66 +573,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 ////////////////////////////////////////////////////////////// diff --git a/src/use_cycle_list.rs b/src/use_cycle_list.rs index b7999c8..2a38b3b 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 { diff --git a/src/use_interval_fn.rs b/src/use_interval_fn.rs index b34e752..4fab709 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,8 @@ where on_cleanup(stop_watch); } - on_cleanup(pause.clone()); + let pause_cleanup = SendWrapper::new(pause.clone()); + on_cleanup(move || pause_cleanup()); Pausable { is_active: is_active.into(), diff --git a/src/watch_with_options.rs b/src/watch_with_options.rs index 86e30ca..e33678a 100644 --- a/src/watch_with_options.rs +++ b/src/watch_with_options.rs @@ -130,7 +130,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())); @@ -139,7 +139,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); @@ -197,5 +197,5 @@ where W: Clone + 'static, T: Clone + 'static, { - leptos::watch(deps, callback, false) + leptos::prelude::watch(deps, callback, false) } From 9866ac62317b9bd56e46e001dacedb24ae5845a2 Mon Sep 17 00:00:00 2001 From: CorvusPrudens Date: Tue, 23 Jul 2024 11:36:12 -0600 Subject: [PATCH 2/6] Added more `Send + Sync` bounds and `SendWrapper`s --- src/core/elements_maybe_signal.rs | 171 ++++++++++++++++++------------ src/core/maybe_rw_signal.rs | 25 ++++- src/core/use_rw_signal.rs | 12 ++- src/lib.rs | 8 +- src/math/shared.rs | 8 +- src/sync_signal.rs | 6 +- src/use_breakpoints.rs | 6 +- src/use_broadcast_channel.rs | 22 ++-- src/use_device_orientation.rs | 8 +- src/use_draggable.rs | 22 ++-- src/use_drop_zone.rs | 23 ++-- src/use_event_source.rs | 4 +- src/use_websocket.rs | 14 +-- src/utils/signal_filtered.rs | 4 +- 14 files changed, 202 insertions(+), 131 deletions(-) diff --git a/src/core/elements_maybe_signal.rs b/src/core/elements_maybe_signal.rs index 9902280..069cd7b 100644 --- a/src/core/elements_maybe_signal.rs +++ b/src/core/elements_maybe_signal.rs @@ -4,8 +4,10 @@ use cfg_if::cfg_if; use leptos::html::{ElementType, HtmlElement}; 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 /// * a `web_sys` element that implements `E` (for example `EventTarget` or `Element`), @@ -58,9 +60,9 @@ impl With for ElementsMaybeSignal where T: Into + Clone + 'static, { - type Value = Vec>; + type Value = Vec>>; - fn with(&self, f: impl FnOnce(&Vec>) -> O) -> O { + fn with(&self, f: impl FnOnce(&Vec>>) -> O) -> O { match self { Self::Static(v) => f(v), Self::Dynamic(s) => s.with(f), @@ -68,7 +70,7 @@ where } } - fn try_with(&self, f: impl FnOnce(&Vec>) -> O) -> Option { + fn try_with(&self, f: impl FnOnce(&Vec>>) -> O) -> Option { match self { Self::Static(v) => Some(f(v)), Self::Dynamic(s) => s.try_with(f), @@ -81,9 +83,9 @@ impl WithUntracked for ElementsMaybeSignal where T: Into + Clone + 'static, { - type Value = Vec>; + type Value = Vec>>; - fn with_untracked(&self, f: impl FnOnce(&Vec>) -> O) -> O { + fn with_untracked(&self, f: impl FnOnce(&Vec>>) -> O) -> O { match self { Self::Static(t) => f(t), Self::Dynamic(s) => s.with_untracked(f), @@ -91,7 +93,10 @@ where } } - fn try_with_untracked(&self, f: impl FnOnce(&Vec>) -> O) -> Option { + fn try_with_untracked( + &self, + f: impl FnOnce(&Vec>>) -> O, + ) -> Option { match self { Self::Static(t) => Some(f(t)), Self::Dynamic(s) => s.try_with_untracked(f), @@ -107,7 +112,7 @@ where T: Into + Clone + 'static, { fn from(value: T) -> Self { - ElementsMaybeSignal::Static(vec![Some(value)]) + ElementsMaybeSignal::Static(vec![Some(SendWrapper::new(value))]) } } @@ -116,7 +121,7 @@ where T: Into + Clone + 'static, { fn from(target: Option) -> Self { - ElementsMaybeSignal::Static(vec![target]) + ElementsMaybeSignal::Static(vec![target.map(SendWrapper::new)]) } } @@ -127,7 +132,7 @@ macro_rules! impl_from_deref_option { E: From<$ty2> + 'static, { fn from(value: $ty) -> Self { - Self::Static(vec![(*value).clone()]) + Self::Static(vec![(*value).clone().map(SendWrapper::new)]) } } }; @@ -185,7 +190,7 @@ macro_rules! impl_from_signal_string { let mut list = Vec::with_capacity(node_list.length() as usize); for i in 0..node_list.length() { let node = node_list.get(i).expect("checked the range"); - list.push(Some(node)); + list.push(Some(SendWrapper::new(node))); } list } else { @@ -209,8 +214,8 @@ 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!(RwSignal<&'static str>); +impl_from_signal_string!(Memo<&'static str>); // From single signal /////////////////////////////////////////////////////////////// @@ -227,10 +232,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>>); +impl_from_signal_option!(ReadSignal>>); +impl_from_signal_option!(RwSignal>>); +impl_from_signal_option!(Memo>>); macro_rules! impl_from_signal { ($ty:ty) => { @@ -245,10 +250,10 @@ macro_rules! impl_from_signal { }; } -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 ////////////////////////////////////////////////////////////// @@ -257,13 +262,13 @@ macro_rules! impl_from_node_ref { impl From> for ElementsMaybeSignal<$ty, $ty> where R: ElementType + Clone + 'static, + R::Output: JsCast + Into<$ty> + Clone + 'static, { fn from(node_ref: NodeRef) -> Self { Self::Dynamic(Signal::derive(move || { vec![node_ref.get().map(move |el| { - let el = el.into_any(); - let el: $ty = el.deref().clone().into(); - el + let el: $ty = el.clone().into(); + SendWrapper::new(el) })] })) } @@ -276,23 +281,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 - 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); +// 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 ////////////////////////////////////////////////////// @@ -301,7 +306,12 @@ where T: Into + Clone + 'static, { fn from(target: &[T]) -> Self { - Self::Static(target.iter().map(|t| Some(t.clone())).collect()) + Self::Static( + target + .iter() + .map(|t| Some(SendWrapper::new(t.clone()))) + .collect(), + ) } } @@ -310,7 +320,12 @@ where T: Into + Clone + 'static, { fn from(target: &[Option]) -> Self { - Self::Static(target.to_vec()) + Self::Static( + target + .iter() + .map(|t| t.clone().map(SendWrapper::new)) + .collect(), + ) } } @@ -319,7 +334,12 @@ where T: Into + Clone + 'static, { fn from(target: Vec) -> Self { - Self::Static(target.iter().map(|t| Some(t.clone())).collect()) + Self::Static( + target + .iter() + .map(|t| Some(SendWrapper::new(t.clone()))) + .collect(), + ) } } @@ -328,7 +348,12 @@ where T: Into + Clone + 'static, { fn from(target: Vec>) -> Self { - Self::Static(target.to_vec()) + Self::Static( + target + .into_iter() + .map(|t| t.map(SendWrapper::new)) + .collect(), + ) } } @@ -337,7 +362,12 @@ where T: Into + Clone + 'static, { fn from(target: [T; C]) -> Self { - Self::Static(target.iter().map(|t| Some(t.clone())).collect()) + Self::Static( + target + .into_iter() + .map(|t| Some(SendWrapper::new(t))) + .collect(), + ) } } @@ -346,7 +376,12 @@ where T: Into + Clone + 'static, { fn from(target: [Option; C]) -> Self { - Self::Static(target.to_vec()) + Self::Static( + target + .into_iter() + .map(|t| t.map(SendWrapper::new)) + .collect(), + ) } } @@ -357,7 +392,7 @@ macro_rules! impl_from_strings_inner { Self::Static( $target .iter() - .filter_map(|sel: &$str_ty| -> Option>> { + .filter_map(|sel: &$str_ty| -> Option>>> { cfg_if! { if #[cfg(feature = "ssr")] { let _ = sel; None @@ -368,7 +403,7 @@ macro_rules! impl_from_strings_inner { 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)); + list.push(Some(SendWrapper::new(node))); } Some(list) @@ -417,33 +452,33 @@ impl_from_strings!(web_sys::EventTarget, String); // From signal of vec //////////////////////////////////////////////////////////////// -impl From>> for ElementsMaybeSignal +impl From>>> for ElementsMaybeSignal where T: Into + Clone + 'static, { - fn from(signal: Signal>) -> Self { + fn from(signal: Signal>>) -> Self { Self::Dynamic(Signal::derive(move || { signal.get().into_iter().map(|t| Some(t)).collect() })) } } -impl From>>> for ElementsMaybeSignal +impl From>>>> for ElementsMaybeSignal where T: Into + Clone + 'static, { - fn from(target: Signal>>) -> Self { + fn from(target: Signal>>>) -> 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 || { @@ -452,11 +487,11 @@ where } } -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 || { @@ -465,11 +500,11 @@ where } } -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 || { @@ -478,11 +513,11 @@ where } } -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 || { @@ -491,11 +526,11 @@ where } } -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 || { @@ -504,11 +539,11 @@ where } } -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 || { @@ -526,9 +561,8 @@ macro_rules! impl_from_multi_node_ref_inner { .iter() .map(|node_ref| { node_ref.get().map(move |el| { - let el = el.into_any(); - let el: $ty = el.deref().clone().into(); - el + let el: $ty = el.clone().into(); + SendWrapper::new(el) }) }) .collect() @@ -541,6 +575,7 @@ macro_rules! impl_from_multi_node_ref { impl From<&[NodeRef]> for ElementsMaybeSignal<$ty, $ty> where 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,6 +586,7 @@ macro_rules! impl_from_multi_node_ref { impl From<[NodeRef; C]> for ElementsMaybeSignal<$ty, $ty> where 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,6 +597,7 @@ macro_rules! impl_from_multi_node_ref { impl From>> for ElementsMaybeSignal<$ty, $ty> where R: ElementType + Clone + 'static, + R::Output: JsCast + Into<$ty> + Clone + 'static, { fn from(node_refs: Vec>) -> Self { let node_refs = node_refs.clone(); diff --git a/src/core/maybe_rw_signal.rs b/src/core/maybe_rw_signal.rs index cc7cbd0..3ac2b67 100644 --- a/src/core/maybe_rw_signal.rs +++ b/src/core/maybe_rw_signal.rs @@ -50,26 +50,38 @@ impl From> for MaybeRwSignal { } } -impl From> for MaybeRwSignal { +impl From> for MaybeRwSignal +where + T: Send + Sync, +{ fn from(s: ReadSignal) -> Self { Self::DynamicRead(s.into()) } } -impl From> for MaybeRwSignal { +impl From> for MaybeRwSignal +where + T: Send + Sync, +{ fn from(s: Memo) -> Self { Self::DynamicRead(s.into()) } } -impl From> for MaybeRwSignal { +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 From<(ReadSignal, WriteSignal)> for MaybeRwSignal +where + T: Send + Sync, +{ fn from(s: (ReadSignal, WriteSignal)) -> Self { Self::DynamicRw(s.0.into(), s.1) } @@ -87,7 +99,10 @@ impl From<&str> for MaybeRwSignal { } } -impl MaybeRwSignal { +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..73a7e85 100644 --- a/src/core/use_rw_signal.rs +++ b/src/core/use_rw_signal.rs @@ -22,7 +22,7 @@ where impl Default for UseRwSignal where - T: Default, + T: Default + Send + Sync, { fn default() -> Self { Self::Combined(Default::default()) @@ -47,7 +47,10 @@ impl DefinedAt for UseRwSignal { } } -impl With for UseRwSignal { +impl With for UseRwSignal +where + T: Send + Sync, +{ type Value = T; fn with(&self, f: impl FnOnce(&T) -> R) -> R { @@ -65,7 +68,10 @@ impl With for UseRwSignal { } } -impl WithUntracked for UseRwSignal { +impl WithUntracked for UseRwSignal +where + T: Send + Sync, +{ type Value = T; fn with_untracked(&self, f: impl FnOnce(&T) -> R) -> R { diff --git a/src/lib.rs b/src/lib.rs index 41112af..aaf827c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,11 +25,11 @@ mod is_none; mod is_ok; mod is_some; mod on_click_outside; -mod use_user_media; mod signal_debounced; mod signal_throttled; mod sync_signal; -mod use_active_element; +mod use_user_media; +// mod use_active_element; mod use_breakpoints; mod use_broadcast_channel; mod use_color_mode; @@ -91,11 +91,11 @@ pub use is_none::*; pub use is_ok::*; pub use is_some::*; pub use on_click_outside::*; -pub use use_user_media::*; pub use signal_debounced::*; pub use signal_throttled::*; pub use sync_signal::*; -pub use use_active_element::*; +pub use use_user_media::*; +// pub use use_active_element::*; pub use use_breakpoints::*; pub use use_broadcast_channel::*; pub use use_color_mode::*; 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/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 33016ca..fee58fe 100644 --- a/src/use_breakpoints.rs +++ b/src/use_breakpoints.rs @@ -110,7 +110,7 @@ use std::hash::Hash; /// /// Since internally this uses [`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 } @@ -118,7 +118,7 @@ pub fn use_breakpoints( /// Return type of [`use_breakpoints`] #[derive(Clone)] -pub struct UseBreakpointsReturn { +pub struct UseBreakpointsReturn { breakpoints: HashMap, } @@ -184,7 +184,7 @@ macro_rules! impl_cmp_reactively { }; } -impl UseBreakpointsReturn { +impl UseBreakpointsReturn { 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 22fe06d..9abd612 100644 --- a/src/use_broadcast_channel.rs +++ b/src/use_broadcast_channel.rs @@ -4,6 +4,7 @@ use crate::{ use codee::{CodecError, Decoder, Encoder}; use leptos::ev::messageerror; use leptos::prelude::*; +use send_wrapper::SendWrapper; use thiserror::Error; use wasm_bindgen::JsValue; @@ -80,12 +81,15 @@ 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(None::>); let (message, set_message) = signal(None::); let (error, set_error) = signal( None::>::Error, >::Error>>, @@ -99,7 +103,9 @@ where channel .post_message(&msg.into()) .map_err(|err| { - set_error.set(Some(UseBroadcastChannelError::PostMessage(err))) + set_error.set(Some(UseBroadcastChannelError::PostMessage( + SendWrapper::new(err), + ))) }) .ok(); } @@ -124,7 +130,7 @@ where if is_supported.get_untracked() { let channel_val = web_sys::BroadcastChannel::new(name).ok(); - set_channel.set(channel_val.clone()); + set_channel.set(channel_val.clone().map(SendWrapper::new)); if let Some(channel) = channel_val { let _ = use_event_listener_with_options( @@ -151,7 +157,9 @@ where channel.clone(), messageerror, move |event| { - set_error.set(Some(UseBroadcastChannelError::MessageEvent(event))); + set_error.set(Some(UseBroadcastChannelError::MessageEvent( + SendWrapper::new(event), + ))); }, UseEventListenerOptions::default().passive(true), ); @@ -188,7 +196,7 @@ where pub is_supported: Signal, /// The broadcast channel that is wrapped by this function - pub channel: Signal>, + pub channel: Signal>>, /// Latest message received from the channel pub message: Signal>, @@ -209,9 +217,9 @@ where #[derive(Debug, Error)] pub enum UseBroadcastChannelError { #[error("failed to post message")] - PostMessage(JsValue), + PostMessage(SendWrapper), #[error("channel message error")] - MessageEvent(web_sys::MessageEvent), + MessageEvent(SendWrapper), #[error("failed to (de)encode value")] Codec(CodecError), #[error("received value is not a string")] diff --git a/src/use_device_orientation.rs b/src/use_device_orientation.rs index d7b1265..d2db892 100644 --- a/src/use_device_orientation.rs +++ b/src/use_device_orientation.rs @@ -36,10 +36,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}; diff --git a/src/use_draggable.rs b/src/use_draggable.rs index 796ba51..43f4893 100644 --- a/src/use_draggable.rs +++ b/src/use_draggable.rs @@ -5,8 +5,9 @@ use leptos::ev::{pointerdown, pointermove, pointerup}; use leptos::prelude::diagnostics::SpecialNonReactiveZone; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; +use send_wrapper::SendWrapper; use std::marker::PhantomData; -use std::rc::Rc; +use std::sync::Arc; use wasm_bindgen::JsCast; use web_sys::PointerEvent; @@ -92,11 +93,12 @@ 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 = Signal::derive(|| SendWrapper::new(handle)); + let handle: ElementMaybeSignal<_, _> = handle.into(); + Signal::derive(move || handle.get().map(|handle| SendWrapper::new(handle.into()))) } else { let target = target.clone(); - Signal::derive(move || target.get().map(|target| target.into())) + Signal::derive(move || target.get().map(|target| SendWrapper::new(target.into()))) }; let (position, set_position) = initial_value.into_signal(); @@ -280,13 +282,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 +308,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..f10a88d 100644 --- a/src/use_drop_zone.rs +++ b/src/use_drop_zone.rs @@ -3,8 +3,9 @@ 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::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 +74,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(Vec::>::new()); #[cfg(not(feature = "ssr"))] { @@ -176,22 +177,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 +215,7 @@ pub struct UseDropZoneEvent { /// Return type of [`use_drop_zone`]. pub struct UseDropZoneReturn { /// Files being handled - pub files: Signal>, + pub files: Signal>>, /// Whether the files (dragged by the pointer) are over the drop zone pub is_over_drop_zone: Signal, } diff --git a/src/use_event_source.rs b/src/use_event_source.rs index dddf76b..e857a10 100644 --- a/src/use_event_source.rs +++ b/src/use_event_source.rs @@ -259,9 +259,9 @@ 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())); + set_event.set(Some(SendWrapper::new(e.clone()))); let data_string = js!(e["data"]).ok().and_then(|d| d.as_string()); set_data_from_string(data_string); }, diff --git a/src/use_websocket.rs b/src/use_websocket.rs index 51b657f..2cf593f 100644 --- a/src/use_websocket.rs +++ b/src/use_websocket.rs @@ -303,9 +303,11 @@ 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: SendWrapper| { + ws.ready_state() != WebSocket::OPEN + }) { reconnect_timer_ref.set_value( set_timeout_with_handle( @@ -417,7 +419,7 @@ where on_message(&val); #[cfg(debug_assertions)] - drop(zone); + drop(zone); set_message.set(Some(val)); } @@ -628,7 +630,7 @@ impl ReconnectLimit { } } -type ArcFnBytes = Arc; +type ArcFnBytes = Arc; /// Options for [`use_websocket_with_options`]. #[derive(DefaultBuilder)] @@ -644,7 +646,7 @@ where /// `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>, 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(); From c414022b2363d6510fd498f1e9517777a8b929b7 Mon Sep 17 00:00:00 2001 From: CorvusPrudens Date: Tue, 23 Jul 2024 21:33:14 -0600 Subject: [PATCH 3/6] Completed MVP port --- src/core/element_maybe_signal.rs | 8 +- src/core/elements_maybe_signal.rs | 2 +- src/lib.rs | 4 +- src/on_click_outside.rs | 2 +- src/storage/use_storage.rs | 94 ++++++++++++++--------- src/use_color_mode.rs | 12 +-- src/use_cookie.rs | 121 ++++++++++++++++-------------- src/use_device_orientation.rs | 4 +- src/use_drop_zone.rs | 28 +++++-- src/use_event_source.rs | 23 +++--- src/use_infinite_scroll.rs | 25 +++--- src/use_intersection_observer.rs | 18 +++-- src/use_intl_number_format.rs | 11 +-- src/use_media_query.rs | 5 +- src/use_mutation_observer.rs | 10 ++- src/use_resize_observer.rs | 7 +- src/use_scroll.rs | 10 ++- src/use_service_worker.rs | 6 +- src/use_sorted.rs | 10 +-- src/use_supported.rs | 2 +- src/use_user_media.rs | 11 ++- src/use_web_notification.rs | 2 +- src/use_websocket.rs | 33 ++++---- src/utils/use_derive_signal.rs | 3 +- 24 files changed, 263 insertions(+), 188 deletions(-) diff --git a/src/core/element_maybe_signal.rs b/src/core/element_maybe_signal.rs index 780ed55..f65423e 100644 --- a/src/core/element_maybe_signal.rs +++ b/src/core/element_maybe_signal.rs @@ -171,7 +171,7 @@ where let _ = target; Self::Static(None) } else { - Self::Static(document().query_selector(target).unwrap_or_default()) + Self::Static(document().query_selector(target).unwrap_or_default().map(SendWrapper::new)) }} } } @@ -197,7 +197,7 @@ macro_rules! impl_from_signal_string { Self::Dynamic(Signal::derive(|| None)) } else { Self::Dynamic( - Signal::derive(move || document().query_selector(&signal.get()).unwrap_or_default()), + Signal::derive(move || document().query_selector(&signal.get()).unwrap_or_default().map(SendWrapper::new)), ) }} } @@ -212,8 +212,8 @@ 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!(RwSignal<&'static str>); +impl_from_signal_string!(Memo<&'static str>); // From signal /////////////////////////////////////////////////////////////// diff --git a/src/core/elements_maybe_signal.rs b/src/core/elements_maybe_signal.rs index 069cd7b..4a5a153 100644 --- a/src/core/elements_maybe_signal.rs +++ b/src/core/elements_maybe_signal.rs @@ -156,7 +156,7 @@ where let mut list = Vec::with_capacity(node_list.length() as usize); for i in 0..node_list.length() { let node = node_list.get(i).expect("checked the range"); - list.push(Some(node)); + list.push(Some(SendWrapper::new(node))); } Self::Static(list) diff --git a/src/lib.rs b/src/lib.rs index aaf827c..617c0b3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -68,7 +68,7 @@ mod use_preferred_dark; mod use_raf_fn; mod use_resize_observer; mod use_scroll; -mod use_service_worker; +// mod use_service_worker; mod use_sorted; mod use_supported; mod use_throttle_fn; @@ -134,7 +134,7 @@ pub use use_preferred_dark::*; pub use use_raf_fn::*; pub use use_resize_observer::*; pub use use_scroll::*; -pub use use_service_worker::*; +// pub use use_service_worker::*; pub use use_sorted::*; pub use use_supported::*; pub use use_throttle_fn::*; diff --git a/src/on_click_outside.rs b/src/on_click_outside.rs index d3868c9..db5e2d9 100644 --- a/src/on_click_outside.rs +++ b/src/on_click_outside.rs @@ -149,7 +149,7 @@ where let ignore = ignore.get_untracked(); ignore.into_iter().flatten().any(|element| { - let element: web_sys::EventTarget = element.into(); + let element: web_sys::EventTarget = element.take().into(); event_target::(event) == element || event.composed_path().includes(element.as_ref(), 0) diff --git a/src/storage/use_storage.rs b/src/storage/use_storage.rs index 9b709c8..93a26d1 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; @@ -202,7 +203,7 @@ where // Get storage API let storage = storage_type .into_storage() - .map_err(UseStorageError::StorageNotAvailable) + .map_err(|e| UseStorageError::StorageNotAvailable(SendWrapper::new(e))) .and_then(|s| s.ok_or(UseStorageError::StorageReturnedNone)); let storage = handle_error(&on_error, storage); @@ -226,7 +227,7 @@ where ) .expect("failed to create custom storage event"), ) - .map_err(UseStorageError::NotifyItemChangedFailed); + .map_err(|e| UseStorageError::NotifyItemChangedFailed(SendWrapper::new(e))); let _ = handle_error(&on_error, result); }) } @@ -238,14 +239,14 @@ 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| { // Get directly from storage let result = storage .get_item(&key) - .map_err(UseStorageError::GetItemFailed); + .map_err(|e| UseStorageError::GetItemFailed(SendWrapper::new(e))); handle_error(&on_error, result) }) .unwrap_or_default() // Drop handled Err(()) @@ -270,20 +271,25 @@ 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(move |prev| { - notify.track(); - match prev { - None => 1, // Avoid async fetch of initial value - Some(prev) => { - fetch_from_storage(); - prev + 1 + let notify_id = Memo::::new({ + let notify = notify.clone(); + let fetch_from_storage = fetch_from_storage.clone(); + + move |prev| { + notify.track(); + match prev { + None => 1, // Avoid async fetch of initial value + Some(prev) => { + fetch_from_storage(); + prev + 1 + } } } }); @@ -308,9 +314,9 @@ where .map_err(|e| UseStorageError::ItemCodecError(CodecError::Encode(e))) .and_then(|enc_value| { // Set storage -- sends a global event - storage - .set_item(&key, &enc_value) - .map_err(UseStorageError::SetItemFailed) + storage.set_item(&key, &enc_value).map_err(|e| { + UseStorageError::SetItemFailed(SendWrapper::new(e)) + }) }); let result = handle_error(&on_error, result); // Send internal storage event @@ -323,31 +329,42 @@ where ); } - // Fetch initial value - if delay_during_hydration && leptos::leptos_dom::HydrationCtx::is_hydrating() { - request_animation_frame(fetch_from_storage.clone()); - } else { - fetch_from_storage(); - } + // TODO: solve for 0.7 + // // Fetch initial value + // if delay_during_hydration && leptos::leptos_dom::HydrationCtx::is_hydrating() { + // request_animation_frame(fetch_from_storage.clone()); + // } else { + // fetch_from_storage(); + // } + request_animation_frame({ + let fetch_from_storage = fetch_from_storage.clone(); + #[allow(clippy::redundant_closure)] + move || 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() + } } }, ); @@ -361,9 +378,9 @@ where // Delete directly from storage let result = storage .remove_item(&key) - .map_err(UseStorageError::RemoveItemFailed); + .map_err(|e| UseStorageError::RemoveItemFailed(SendWrapper::new(e))); let _ = handle_error(&on_error, result); - notify.notify(); + notify.trigger(); dispatch_storage_event(); }); } @@ -377,17 +394,17 @@ where #[derive(Error, Debug)] pub enum UseStorageError { #[error("storage not available")] - StorageNotAvailable(JsValue), + StorageNotAvailable(SendWrapper), #[error("storage not returned from window")] StorageReturnedNone, #[error("failed to get item")] - GetItemFailed(JsValue), + GetItemFailed(SendWrapper), #[error("failed to set item")] - SetItemFailed(JsValue), + SetItemFailed(SendWrapper), #[error("failed to delete item")] - RemoveItemFailed(JsValue), + RemoveItemFailed(SendWrapper), #[error("failed to notify item changed")] - NotifyItemChangedFailed(JsValue), + NotifyItemChangedFailed(SendWrapper), #[error("failed to encode / decode item value")] ItemCodecError(CodecError), } @@ -400,7 +417,7 @@ where { // 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 @@ -418,7 +435,7 @@ 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)) @@ -438,7 +455,10 @@ impl Default for UseStorageOptions { impl UseStorageOptions { /// 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/use_color_mode.rs b/src/use_color_mode.rs index d233475..d1d3194 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 e624d11..11c3b9f 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. /// @@ -143,7 +143,7 @@ use std::rc::Rc; pub fn use_cookie(cookie_name: &str) -> (Signal>, WriteSignal>) where C: Encoder + Decoder, - T: Clone, + T: Clone + Send + Sync, { use_cookie_with_options::(cookie_name, UseCookieOptions::default()) } @@ -155,7 +155,7 @@ pub fn use_cookie_with_options( ) -> (Signal>, WriteSignal>) where C: Encoder + Decoder, - T: Clone, + T: Clone + Send + Sync, { let UseCookieOptions { max_age, @@ -189,7 +189,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) { @@ -229,8 +229,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(); @@ -265,7 +265,7 @@ where same_site, secure, http_only, - Rc::clone(&ssr_cookies_header_getter), + Arc::clone(&ssr_cookies_header_getter), ); }); @@ -288,7 +288,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 |_| { @@ -299,7 +299,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( @@ -325,7 +325,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( @@ -467,14 +467,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 { @@ -490,7 +490,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"))] @@ -564,7 +564,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")] @@ -615,7 +615,7 @@ impl Default for UseCookieOptions { let _ = cookie; }), - on_error: Rc::new(|_| { + on_error: Arc::new(|_| { error!("cookie (de-/)serialization error"); }), } @@ -623,7 +623,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; @@ -646,71 +646,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(); }; } @@ -735,7 +744,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; @@ -771,7 +780,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; @@ -859,7 +868,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( @@ -877,7 +886,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_device_orientation.rs b/src/use_device_orientation.rs index d2db892..f02ee54 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 @@ -67,7 +68,8 @@ pub fn use_device_orientation() -> UseDeviceOrientationReturn { .once(false), ); - on_cleanup(cleanup); + let cleanup = SendWrapper::new(cleanup); + on_cleanup(move || cleanup()); } }} diff --git a/src/use_drop_zone.rs b/src/use_drop_zone.rs index f10a88d..e88b345 100644 --- a/src/use_drop_zone.rs +++ b/src/use_drop_zone.rs @@ -90,12 +90,12 @@ 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() .into_iter() - .map(web_sys::File::from) + .map(|f| SendWrapper::new(web_sys::File::from(f))) .collect(); set_files.update(move |f| *f = files); @@ -113,7 +113,11 @@ where let _z = SpecialNonReactiveZone::enter(); on_enter(UseDropZoneEvent { - files: files.get_untracked(), + files: files + .get_untracked() + .into_iter() + .map(SendWrapper::take) + .collect(), event, }); }); @@ -126,7 +130,11 @@ where let _z = SpecialNonReactiveZone::enter(); on_over(UseDropZoneEvent { - files: files.get_untracked(), + files: files + .get_untracked() + .into_iter() + .map(SendWrapper::take) + .collect(), event, }); }); @@ -144,7 +152,11 @@ where let _z = SpecialNonReactiveZone::enter(); on_leave(UseDropZoneEvent { - files: files.get_untracked(), + files: files + .get_untracked() + .into_iter() + .map(SendWrapper::take) + .collect(), event, }); }); @@ -160,7 +172,11 @@ where let _z = SpecialNonReactiveZone::enter(); on_drop(UseDropZoneEvent { - files: files.get_untracked(), + files: files + .get_untracked() + .into_iter() + .map(SendWrapper::take) + .collect(), event, }); }); diff --git a/src/use_event_source.rs b/src/use_event_source.rs index e857a10..9909c4f 100644 --- a/src/use_event_source.rs +++ b/src/use_event_source.rs @@ -5,8 +5,8 @@ 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; @@ -154,8 +154,8 @@ where let (event_source, set_event_source) = signal(None::>); let (error, set_error) = signal(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 { @@ -174,7 +174,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); } } }; @@ -188,7 +188,7 @@ where move || { use wasm_bindgen::prelude::*; - if explicitly_closed.get() { + if explicitly_closed.load(std::sync::atomic::Ordering::Relaxed) { return; } @@ -222,14 +222,15 @@ where // 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() { @@ -281,8 +282,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(); } @@ -326,7 +327,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. diff --git a/src/use_infinite_scroll.rs b/src/use_infinite_scroll.rs index 3239ac0..4059c64 100644 --- a/src/use_infinite_scroll.rs +++ b/src/use_infinite_scroll.rs @@ -9,8 +9,9 @@ use gloo_timers::future::sleep; use leptos::prelude::diagnostics::SpecialNonReactiveZone; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; +use send_wrapper::SendWrapper; use std::future::Future; -use std::rc::Rc; +use std::sync::Arc; use std::time::Duration; use wasm_bindgen::JsCast; @@ -55,7 +56,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 +71,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 { @@ -117,20 +118,22 @@ where let el = el.into(); if el.is_instance_of::() || el.is_instance_of::() { - document() - .document_element() - .expect("document element not found") + SendWrapper::new( + document() + .document_element() + .expect("document element not found"), + ) } else { - el + SendWrapper::new(el) } }) }); 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 +218,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 +236,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 7e3bcea..5f24990 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(); } } @@ -173,11 +175,11 @@ where .expect("failed to create IntersectionObserver"); for target in targets.iter().flatten() { - let target: web_sys::Element = target.clone().into(); + let target: web_sys::Element = target.clone().take().into(); obs.observe(&target); } - observer.replace(Some(obs)); + *observer.lock().unwrap() = Some(SendWrapper::new(obs)); }, WatchOptions::default().immediate(immediate), ) diff --git a/src/use_intl_number_format.rs b/src/use_intl_number_format.rs index 9fe9aca..ca95fd0 100644 --- a/src/use_intl_number_format.rs +++ b/src/use_intl_number_format.rs @@ -6,6 +6,7 @@ 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::fmt::Display; use wasm_bindgen::{JsCast, JsValue}; @@ -167,7 +168,7 @@ pub fn use_intl_number_format(options: UseIntlNumberFormatOptions) -> UseIntlNum ); UseIntlNumberFormatReturn { - js_intl_number_format: number_format, + js_intl_number_format: SendWrapper::new(number_format), } }} } @@ -768,7 +769,7 @@ cfg_if! { if #[cfg(feature = "ssr")] { /// Return type of [`use_intl_number_format`]. pub struct UseIntlNumberFormatReturn { /// The instance of [`Intl.NumberFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat). - pub js_intl_number_format: js_sys::Intl::NumberFormat, + pub js_intl_number_format: SendWrapper, } }} @@ -777,7 +778,7 @@ impl UseIntlNumberFormatReturn { /// See [`use_intl_number_format`] for more information. 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(); @@ -854,8 +855,8 @@ impl UseIntlNumberFormatReturn { end: impl Into>, ) -> 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, { diff --git a/src/use_media_query.rs b/src/use_media_query.rs index f3ad681..c5e3ffb 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..ceabaa4 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(); @@ -135,7 +136,7 @@ where .expect("failed to create MutationObserver"); for target in targets.iter().flatten() { - let target: web_sys::Element = target.clone().into(); + let target: web_sys::Element = target.clone().take().into(); let _ = obs.observe_with_options(&target, &options.clone().into()); } @@ -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_resize_observer.rs b/src/use_resize_observer.rs index 34bb0c2..c6d96e1 100644 --- a/src/use_resize_observer.rs +++ b/src/use_resize_observer.rs @@ -138,7 +138,7 @@ where .expect("failed to create ResizeObserver"); for target in targets.iter().flatten() { - let target: web_sys::Element = target.clone().into(); + let target: web_sys::Element = target.clone().take().into(); obs.observe_with_options(&target, &options.clone().into()); } observer.replace(Some(obs)); @@ -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..b00dec2 100644 --- a/src/use_scroll.rs +++ b/src/use_scroll.rs @@ -221,6 +221,8 @@ where let set_y = |_| {}; let measure = || {}; } else { + use send_wrapper::SendWrapper; + let signal = element.into(); let behavior = options.behavior; @@ -372,7 +374,7 @@ where Signal::derive(move || { let element = signal.get(); - element.map(|element| element.into().unchecked_into::()) + element.map(|element| SendWrapper::new(element.into().unchecked_into::())) }) }; @@ -392,14 +394,14 @@ where let _ = use_event_listener_with_options::< _, - Signal>, + Signal>>, web_sys::EventTarget, _, >(target, ev::scroll, handler, options.event_listener_options); } else { let _ = use_event_listener_with_options::< _, - Signal>, + Signal>>, web_sys::EventTarget, _, >( @@ -412,7 +414,7 @@ where let _ = use_event_listener_with_options::< _, - Signal>, + Signal>>, web_sys::EventTarget, _, >( diff --git a/src/use_service_worker.rs b/src/use_service_worker.rs index 508b3d6..76958b1 100644 --- a/src/use_service_worker.rs +++ b/src/use_service_worker.rs @@ -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)), } } }, @@ -275,8 +275,10 @@ fn create_action_create_or_update_registration() -> Action< 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"))) } } }) diff --git a/src/use_sorted.rs b/src/use_sorted.rs index 02436ef..e837b4a 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, { 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, + 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, 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..aba11dc 100644 --- a/src/use_user_media.rs +++ b/src/use_user_media.rs @@ -2,6 +2,7 @@ use crate::core::MaybeRwSignal; use cfg_if::cfg_if; use default_struct_builder::DefaultBuilder; use leptos::prelude::*; +use send_wrapper::SendWrapper; use wasm_bindgen::{JsCast, JsValue}; /// Reactive [`mediaDevices.getUserMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia) streaming. @@ -59,7 +60,8 @@ 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(None::, SendWrapper>>); let _start = move || async move { cfg_if! { if #[cfg(not(feature = "ssr"))] { @@ -67,7 +69,10 @@ pub fn use_user_media_with_options( return; } - let stream = create_media(video, audio).await; + let stream = create_media(video, audio) + .await + .map(SendWrapper::new) + .map_err(SendWrapper::new); set_stream.update(|s| *s = Some(stream)); } else { @@ -187,7 +192,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, SendWrapper>>>, /// 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..afad4df 100644 --- a/src/use_web_notification.rs +++ b/src/use_web_notification.rs @@ -149,7 +149,7 @@ pub fn use_web_notification_with_options( notification_value.set_onerror(Some(on_error_closure.unchecked_ref())); notification_value.set_onshow(Some(on_show_closure.unchecked_ref())); - set_notification.set(Some(notification_value)); + set_notification.set(Some(SendWrapper::new(notification_value))); }); } }; diff --git a/src/use_websocket.rs b/src/use_websocket.rs index 2cf593f..776706d 100644 --- a/src/use_websocket.rs +++ b/src/use_websocket.rs @@ -237,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>, @@ -261,7 +261,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>, @@ -358,7 +358,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 +387,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 +409,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 +446,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 +473,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 +502,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; } @@ -524,7 +525,7 @@ where onclose_closure.forget(); } - ws_ref.set_value(Some(web_socket)); + ws_ref.set_value(Some(SendWrapper::new(web_socket))); })) }); } @@ -642,7 +643,7 @@ 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. @@ -669,7 +670,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 +681,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 +711,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, diff --git a/src/utils/use_derive_signal.rs b/src/utils/use_derive_signal.rs index 1e7e9c2..e715129 100644 --- a/src/utils/use_derive_signal.rs +++ b/src/utils/use_derive_signal.rs @@ -1,5 +1,5 @@ /// Macro to easily create helper functions that derive a signal using a piece of code. -/// +/// /// See [`is_ok`] or [`use_to_string`] as examples. #[macro_export] macro_rules! use_derive_signal { @@ -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(); From feb585362e4fdb36ecb7fc0e7dca9fe19c488adf Mon Sep 17 00:00:00 2001 From: CorvusPrudens Date: Sat, 3 Aug 2024 23:28:09 -0600 Subject: [PATCH 4/6] Removed all trivial SendWrappers --- src/core/element_maybe_signal.rs | 85 +++++------ src/core/elements_maybe_signal.rs | 224 +++++++++++++---------------- src/core/maybe_rw_signal.rs | 143 +++++++++++++++--- src/core/use_rw_signal.rs | 72 +++++++--- src/lib.rs | 4 +- src/on_click_outside.rs | 2 +- src/storage/use_local_storage.rs | 2 +- src/storage/use_session_storage.rs | 2 +- src/storage/use_storage.rs | 63 ++++---- src/use_breakpoints.rs | 5 +- src/use_broadcast_channel.rs | 29 ++-- src/use_cookie.rs | 59 ++++---- src/use_cycle_list.rs | 6 +- src/use_device_orientation.rs | 6 +- src/use_display_media.rs | 11 +- src/use_draggable.rs | 6 +- src/use_drop_zone.rs | 31 +--- src/use_event_listener.rs | 6 +- src/use_event_source.rs | 21 ++- src/use_geolocation.rs | 13 +- src/use_infinite_scroll.rs | 13 +- src/use_intersection_observer.rs | 2 +- src/use_interval_fn.rs | 6 +- src/use_intl_number_format.rs | 17 ++- src/use_mutation_observer.rs | 2 +- src/use_raf_fn.rs | 6 +- src/use_resize_observer.rs | 2 +- src/use_scroll.rs | 12 +- src/use_service_worker.rs | 8 +- src/use_sorted.rs | 6 +- src/use_user_media.rs | 11 +- src/use_web_notification.rs | 7 +- src/use_websocket.rs | 11 +- 33 files changed, 488 insertions(+), 405 deletions(-) diff --git a/src/core/element_maybe_signal.rs b/src/core/element_maybe_signal.rs index f65423e..5f3b68c 100644 --- a/src/core/element_maybe_signal.rs +++ b/src/core/element_maybe_signal.rs @@ -18,8 +18,8 @@ pub enum ElementMaybeSignal where T: Into + Clone + 'static, { - Static(Option>), - Dynamic(Signal>>), + Static(SendWrapper>), + Dynamic(Signal, LocalStorage>), _Phantom(PhantomData E>), } @@ -28,7 +28,7 @@ where T: Into + Clone + 'static, { fn default() -> Self { - Self::Static(None) + Self::Static(SendWrapper::new(None)) } } @@ -62,28 +62,19 @@ where fn with(&self, f: impl FnOnce(&Option) -> O) -> O { match self { - Self::Static(t) => { - let value = t.as_ref().map(|t| t.clone().take()); + Self::Static(t) => f(&t), + Self::Dynamic(s) => { + let value = s.get(); f(&value) } - Self::Dynamic(s) => s.with(|s| { - let value = s.as_ref().map(|s| s.clone().take()); - f(&value) - }), _ => unreachable!(), } } fn try_with(&self, f: impl FnOnce(&Option) -> O) -> Option { match self { - Self::Static(t) => { - let value = t.as_ref().map(|t| t.clone().take()); - Some(f(&value)) - } - Self::Dynamic(s) => s.try_with(|s| { - let value = s.as_ref().map(|s| s.clone().take()); - f(&value) - }), + Self::Static(t) => Some(f(&t)), + Self::Dynamic(s) => s.try_with(f), _ => unreachable!(), } } @@ -97,28 +88,16 @@ where fn with_untracked(&self, f: impl FnOnce(&Option) -> O) -> O { match self { - Self::Static(t) => { - let value = t.as_ref().map(|t| t.clone().take()); - f(&value) - } - Self::Dynamic(s) => s.with_untracked(|s| { - let value = s.as_ref().map(|s| s.clone().take()); - f(&value) - }), + Self::Static(t) => f(&t), + Self::Dynamic(s) => s.with_untracked(f), _ => unreachable!(), } } fn try_with_untracked(&self, f: impl FnOnce(&Option) -> O) -> Option { match self { - Self::Static(t) => { - let value = t.as_ref().map(|t| t.clone().take()); - Some(f(&value)) - } - Self::Dynamic(s) => s.try_with_untracked(|s| { - let value = s.as_ref().map(|s| s.clone().take()); - f(&value) - }), + Self::Static(t) => Some(f(&t)), + Self::Dynamic(s) => s.try_with_untracked(f), _ => unreachable!(), } } @@ -131,7 +110,7 @@ where T: Into + Clone + 'static, { fn from(value: T) -> Self { - ElementMaybeSignal::Static(Some(SendWrapper::new(value))) + ElementMaybeSignal::Static(SendWrapper::new(Some(value))) } } @@ -140,7 +119,7 @@ where T: Into + Clone + 'static, { fn from(target: Option) -> Self { - ElementMaybeSignal::Static(target.map(SendWrapper::new)) + ElementMaybeSignal::Static(SendWrapper::new(target)) } } @@ -151,7 +130,7 @@ macro_rules! impl_from_deref_option { E: From<$ty2> + 'static, { fn from(value: $ty) -> Self { - Self::Static((*value).clone().map(SendWrapper::new)) + Self::Static(SendWrapper::new((*value).clone())) } } }; @@ -169,9 +148,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().map(SendWrapper::new)) + Self::Static(SendWrapper::new(document().query_selector(target).unwrap_or_default())) }} } } @@ -194,10 +173,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().map(SendWrapper::new)), + Signal::derive_local(move || document().query_selector(&signal.get()).unwrap_or_default()), ) }} } @@ -210,8 +189,8 @@ 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!(Signal<&'static str>); +impl_from_signal_string!(ReadSignal<&'static str>); impl_from_signal_string!(RwSignal<&'static str>); impl_from_signal_string!(Memo<&'static str>); @@ -230,10 +209,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) => { @@ -242,16 +221,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 ////////////////////////////////////////////////////////////// @@ -263,10 +242,10 @@ macro_rules! impl_from_node_ref { 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: $ty = el.clone().into(); - SendWrapper::new(el) + el }) })) } diff --git a/src/core/elements_maybe_signal.rs b/src/core/elements_maybe_signal.rs index 4a5a153..41a520f 100644 --- a/src/core/elements_maybe_signal.rs +++ b/src/core/elements_maybe_signal.rs @@ -1,12 +1,11 @@ use crate::core::ElementMaybeSignal; use crate::{UseDocument, UseWindow}; use cfg_if::cfg_if; -use leptos::html::{ElementType, HtmlElement}; +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,8 +19,8 @@ pub enum ElementsMaybeSignal where T: Into + Clone + 'static, { - Static(Vec>>), - Dynamic(Signal>>>), + Static(SendWrapper>>), + Dynamic(Signal>, LocalStorage>), _Phantom(PhantomData E>), } @@ -30,7 +29,7 @@ where T: Into + Clone + 'static, { fn default() -> Self { - Self::Static(vec![]) + Self::Static(SendWrapper::new(vec![])) } } @@ -60,9 +59,9 @@ impl With for ElementsMaybeSignal where T: Into + Clone + 'static, { - type Value = Vec>>; + type Value = Vec>; - fn with(&self, f: impl FnOnce(&Vec>>) -> O) -> O { + fn with(&self, f: impl FnOnce(&Vec>) -> O) -> O { match self { Self::Static(v) => f(v), Self::Dynamic(s) => s.with(f), @@ -70,7 +69,7 @@ where } } - fn try_with(&self, f: impl FnOnce(&Vec>>) -> O) -> Option { + fn try_with(&self, f: impl FnOnce(&Vec>) -> O) -> Option { match self { Self::Static(v) => Some(f(v)), Self::Dynamic(s) => s.try_with(f), @@ -83,9 +82,9 @@ impl WithUntracked for ElementsMaybeSignal where T: Into + Clone + 'static, { - type Value = Vec>>; + type Value = Vec>; - fn with_untracked(&self, f: impl FnOnce(&Vec>>) -> O) -> O { + fn with_untracked(&self, f: impl FnOnce(&Vec>) -> O) -> O { match self { Self::Static(t) => f(t), Self::Dynamic(s) => s.with_untracked(f), @@ -93,10 +92,7 @@ where } } - fn try_with_untracked( - &self, - f: impl FnOnce(&Vec>>) -> O, - ) -> Option { + fn try_with_untracked(&self, f: impl FnOnce(&Vec>) -> O) -> Option { match self { Self::Static(t) => Some(f(t)), Self::Dynamic(s) => s.try_with_untracked(f), @@ -112,7 +108,7 @@ where T: Into + Clone + 'static, { fn from(value: T) -> Self { - ElementsMaybeSignal::Static(vec![Some(SendWrapper::new(value))]) + ElementsMaybeSignal::Static(SendWrapper::new(vec![Some(value)])) } } @@ -121,7 +117,7 @@ where T: Into + Clone + 'static, { fn from(target: Option) -> Self { - ElementsMaybeSignal::Static(vec![target.map(SendWrapper::new)]) + ElementsMaybeSignal::Static(SendWrapper::new(vec![target])) } } @@ -132,7 +128,7 @@ macro_rules! impl_from_deref_option { E: From<$ty2> + 'static, { fn from(value: $ty) -> Self { - Self::Static(vec![(*value).clone().map(SendWrapper::new)]) + Self::Static(SendWrapper::new(vec![(*value).clone()])) } } }; @@ -150,18 +146,18 @@ 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); for i in 0..node_list.length() { let node = node_list.get(i).expect("checked the range"); - list.push(Some(SendWrapper::new(node))); + list.push(Some(node)); } - Self::Static(list) + Self::Static(SendWrapper::new(list)) } else { - Self::Static(vec![]) + Self::Static(SendWrapper::new(vec![])) } }} } @@ -185,12 +181,12 @@ 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() { let node = node_list.get(i).expect("checked the range"); - list.push(Some(SendWrapper::new(node))); + list.push(Some(node)); } list } else { @@ -200,7 +196,7 @@ macro_rules! impl_from_signal_string { ) } else { let _ = signal; - Self::Dynamic(Signal::derive(Vec::new)) + Self::Dynamic(Signal::derive_local(Vec::new)) }} } } @@ -212,8 +208,8 @@ 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!(Signal<&'static str>); +impl_from_signal_string!(ReadSignal<&'static str>); impl_from_signal_string!(RwSignal<&'static str>); impl_from_signal_string!(Memo<&'static str>); @@ -226,16 +222,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) => { @@ -244,16 +240,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 ////////////////////////////////////////////////////////////// @@ -265,10 +261,10 @@ macro_rules! impl_from_node_ref { 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: $ty = el.clone().into(); - SendWrapper::new(el) + el })] })) } @@ -306,12 +302,9 @@ where T: Into + Clone + 'static, { fn from(target: &[T]) -> Self { - Self::Static( - target - .iter() - .map(|t| Some(SendWrapper::new(t.clone()))) - .collect(), - ) + Self::Static(SendWrapper::new( + target.iter().map(|t| Some(t.clone())).collect(), + )) } } @@ -320,12 +313,7 @@ where T: Into + Clone + 'static, { fn from(target: &[Option]) -> Self { - Self::Static( - target - .iter() - .map(|t| t.clone().map(SendWrapper::new)) - .collect(), - ) + Self::Static(SendWrapper::new(target.iter().map(|t| t.clone()).collect())) } } @@ -334,12 +322,9 @@ where T: Into + Clone + 'static, { fn from(target: Vec) -> Self { - Self::Static( - target - .iter() - .map(|t| Some(SendWrapper::new(t.clone()))) - .collect(), - ) + Self::Static(SendWrapper::new( + target.iter().map(|t| Some(t.clone())).collect(), + )) } } @@ -348,12 +333,7 @@ where T: Into + Clone + 'static, { fn from(target: Vec>) -> Self { - Self::Static( - target - .into_iter() - .map(|t| t.map(SendWrapper::new)) - .collect(), - ) + Self::Static(SendWrapper::new(target.into_iter().map(|t| t).collect())) } } @@ -362,12 +342,9 @@ where T: Into + Clone + 'static, { fn from(target: [T; C]) -> Self { - Self::Static( - target - .into_iter() - .map(|t| Some(SendWrapper::new(t))) - .collect(), - ) + Self::Static(SendWrapper::new( + target.into_iter().map(|t| Some(t)).collect(), + )) } } @@ -376,12 +353,7 @@ where T: Into + Clone + 'static, { fn from(target: [Option; C]) -> Self { - Self::Static( - target - .into_iter() - .map(|t| t.map(SendWrapper::new)) - .collect(), - ) + Self::Static(SendWrapper::new(target.into_iter().collect())) } } @@ -390,30 +362,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(SendWrapper::new(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(), + ) ) }; } @@ -452,101 +426,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() })) } @@ -556,13 +530,13 @@ 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: $ty = el.clone().into(); - SendWrapper::new(el) + el }) }) .collect() @@ -685,9 +659,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 3ac2b67..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,12 +48,42 @@ 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 FromLocal> for MaybeRwSignal +where + LocalStorage: Storage, +{ + fn from_local(s: Signal) -> Self { + Self::DynamicRead(s) + } +} + impl From> for MaybeRwSignal where T: Send + Sync, @@ -59,6 +93,15 @@ where } } +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, @@ -68,6 +111,15 @@ where } } +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, @@ -78,6 +130,16 @@ where } } +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, @@ -87,18 +149,67 @@ where } } -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 { + 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, diff --git a/src/core/use_rw_signal.rs b/src/core/use_rw_signal.rs index 73a7e85..c86e722 100644 --- a/src/core/use_rw_signal.rs +++ b/src/core/use_rw_signal.rs @@ -1,21 +1,28 @@ 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) } } @@ -29,15 +36,30 @@ where } } -impl Clone for UseRwSignal { +impl Default for UseRwSignal +where + T: Default, +{ + fn default() -> Self { + Self::Combined(Default::default()) + } +} + +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,9 +69,12 @@ impl DefinedAt for UseRwSignal { } } -impl With for UseRwSignal +impl With for UseRwSignal where - T: Send + Sync, + RwSignal: With, + Signal: With, + ReadSignal: With, + S: Storage, { type Value = T; @@ -68,9 +93,12 @@ where } } -impl WithUntracked for UseRwSignal +impl WithUntracked for UseRwSignal where - T: Send + Sync, + RwSignal: WithUntracked, + Signal: WithUntracked, + ReadSignal: WithUntracked, + S: Storage, { type Value = T; @@ -89,7 +117,12 @@ where } } -impl Set for UseRwSignal { +impl Set for UseRwSignal +where + RwSignal: Set, + WriteSignal: Set, + S: Storage, +{ type Value = T; fn set(&self, new_value: T) { @@ -107,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 617c0b3..aaf827c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -68,7 +68,7 @@ mod use_preferred_dark; mod use_raf_fn; mod use_resize_observer; mod use_scroll; -// mod use_service_worker; +mod use_service_worker; mod use_sorted; mod use_supported; mod use_throttle_fn; @@ -134,7 +134,7 @@ pub use use_preferred_dark::*; pub use use_raf_fn::*; pub use use_resize_observer::*; pub use use_scroll::*; -// pub use use_service_worker::*; +pub use use_service_worker::*; pub use use_sorted::*; pub use use_supported::*; pub use use_throttle_fn::*; diff --git a/src/on_click_outside.rs b/src/on_click_outside.rs index db5e2d9..d3868c9 100644 --- a/src/on_click_outside.rs +++ b/src/on_click_outside.rs @@ -149,7 +149,7 @@ where let ignore = ignore.get_untracked(); ignore.into_iter().flatten().any(|element| { - let element: web_sys::EventTarget = element.take().into(); + let element: web_sys::EventTarget = element.into(); event_target::(event) == element || event.composed_path().includes(element.as_ref(), 0) diff --git a/src/storage/use_local_storage.rs b/src/storage/use_local_storage.rs index 0009439..9f3a66b 100644 --- a/src/storage/use_local_storage.rs +++ b/src/storage/use_local_storage.rs @@ -15,7 +15,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 cce1d65..bbf5777 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 93a26d1..96a2be2 100644 --- a/src/storage/use_storage.rs +++ b/src/storage/use_storage.rs @@ -152,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()) @@ -203,7 +203,7 @@ where // Get storage API let storage = storage_type .into_storage() - .map_err(|e| UseStorageError::StorageNotAvailable(SendWrapper::new(e))) + .map_err(UseStorageError::StorageNotAvailable) .and_then(|s| s.ok_or(UseStorageError::StorageReturnedNone)); let storage = handle_error(&on_error, storage); @@ -227,7 +227,7 @@ where ) .expect("failed to create custom storage event"), ) - .map_err(|e| UseStorageError::NotifyItemChangedFailed(SendWrapper::new(e))); + .map_err(UseStorageError::NotifyItemChangedFailed); let _ = handle_error(&on_error, result); }) } @@ -246,7 +246,7 @@ where // Get directly from storage let result = storage .get_item(&key) - .map_err(|e| UseStorageError::GetItemFailed(SendWrapper::new(e))); + .map_err(UseStorageError::GetItemFailed); handle_error(&on_error, result) }) .unwrap_or_default() // Drop handled Err(()) @@ -314,9 +314,9 @@ where .map_err(|e| UseStorageError::ItemCodecError(CodecError::Encode(e))) .and_then(|enc_value| { // Set storage -- sends a global event - storage.set_item(&key, &enc_value).map_err(|e| { - UseStorageError::SetItemFailed(SendWrapper::new(e)) - }) + storage + .set_item(&key, &enc_value) + .map_err(UseStorageError::SetItemFailed) }); let result = handle_error(&on_error, result); // Send internal storage event @@ -329,18 +329,19 @@ where ); } - // TODO: solve for 0.7 - // // Fetch initial value - // if delay_during_hydration && leptos::leptos_dom::HydrationCtx::is_hydrating() { - // request_animation_frame(fetch_from_storage.clone()); - // } else { - // fetch_from_storage(); - // } - request_animation_frame({ - let fetch_from_storage = fetch_from_storage.clone(); - #[allow(clippy::redundant_closure)] - move || fetch_from_storage() - }); + 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(); @@ -378,7 +379,7 @@ where // Delete directly from storage let result = storage .remove_item(&key) - .map_err(|e| UseStorageError::RemoveItemFailed(SendWrapper::new(e))); + .map_err(|e| UseStorageError::RemoveItemFailed(e)); let _ = handle_error(&on_error, result); notify.trigger(); dispatch_storage_event(); @@ -394,17 +395,17 @@ where #[derive(Error, Debug)] pub enum UseStorageError { #[error("storage not available")] - StorageNotAvailable(SendWrapper), + StorageNotAvailable(JsValue), #[error("storage not returned from window")] StorageReturnedNone, #[error("failed to get item")] - GetItemFailed(SendWrapper), + GetItemFailed(JsValue), #[error("failed to set item")] - SetItemFailed(SendWrapper), + SetItemFailed(JsValue), #[error("failed to delete item")] - RemoveItemFailed(SendWrapper), + RemoveItemFailed(JsValue), #[error("failed to notify item changed")] - NotifyItemChangedFailed(SendWrapper), + NotifyItemChangedFailed(JsValue), #[error("failed to encode / decode item value")] ItemCodecError(CodecError), } @@ -413,7 +414,7 @@ pub enum UseStorageError { #[derive(DefaultBuilder)] pub struct UseStorageOptions where - T: 'static, + T: Send + Sync + 'static, { // Callback for when an error occurs #[builder(skip)] @@ -441,7 +442,10 @@ fn handle_error( 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| ()), @@ -453,7 +457,10 @@ impl Default for UseStorageOptions { } } -impl UseStorageOptions { +impl UseStorageOptions +where + T: Send + Sync + 'static, +{ /// Optional callback whenever an error occurs. pub fn on_error( self, diff --git a/src/use_breakpoints.rs b/src/use_breakpoints.rs index fee58fe..e2f8106 100644 --- a/src/use_breakpoints.rs +++ b/src/use_breakpoints.rs @@ -184,7 +184,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 9abd612..9f09186 100644 --- a/src/use_broadcast_channel.rs +++ b/src/use_broadcast_channel.rs @@ -4,7 +4,6 @@ use crate::{ use codee::{CodecError, Decoder, Encoder}; use leptos::ev::messageerror; use leptos::prelude::*; -use send_wrapper::SendWrapper; use thiserror::Error; use wasm_bindgen::JsValue; @@ -89,9 +88,9 @@ where 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>>, ); @@ -103,9 +102,7 @@ where channel .post_message(&msg.into()) .map_err(|err| { - set_error.set(Some(UseBroadcastChannelError::PostMessage( - SendWrapper::new(err), - ))) + set_error.set(Some(UseBroadcastChannelError::PostMessage(err))) }) .ok(); } @@ -130,7 +127,7 @@ where if is_supported.get_untracked() { let channel_val = web_sys::BroadcastChannel::new(name).ok(); - set_channel.set(channel_val.clone().map(SendWrapper::new)); + set_channel.set(channel_val.clone()); if let Some(channel) = channel_val { let _ = use_event_listener_with_options( @@ -157,9 +154,7 @@ where channel.clone(), messageerror, move |event| { - set_error.set(Some(UseBroadcastChannelError::MessageEvent( - SendWrapper::new(event), - ))); + set_error.set(Some(UseBroadcastChannelError::MessageEvent(event))); }, UseEventListenerOptions::default().passive(true), ); @@ -186,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>, @@ -208,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, @@ -217,9 +212,9 @@ where #[derive(Debug, Error)] pub enum UseBroadcastChannelError { #[error("failed to post message")] - PostMessage(SendWrapper), + PostMessage(JsValue), #[error("channel message error")] - MessageEvent(SendWrapper), + MessageEvent(web_sys::MessageEvent), #[error("failed to (de)encode value")] Codec(CodecError), #[error("received value is not a string")] diff --git a/src/use_cookie.rs b/src/use_cookie.rs index 11c3b9f..f1261e5 100644 --- a/src/use_cookie.rs +++ b/src/use_cookie.rs @@ -143,7 +143,7 @@ use std::sync::Arc; pub fn use_cookie(cookie_name: &str) -> (Signal>, WriteSignal>) where C: Encoder + Decoder, - T: Clone + Send + Sync, + T: Clone + Send + Sync + 'static, { use_cookie_with_options::(cookie_name, UseCookieOptions::default()) } @@ -155,7 +155,7 @@ pub fn use_cookie_with_options( ) -> (Signal>, WriteSignal>) where C: Encoder + Decoder, - T: Clone + Send + Sync, + T: Clone + Send + Sync + 'static, { let UseCookieOptions { max_age, @@ -363,31 +363,38 @@ where #[cfg(feature = "ssr")] { if !readonly { - 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() + Effect::new_isomorphic({ + let cookie_name = cookie_name.to_owned(); + + move |_| { + let domain = domain.clone(); + let path = path.clone(); + + 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, - jar, - max_age, - expires, - domain, - path, - same_site, - secure, - http_only, - ssr_set_cookie, - ) - }); + .flatten(); + jar.update_value(|jar| { + write_server_cookie( + &cookie_name, + value, + jar, + max_age, + expires, + domain, + path, + same_site, + secure, + http_only, + Arc::clone(&ssr_set_cookie), + ) + }); + } }); } } diff --git a/src/use_cycle_list.rs b/src/use_cycle_list.rs index 2a38b3b..5c1d3ce 100644 --- a/src/use_cycle_list.rs +++ b/src/use_cycle_list.rs @@ -173,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. @@ -191,7 +191,7 @@ where impl Default for UseCycleListOptions where - T: Clone + PartialEq + 'static, + T: Clone + PartialEq + Send + Sync + 'static, { fn default() -> Self { Self { @@ -205,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 f02ee54..051a10d 100644 --- a/src/use_device_orientation.rs +++ b/src/use_device_orientation.rs @@ -68,8 +68,10 @@ pub fn use_device_orientation() -> UseDeviceOrientationReturn { .once(false), ); - let cleanup = SendWrapper::new(cleanup); - on_cleanup(move || 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 43f4893..e0d0d72 100644 --- a/src/use_draggable.rs +++ b/src/use_draggable.rs @@ -5,7 +5,6 @@ use leptos::ev::{pointerdown, pointermove, pointerup}; use leptos::prelude::diagnostics::SpecialNonReactiveZone; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; -use send_wrapper::SendWrapper; use std::marker::PhantomData; use std::sync::Arc; use wasm_bindgen::JsCast; @@ -93,12 +92,11 @@ where let target = target.into(); let dragging_handle = if let Some(handle) = handle { - // let handle = Signal::derive(|| SendWrapper::new(handle)); let handle: ElementMaybeSignal<_, _> = handle.into(); - Signal::derive(move || handle.get().map(|handle| SendWrapper::new(handle.into()))) + Signal::derive_local(move || handle.get().map(|handle| handle.into())) } else { let target = target.clone(); - Signal::derive(move || target.get().map(|target| SendWrapper::new(target.into()))) + Signal::derive_local(move || target.get().map(|target| target.into())) }; let (position, set_position) = initial_value.into_signal(); diff --git a/src/use_drop_zone.rs b/src/use_drop_zone.rs index e88b345..d64a907 100644 --- a/src/use_drop_zone.rs +++ b/src/use_drop_zone.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 std::fmt::{Debug, Formatter}; use std::sync::Arc; @@ -74,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"))] { @@ -95,7 +94,7 @@ where .map(|f| js_sys::Array::from(&f).to_vec()) .unwrap_or_default() .into_iter() - .map(|f| SendWrapper::new(web_sys::File::from(f))) + .map(web_sys::File::from) .collect(); set_files.update(move |f| *f = files); @@ -113,11 +112,7 @@ where let _z = SpecialNonReactiveZone::enter(); on_enter(UseDropZoneEvent { - files: files - .get_untracked() - .into_iter() - .map(SendWrapper::take) - .collect(), + files: files.get_untracked().into_iter().collect(), event, }); }); @@ -130,11 +125,7 @@ where let _z = SpecialNonReactiveZone::enter(); on_over(UseDropZoneEvent { - files: files - .get_untracked() - .into_iter() - .map(SendWrapper::take) - .collect(), + files: files.get_untracked().into_iter().collect(), event, }); }); @@ -152,11 +143,7 @@ where let _z = SpecialNonReactiveZone::enter(); on_leave(UseDropZoneEvent { - files: files - .get_untracked() - .into_iter() - .map(SendWrapper::take) - .collect(), + files: files.get_untracked().into_iter().collect(), event, }); }); @@ -172,11 +159,7 @@ where let _z = SpecialNonReactiveZone::enter(); on_drop(UseDropZoneEvent { - files: files - .get_untracked() - .into_iter() - .map(SendWrapper::take) - .collect(), + files: files.get_untracked().into_iter().collect(), event, }); }); @@ -231,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 9909c4f..2dc5f0f 100644 --- a/src/use_event_source.rs +++ b/src/use_event_source.rs @@ -4,7 +4,6 @@ use codee::Decoder; use default_struct_builder::DefaultBuilder; use leptos::prelude::diagnostics::SpecialNonReactiveZone; use leptos::prelude::*; -use send_wrapper::SendWrapper; use std::marker::PhantomData; use std::sync::atomic::{AtomicBool, AtomicU32}; use std::sync::Arc; @@ -148,11 +147,11 @@ 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(AtomicBool::new(false)); let retried = Arc::new(AtomicU32::new(0)); @@ -200,7 +199,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); @@ -217,7 +216,7 @@ 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) @@ -262,7 +261,7 @@ where es.clone(), leptos::ev::Custom::::new(event_name), move |e| { - set_event.set(Some(SendWrapper::new(e.clone()))); + set_event.set(Some(e.clone())); let data_string = js!(e["data"]).ok().and_then(|d| d.as_string()); set_data_from_string(data_string); }, @@ -373,10 +372,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. @@ -386,13 +385,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 4059c64..e55642f 100644 --- a/src/use_infinite_scroll.rs +++ b/src/use_infinite_scroll.rs @@ -9,7 +9,6 @@ use gloo_timers::future::sleep; use leptos::prelude::diagnostics::SpecialNonReactiveZone; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; -use send_wrapper::SendWrapper; use std::future::Future; use std::sync::Arc; use std::time::Duration; @@ -111,20 +110,18 @@ 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| { let el = el.into(); if el.is_instance_of::() || el.is_instance_of::() { - SendWrapper::new( - document() - .document_element() - .expect("document element not found"), - ) + document() + .document_element() + .expect("document element not found") } else { - SendWrapper::new(el) + el } }) }); diff --git a/src/use_intersection_observer.rs b/src/use_intersection_observer.rs index 5f24990..7acc128 100644 --- a/src/use_intersection_observer.rs +++ b/src/use_intersection_observer.rs @@ -175,7 +175,7 @@ where .expect("failed to create IntersectionObserver"); for target in targets.iter().flatten() { - let target: web_sys::Element = target.clone().take().into(); + let target: web_sys::Element = target.clone().into(); obs.observe(&target); } diff --git a/src/use_interval_fn.rs b/src/use_interval_fn.rs index 4fab709..e21fed4 100644 --- a/src/use_interval_fn.rs +++ b/src/use_interval_fn.rs @@ -141,8 +141,10 @@ where on_cleanup(stop_watch); } - let pause_cleanup = SendWrapper::new(pause.clone()); - on_cleanup(move || pause_cleanup()); + 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 ca95fd0..1c1bb63 100644 --- a/src/use_intl_number_format.rs +++ b/src/use_intl_number_format.rs @@ -6,7 +6,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 std::fmt::Display; use wasm_bindgen::{JsCast, JsValue}; @@ -168,7 +167,7 @@ pub fn use_intl_number_format(options: UseIntlNumberFormatOptions) -> UseIntlNum ); UseIntlNumberFormatReturn { - js_intl_number_format: SendWrapper::new(number_format), + js_intl_number_format: number_format, } }} } @@ -769,14 +768,14 @@ cfg_if! { if #[cfg(feature = "ssr")] { /// Return type of [`use_intl_number_format`]. pub struct UseIntlNumberFormatReturn { /// The instance of [`Intl.NumberFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat). - pub js_intl_number_format: SendWrapper, + pub js_intl_number_format: js_sys::Intl::NumberFormat, } }} 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 + Send + Sync + 'static, js_sys::Number: From, @@ -784,13 +783,13 @@ impl UseIntlNumberFormatReturn { 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()) @@ -853,7 +852,7 @@ impl UseIntlNumberFormatReturn { &self, start: impl Into>, end: impl Into>, - ) -> Signal + ) -> Signal where NStart: Clone + Display + Send + Sync + 'static, NEnd: Clone + Display + Send + Sync + 'static, @@ -864,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_mutation_observer.rs b/src/use_mutation_observer.rs index ceabaa4..8f223c4 100644 --- a/src/use_mutation_observer.rs +++ b/src/use_mutation_observer.rs @@ -136,7 +136,7 @@ where .expect("failed to create MutationObserver"); for target in targets.iter().flatten() { - let target: web_sys::Element = target.clone().take().into(); + let target: web_sys::Element = target.clone().into(); let _ = obs.observe_with_options(&target, &options.clone().into()); } diff --git a/src/use_raf_fn.rs b/src/use_raf_fn.rs index 45fce03..728f8f5 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 c6d96e1..86c1a15 100644 --- a/src/use_resize_observer.rs +++ b/src/use_resize_observer.rs @@ -138,7 +138,7 @@ where .expect("failed to create ResizeObserver"); for target in targets.iter().flatten() { - let target: web_sys::Element = target.clone().take().into(); + let target: web_sys::Element = target.clone().into(); obs.observe_with_options(&target, &options.clone().into()); } observer.replace(Some(obs)); diff --git a/src/use_scroll.rs b/src/use_scroll.rs index b00dec2..a1f28c6 100644 --- a/src/use_scroll.rs +++ b/src/use_scroll.rs @@ -221,8 +221,6 @@ where let set_y = |_| {}; let measure = || {}; } else { - use send_wrapper::SendWrapper; - let signal = element.into(); let behavior = options.behavior; @@ -372,9 +370,9 @@ where let target = { let signal = signal.clone(); - Signal::derive(move || { + Signal::derive_local(move || { let element = signal.get(); - element.map(|element| SendWrapper::new(element.into().unchecked_into::())) + element.map(|element| element.into().unchecked_into::()) }) }; @@ -394,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, _, >( @@ -414,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 76958b1..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 { @@ -268,7 +268,7 @@ 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() { @@ -287,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 e837b4a..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 + Send + Sync, + I: DerefMut + Clone + PartialEq + Send + Sync + 'static, { let iterable = iterable.into(); @@ -93,7 +93,7 @@ where pub fn use_sorted_by(iterable: S, cmp_fn: F) -> Signal where S: Into>, - I: DerefMut + Clone + PartialEq + Send + Sync, + I: DerefMut + Clone + PartialEq + Send + Sync + 'static, F: FnMut(&T, &T) -> Ordering + Clone + Send + Sync + 'static, { let iterable = iterable.into(); @@ -109,7 +109,7 @@ where pub fn use_sorted_by_key(iterable: S, key_fn: F) -> Signal where S: Into>, - I: DerefMut + Clone + PartialEq + Send + Sync, + I: DerefMut + Clone + PartialEq + Send + Sync + 'static, K: Ord, F: FnMut(&T) -> K + Clone + Send + Sync + 'static, { diff --git a/src/use_user_media.rs b/src/use_user_media.rs index aba11dc..83ec073 100644 --- a/src/use_user_media.rs +++ b/src/use_user_media.rs @@ -2,7 +2,6 @@ use crate::core::MaybeRwSignal; use cfg_if::cfg_if; use default_struct_builder::DefaultBuilder; use leptos::prelude::*; -use send_wrapper::SendWrapper; use wasm_bindgen::{JsCast, JsValue}; /// Reactive [`mediaDevices.getUserMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia) streaming. @@ -60,8 +59,7 @@ pub fn use_user_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"))] { @@ -69,10 +67,7 @@ pub fn use_user_media_with_options( return; } - let stream = create_media(video, audio) - .await - .map(SendWrapper::new) - .map_err(SendWrapper::new); + let stream = create_media(video, audio).await; set_stream.update(|s| *s = Some(stream)); } else { @@ -192,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, 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_web_notification.rs b/src/use_web_notification.rs index afad4df..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()); @@ -149,7 +148,7 @@ pub fn use_web_notification_with_options( notification_value.set_onerror(Some(on_error_closure.unchecked_ref())); notification_value.set_onshow(Some(on_show_closure.unchecked_ref())); - set_notification.set(Some(SendWrapper::new(notification_value))); + set_notification.set(Some(notification_value)); }); } }; @@ -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 776706d..28d83b8 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; @@ -284,7 +283,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,7 @@ where && !reconnect_limit.is_exceeded_by(reconnect_times_ref.get_value()) && ws_ref .get_value() - .map_or(false, |ws: SendWrapper| { - ws.ready_state() != WebSocket::OPEN - }) + .map_or(false, |ws: WebSocket| ws.ready_state() != WebSocket::OPEN) { reconnect_timer_ref.set_value( set_timeout_with_handle( @@ -525,7 +522,7 @@ where onclose_closure.forget(); } - ws_ref.set_value(Some(SendWrapper::new(web_socket))); + ws_ref.set_value(Some(web_socket)); })) }); } @@ -721,7 +718,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 From bbe4e66648edc684057bc7a9b06b5bf21690af27 Mon Sep 17 00:00:00 2001 From: CorvusPrudens Date: Sat, 3 Aug 2024 23:44:56 -0600 Subject: [PATCH 5/6] Added newer spawn paths --- src/lib.rs | 1 - src/use_clipboard.rs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f747ea3..8d765e9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,7 +75,6 @@ mod use_throttle_fn; mod use_timeout_fn; mod use_timestamp; mod use_to_string; -mod use_user_media; mod use_web_notification; mod use_websocket; mod use_window; 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)); From 204c5e10b6f212d24b84078fa5ab3ade305259a2 Mon Sep 17 00:00:00 2001 From: CorvusPrudens Date: Sat, 3 Aug 2024 23:49:16 -0600 Subject: [PATCH 6/6] Fixed up import order --- src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8d765e9..6e85934 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,7 +28,6 @@ mod on_click_outside; mod signal_debounced; mod signal_throttled; mod sync_signal; -mod use_user_media; // mod use_active_element; mod use_breakpoints; mod use_broadcast_channel; @@ -75,6 +74,7 @@ mod use_throttle_fn; mod use_timeout_fn; mod use_timestamp; mod use_to_string; +mod use_user_media; mod use_web_notification; mod use_websocket; mod use_window; @@ -94,7 +94,6 @@ pub use on_click_outside::*; pub use signal_debounced::*; pub use signal_throttled::*; pub use sync_signal::*; -pub use use_user_media::*; // pub use use_active_element::*; pub use use_breakpoints::*; pub use use_broadcast_channel::*; @@ -141,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::*;