Added more Send + Sync bounds and SendWrappers

This commit is contained in:
CorvusPrudens 2024-07-23 11:36:12 -06:00
parent 3433fc6608
commit 9866ac6231
14 changed files with 202 additions and 131 deletions

View file

@ -4,8 +4,10 @@ use cfg_if::cfg_if;
use leptos::html::{ElementType, HtmlElement}; use leptos::html::{ElementType, HtmlElement};
use leptos::prelude::wrappers::read::Signal; use leptos::prelude::wrappers::read::Signal;
use leptos::prelude::*; use leptos::prelude::*;
use send_wrapper::SendWrapper;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ops::Deref; use std::ops::Deref;
use wasm_bindgen::JsCast;
/// Used as an argument type to make it easily possible to pass either /// 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`), /// * a `web_sys` element that implements `E` (for example `EventTarget` or `Element`),
@ -58,9 +60,9 @@ impl<T, E> With for ElementsMaybeSignal<T, E>
where where
T: Into<E> + Clone + 'static, T: Into<E> + Clone + 'static,
{ {
type Value = Vec<Option<T>>; type Value = Vec<Option<SendWrapper<T>>>;
fn with<O>(&self, f: impl FnOnce(&Vec<Option<T>>) -> O) -> O { fn with<O>(&self, f: impl FnOnce(&Vec<Option<SendWrapper<T>>>) -> O) -> O {
match self { match self {
Self::Static(v) => f(v), Self::Static(v) => f(v),
Self::Dynamic(s) => s.with(f), Self::Dynamic(s) => s.with(f),
@ -68,7 +70,7 @@ where
} }
} }
fn try_with<O>(&self, f: impl FnOnce(&Vec<Option<T>>) -> O) -> Option<O> { fn try_with<O>(&self, f: impl FnOnce(&Vec<Option<SendWrapper<T>>>) -> O) -> Option<O> {
match self { match self {
Self::Static(v) => Some(f(v)), Self::Static(v) => Some(f(v)),
Self::Dynamic(s) => s.try_with(f), Self::Dynamic(s) => s.try_with(f),
@ -81,9 +83,9 @@ impl<T, E> WithUntracked for ElementsMaybeSignal<T, E>
where where
T: Into<E> + Clone + 'static, T: Into<E> + Clone + 'static,
{ {
type Value = Vec<Option<T>>; type Value = Vec<Option<SendWrapper<T>>>;
fn with_untracked<O>(&self, f: impl FnOnce(&Vec<Option<T>>) -> O) -> O { fn with_untracked<O>(&self, f: impl FnOnce(&Vec<Option<SendWrapper<T>>>) -> O) -> O {
match self { match self {
Self::Static(t) => f(t), Self::Static(t) => f(t),
Self::Dynamic(s) => s.with_untracked(f), Self::Dynamic(s) => s.with_untracked(f),
@ -91,7 +93,10 @@ where
} }
} }
fn try_with_untracked<O>(&self, f: impl FnOnce(&Vec<Option<T>>) -> O) -> Option<O> { fn try_with_untracked<O>(
&self,
f: impl FnOnce(&Vec<Option<SendWrapper<T>>>) -> O,
) -> Option<O> {
match self { match self {
Self::Static(t) => Some(f(t)), Self::Static(t) => Some(f(t)),
Self::Dynamic(s) => s.try_with_untracked(f), Self::Dynamic(s) => s.try_with_untracked(f),
@ -107,7 +112,7 @@ where
T: Into<E> + Clone + 'static, T: Into<E> + Clone + 'static,
{ {
fn from(value: T) -> Self { fn from(value: T) -> Self {
ElementsMaybeSignal::Static(vec![Some(value)]) ElementsMaybeSignal::Static(vec![Some(SendWrapper::new(value))])
} }
} }
@ -116,7 +121,7 @@ where
T: Into<E> + Clone + 'static, T: Into<E> + Clone + 'static,
{ {
fn from(target: Option<T>) -> Self { fn from(target: Option<T>) -> 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, E: From<$ty2> + 'static,
{ {
fn from(value: $ty) -> Self { 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); let mut list = Vec::with_capacity(node_list.length() as usize);
for i in 0..node_list.length() { for i in 0..node_list.length() {
let node = node_list.get(i).expect("checked the range"); let node = node_list.get(i).expect("checked the range");
list.push(Some(node)); list.push(Some(SendWrapper::new(node)));
} }
list list
} else { } else {
@ -209,8 +214,8 @@ impl_from_signal_string!(Memo<String>);
impl_from_signal_string!(Signal<&str>); impl_from_signal_string!(Signal<&str>);
impl_from_signal_string!(ReadSignal<&str>); impl_from_signal_string!(ReadSignal<&str>);
impl_from_signal_string!(RwSignal<&str>); impl_from_signal_string!(RwSignal<&'static str>);
impl_from_signal_string!(Memo<&str>); impl_from_signal_string!(Memo<&'static str>);
// From single signal /////////////////////////////////////////////////////////////// // From single signal ///////////////////////////////////////////////////////////////
@ -227,10 +232,10 @@ macro_rules! impl_from_signal_option {
}; };
} }
impl_from_signal_option!(Signal<Option<T>>); impl_from_signal_option!(Signal<Option<SendWrapper<T>>>);
impl_from_signal_option!(ReadSignal<Option<T>>); impl_from_signal_option!(ReadSignal<Option<SendWrapper<T>>>);
impl_from_signal_option!(RwSignal<Option<T>>); impl_from_signal_option!(RwSignal<Option<SendWrapper<T>>>);
impl_from_signal_option!(Memo<Option<T>>); impl_from_signal_option!(Memo<Option<SendWrapper<T>>>);
macro_rules! impl_from_signal { macro_rules! impl_from_signal {
($ty:ty) => { ($ty:ty) => {
@ -245,10 +250,10 @@ macro_rules! impl_from_signal {
}; };
} }
impl_from_signal!(Signal<T>); impl_from_signal!(Signal<SendWrapper<T>>);
impl_from_signal!(ReadSignal<T>); impl_from_signal!(ReadSignal<SendWrapper<T>>);
impl_from_signal!(RwSignal<T>); impl_from_signal!(RwSignal<SendWrapper<T>>);
impl_from_signal!(Memo<T>); impl_from_signal!(Memo<SendWrapper<T>>);
// From single NodeRef ////////////////////////////////////////////////////////////// // From single NodeRef //////////////////////////////////////////////////////////////
@ -257,13 +262,13 @@ macro_rules! impl_from_node_ref {
impl<R> From<NodeRef<R>> for ElementsMaybeSignal<$ty, $ty> impl<R> From<NodeRef<R>> for ElementsMaybeSignal<$ty, $ty>
where where
R: ElementType + Clone + 'static, R: ElementType + Clone + 'static,
R::Output: JsCast + Into<$ty> + Clone + 'static,
{ {
fn from(node_ref: NodeRef<R>) -> Self { fn from(node_ref: NodeRef<R>) -> Self {
Self::Dynamic(Signal::derive(move || { Self::Dynamic(Signal::derive(move || {
vec![node_ref.get().map(move |el| { vec![node_ref.get().map(move |el| {
let el = el.into_any(); let el: $ty = el.clone().into();
let el: $ty = el.deref().clone().into(); SendWrapper::new(el)
el
})] })]
})) }))
} }
@ -276,23 +281,23 @@ impl_from_node_ref!(web_sys::Element);
// From single leptos::html::HTMLElement /////////////////////////////////////////// // From single leptos::html::HTMLElement ///////////////////////////////////////////
macro_rules! impl_from_html_element { // macro_rules! impl_from_html_element {
($ty:ty) => { // ($ty:ty) => {
impl<E, At, Ch, Rndr> From<HtmlElement<E, At, Ch, Rndr>> for ElementsMaybeSignal<$ty, $ty> // impl<E, At, Ch, Rndr> From<HtmlElement<E, At, Ch, Rndr>> for ElementsMaybeSignal<$ty, $ty>
where // where
E: ElementType, // E: ElementType,
E::Output: std::ops::Deref<Target = $ty>, // E::Output: std::ops::Deref<Target = $ty>,
{ // {
fn from(value: HtmlElement<E, At, Ch, Rndr>) -> Self { // fn from(value: HtmlElement<E, At, Ch, Rndr>) -> Self {
let el: &$ty = value.deref(); // let el: &$ty = value.deref();
Self::Static(vec![Some(el.clone())]) // Self::Static(vec![Some(el.clone())])
} // }
} // }
}; // };
} // }
//
impl_from_html_element!(web_sys::EventTarget); // impl_from_html_element!(web_sys::EventTarget);
impl_from_html_element!(web_sys::Element); // impl_from_html_element!(web_sys::Element);
// From multiple static elements ////////////////////////////////////////////////////// // From multiple static elements //////////////////////////////////////////////////////
@ -301,7 +306,12 @@ where
T: Into<E> + Clone + 'static, T: Into<E> + Clone + 'static,
{ {
fn from(target: &[T]) -> Self { 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<E> + Clone + 'static, T: Into<E> + Clone + 'static,
{ {
fn from(target: &[Option<T>]) -> Self { fn from(target: &[Option<T>]) -> 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<E> + Clone + 'static, T: Into<E> + Clone + 'static,
{ {
fn from(target: Vec<T>) -> Self { fn from(target: Vec<T>) -> 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<E> + Clone + 'static, T: Into<E> + Clone + 'static,
{ {
fn from(target: Vec<Option<T>>) -> Self { fn from(target: Vec<Option<T>>) -> 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<E> + Clone + 'static, T: Into<E> + Clone + 'static,
{ {
fn from(target: [T; C]) -> Self { 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<E> + Clone + 'static, T: Into<E> + Clone + 'static,
{ {
fn from(target: [Option<T>; C]) -> Self { fn from(target: [Option<T>; 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( Self::Static(
$target $target
.iter() .iter()
.filter_map(|sel: &$str_ty| -> Option<Vec<Option<$el_ty>>> { .filter_map(|sel: &$str_ty| -> Option<Vec<Option<SendWrapper<$el_ty>>>> {
cfg_if! { if #[cfg(feature = "ssr")] { cfg_if! { if #[cfg(feature = "ssr")] {
let _ = sel; let _ = sel;
None None
@ -368,7 +403,7 @@ macro_rules! impl_from_strings_inner {
let mut list = Vec::with_capacity(node_list.length() as usize); let mut list = Vec::with_capacity(node_list.length() as usize);
for i in 0..node_list.length() { for i in 0..node_list.length() {
let node: $el_ty = node_list.get(i).expect("checked the range").unchecked_into(); 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) Some(list)
@ -417,33 +452,33 @@ impl_from_strings!(web_sys::EventTarget, String);
// From signal of vec //////////////////////////////////////////////////////////////// // From signal of vec ////////////////////////////////////////////////////////////////
impl<T, E> From<Signal<Vec<T>>> for ElementsMaybeSignal<T, E> impl<T, E> From<Signal<Vec<SendWrapper<T>>>> for ElementsMaybeSignal<T, E>
where where
T: Into<E> + Clone + 'static, T: Into<E> + Clone + 'static,
{ {
fn from(signal: Signal<Vec<T>>) -> Self { fn from(signal: Signal<Vec<SendWrapper<T>>>) -> Self {
Self::Dynamic(Signal::derive(move || { Self::Dynamic(Signal::derive(move || {
signal.get().into_iter().map(|t| Some(t)).collect() signal.get().into_iter().map(|t| Some(t)).collect()
})) }))
} }
} }
impl<T, E> From<Signal<Vec<Option<T>>>> for ElementsMaybeSignal<T, E> impl<T, E> From<Signal<Vec<Option<SendWrapper<T>>>>> for ElementsMaybeSignal<T, E>
where where
T: Into<E> + Clone + 'static, T: Into<E> + Clone + 'static,
{ {
fn from(target: Signal<Vec<Option<T>>>) -> Self { fn from(target: Signal<Vec<Option<SendWrapper<T>>>>) -> Self {
Self::Dynamic(target) Self::Dynamic(target)
} }
} }
// From multiple signals ////////////////////////////////////////////////////////////// // From multiple signals //////////////////////////////////////////////////////////////
impl<T, E> From<&[Signal<T>]> for ElementsMaybeSignal<T, E> impl<T, E> From<&[Signal<SendWrapper<T>>]> for ElementsMaybeSignal<T, E>
where where
T: Into<E> + Clone + 'static, T: Into<E> + Clone + 'static,
{ {
fn from(list: &[Signal<T>]) -> Self { fn from(list: &[Signal<SendWrapper<T>>]) -> Self {
let list = list.to_vec(); let list = list.to_vec();
Self::Dynamic(Signal::derive(move || { Self::Dynamic(Signal::derive(move || {
@ -452,11 +487,11 @@ where
} }
} }
impl<T, E> From<&[Signal<Option<T>>]> for ElementsMaybeSignal<T, E> impl<T, E> From<&[Signal<Option<SendWrapper<T>>>]> for ElementsMaybeSignal<T, E>
where where
T: Into<E> + Clone + 'static, T: Into<E> + Clone + 'static,
{ {
fn from(list: &[Signal<Option<T>>]) -> Self { fn from(list: &[Signal<Option<SendWrapper<T>>>]) -> Self {
let list = list.to_vec(); let list = list.to_vec();
Self::Dynamic(Signal::derive(move || { Self::Dynamic(Signal::derive(move || {
@ -465,11 +500,11 @@ where
} }
} }
impl<T, E> From<Vec<Signal<T>>> for ElementsMaybeSignal<T, E> impl<T, E> From<Vec<Signal<SendWrapper<T>>>> for ElementsMaybeSignal<T, E>
where where
T: Into<E> + Clone + 'static, T: Into<E> + Clone + 'static,
{ {
fn from(list: Vec<Signal<T>>) -> Self { fn from(list: Vec<Signal<SendWrapper<T>>>) -> Self {
let list = list.clone(); let list = list.clone();
Self::Dynamic(Signal::derive(move || { Self::Dynamic(Signal::derive(move || {
@ -478,11 +513,11 @@ where
} }
} }
impl<T, E> From<Vec<Signal<Option<T>>>> for ElementsMaybeSignal<T, E> impl<T, E> From<Vec<Signal<Option<SendWrapper<T>>>>> for ElementsMaybeSignal<T, E>
where where
T: Into<E> + Clone + 'static, T: Into<E> + Clone + 'static,
{ {
fn from(list: Vec<Signal<Option<T>>>) -> Self { fn from(list: Vec<Signal<Option<SendWrapper<T>>>>) -> Self {
let list = list.clone(); let list = list.clone();
Self::Dynamic(Signal::derive(move || { Self::Dynamic(Signal::derive(move || {
@ -491,11 +526,11 @@ where
} }
} }
impl<T, E, const C: usize> From<[Signal<T>; C]> for ElementsMaybeSignal<T, E> impl<T, E, const C: usize> From<[Signal<SendWrapper<T>>; C]> for ElementsMaybeSignal<T, E>
where where
T: Into<E> + Clone + 'static, T: Into<E> + Clone + 'static,
{ {
fn from(list: [Signal<T>; C]) -> Self { fn from(list: [Signal<SendWrapper<T>>; C]) -> Self {
let list = list.to_vec(); let list = list.to_vec();
Self::Dynamic(Signal::derive(move || { Self::Dynamic(Signal::derive(move || {
@ -504,11 +539,11 @@ where
} }
} }
impl<T, E, const C: usize> From<[Signal<Option<T>>; C]> for ElementsMaybeSignal<T, E> impl<T, E, const C: usize> From<[Signal<Option<SendWrapper<T>>>; C]> for ElementsMaybeSignal<T, E>
where where
T: Into<E> + Clone + 'static, T: Into<E> + Clone + 'static,
{ {
fn from(list: [Signal<Option<T>>; C]) -> Self { fn from(list: [Signal<Option<SendWrapper<T>>>; C]) -> Self {
let list = list.to_vec(); let list = list.to_vec();
Self::Dynamic(Signal::derive(move || { Self::Dynamic(Signal::derive(move || {
@ -526,9 +561,8 @@ macro_rules! impl_from_multi_node_ref_inner {
.iter() .iter()
.map(|node_ref| { .map(|node_ref| {
node_ref.get().map(move |el| { node_ref.get().map(move |el| {
let el = el.into_any(); let el: $ty = el.clone().into();
let el: $ty = el.deref().clone().into(); SendWrapper::new(el)
el
}) })
}) })
.collect() .collect()
@ -541,6 +575,7 @@ macro_rules! impl_from_multi_node_ref {
impl<R> From<&[NodeRef<R>]> for ElementsMaybeSignal<$ty, $ty> impl<R> From<&[NodeRef<R>]> for ElementsMaybeSignal<$ty, $ty>
where where
R: ElementType + Clone + 'static, R: ElementType + Clone + 'static,
R::Output: JsCast + Into<$ty> + Clone + 'static,
{ {
fn from(node_refs: &[NodeRef<R>]) -> Self { fn from(node_refs: &[NodeRef<R>]) -> Self {
let node_refs = node_refs.to_vec(); let node_refs = node_refs.to_vec();
@ -551,6 +586,7 @@ macro_rules! impl_from_multi_node_ref {
impl<R, const C: usize> From<[NodeRef<R>; C]> for ElementsMaybeSignal<$ty, $ty> impl<R, const C: usize> From<[NodeRef<R>; C]> for ElementsMaybeSignal<$ty, $ty>
where where
R: ElementType + Clone + 'static, R: ElementType + Clone + 'static,
R::Output: JsCast + Into<$ty> + Clone + 'static,
{ {
fn from(node_refs: [NodeRef<R>; C]) -> Self { fn from(node_refs: [NodeRef<R>; C]) -> Self {
let node_refs = node_refs.to_vec(); let node_refs = node_refs.to_vec();
@ -561,6 +597,7 @@ macro_rules! impl_from_multi_node_ref {
impl<R> From<Vec<NodeRef<R>>> for ElementsMaybeSignal<$ty, $ty> impl<R> From<Vec<NodeRef<R>>> for ElementsMaybeSignal<$ty, $ty>
where where
R: ElementType + Clone + 'static, R: ElementType + Clone + 'static,
R::Output: JsCast + Into<$ty> + Clone + 'static,
{ {
fn from(node_refs: Vec<NodeRef<R>>) -> Self { fn from(node_refs: Vec<NodeRef<R>>) -> Self {
let node_refs = node_refs.clone(); let node_refs = node_refs.clone();

View file

@ -50,26 +50,38 @@ impl<T> From<Signal<T>> for MaybeRwSignal<T> {
} }
} }
impl<T> From<ReadSignal<T>> for MaybeRwSignal<T> { impl<T> From<ReadSignal<T>> for MaybeRwSignal<T>
where
T: Send + Sync,
{
fn from(s: ReadSignal<T>) -> Self { fn from(s: ReadSignal<T>) -> Self {
Self::DynamicRead(s.into()) Self::DynamicRead(s.into())
} }
} }
impl<T> From<Memo<T>> for MaybeRwSignal<T> { impl<T> From<Memo<T>> for MaybeRwSignal<T>
where
T: Send + Sync,
{
fn from(s: Memo<T>) -> Self { fn from(s: Memo<T>) -> Self {
Self::DynamicRead(s.into()) Self::DynamicRead(s.into())
} }
} }
impl<T> From<RwSignal<T>> for MaybeRwSignal<T> { impl<T> From<RwSignal<T>> for MaybeRwSignal<T>
where
T: Send + Sync,
{
fn from(s: RwSignal<T>) -> Self { fn from(s: RwSignal<T>) -> Self {
let (r, w) = s.split(); let (r, w) = s.split();
Self::DynamicRw(r.into(), w) Self::DynamicRw(r.into(), w)
} }
} }
impl<T> From<(ReadSignal<T>, WriteSignal<T>)> for MaybeRwSignal<T> { impl<T> From<(ReadSignal<T>, WriteSignal<T>)> for MaybeRwSignal<T>
where
T: Send + Sync,
{
fn from(s: (ReadSignal<T>, WriteSignal<T>)) -> Self { fn from(s: (ReadSignal<T>, WriteSignal<T>)) -> Self {
Self::DynamicRw(s.0.into(), s.1) Self::DynamicRw(s.0.into(), s.1)
} }
@ -87,7 +99,10 @@ impl From<&str> for MaybeRwSignal<String> {
} }
} }
impl<T: Clone> MaybeRwSignal<T> { impl<T: Clone> MaybeRwSignal<T>
where
T: Send + Sync,
{
pub fn into_signal(self) -> (Signal<T>, WriteSignal<T>) { pub fn into_signal(self) -> (Signal<T>, WriteSignal<T>) {
match self { match self {
Self::DynamicRead(s) => { Self::DynamicRead(s) => {

View file

@ -22,7 +22,7 @@ where
impl<T> Default for UseRwSignal<T> impl<T> Default for UseRwSignal<T>
where where
T: Default, T: Default + Send + Sync,
{ {
fn default() -> Self { fn default() -> Self {
Self::Combined(Default::default()) Self::Combined(Default::default())
@ -47,7 +47,10 @@ impl<T> DefinedAt for UseRwSignal<T> {
} }
} }
impl<T> With for UseRwSignal<T> { impl<T> With for UseRwSignal<T>
where
T: Send + Sync,
{
type Value = T; type Value = T;
fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R { fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
@ -65,7 +68,10 @@ impl<T> With for UseRwSignal<T> {
} }
} }
impl<T> WithUntracked for UseRwSignal<T> { impl<T> WithUntracked for UseRwSignal<T>
where
T: Send + Sync,
{
type Value = T; type Value = T;
fn with_untracked<R>(&self, f: impl FnOnce(&T) -> R) -> R { fn with_untracked<R>(&self, f: impl FnOnce(&T) -> R) -> R {

View file

@ -25,11 +25,11 @@ mod is_none;
mod is_ok; mod is_ok;
mod is_some; mod is_some;
mod on_click_outside; mod on_click_outside;
mod use_user_media;
mod signal_debounced; mod signal_debounced;
mod signal_throttled; mod signal_throttled;
mod sync_signal; mod sync_signal;
mod use_active_element; mod use_user_media;
// mod use_active_element;
mod use_breakpoints; mod use_breakpoints;
mod use_broadcast_channel; mod use_broadcast_channel;
mod use_color_mode; mod use_color_mode;
@ -91,11 +91,11 @@ pub use is_none::*;
pub use is_ok::*; pub use is_ok::*;
pub use is_some::*; pub use is_some::*;
pub use on_click_outside::*; pub use on_click_outside::*;
pub use use_user_media::*;
pub use signal_debounced::*; pub use signal_debounced::*;
pub use signal_throttled::*; pub use signal_throttled::*;
pub use sync_signal::*; 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_breakpoints::*;
pub use use_broadcast_channel::*; pub use use_broadcast_channel::*;
pub use use_color_mode::*; pub use use_color_mode::*;

View file

@ -7,9 +7,9 @@ macro_rules! use_partial_cmp {
pub fn $fn_name<C, S, N>(container: S) -> Signal<Option<N>> pub fn $fn_name<C, S, N>(container: S) -> Signal<Option<N>>
where where
S: Into<MaybeSignal<C>>, S: Into<MaybeSignal<C>>,
C: 'static, C: Send + Sync + 'static,
for<'a> &'a C: IntoIterator<Item = &'a N>, for<'a> &'a C: IntoIterator<Item = &'a N>,
N: PartialOrd + Clone, N: PartialOrd + Clone + Send + Sync,
{ {
let container = container.into(); let container = container.into();
@ -47,8 +47,8 @@ macro_rules! use_simple_math {
$(#[$outer])* $(#[$outer])*
pub fn [<use_ $fn_name>]<S, N>(x: S) -> Signal<N> pub fn [<use_ $fn_name>]<S, N>(x: S) -> Signal<N>
where where
S: Into<MaybeSignal<N>>, S: Into<MaybeSignal<N>> + Send + Sync,
N: Float, N: Float + Send + Sync,
{ {
let x = x.into(); let x = x.into();
Signal::derive(move || x.get().$fn_name()) Signal::derive(move || x.get().$fn_name())

View file

@ -148,7 +148,7 @@ pub fn sync_signal<T>(
right: impl Into<UseRwSignal<T>>, right: impl Into<UseRwSignal<T>>,
) -> impl Fn() + Clone ) -> impl Fn() + Clone
where where
T: Clone + PartialEq + 'static, T: Clone + PartialEq + Send + Sync + 'static,
{ {
sync_signal_with_options(left, right, SyncSignalOptions::default()) sync_signal_with_options(left, right, SyncSignalOptions::default())
} }
@ -160,8 +160,8 @@ pub fn sync_signal_with_options<L, R>(
options: SyncSignalOptions<L, R>, options: SyncSignalOptions<L, R>,
) -> impl Fn() + Clone ) -> impl Fn() + Clone
where where
L: Clone + PartialEq + 'static, L: Clone + PartialEq + Send + Sync + 'static,
R: Clone + PartialEq + 'static, R: Clone + PartialEq + Send + Sync + 'static,
{ {
let SyncSignalOptions { let SyncSignalOptions {
immediate, immediate,

View file

@ -110,7 +110,7 @@ use std::hash::Hash;
/// ///
/// Since internally this uses [`use_media_query`], which returns always `false` on the server, /// Since internally this uses [`use_media_query`], which returns always `false` on the server,
/// the returned methods also will return `false`. /// the returned methods also will return `false`.
pub fn use_breakpoints<K: Eq + Hash + Debug + Clone>( pub fn use_breakpoints<K: Eq + Hash + Debug + Clone + Send + Sync>(
breakpoints: HashMap<K, u32>, breakpoints: HashMap<K, u32>,
) -> UseBreakpointsReturn<K> { ) -> UseBreakpointsReturn<K> {
UseBreakpointsReturn { breakpoints } UseBreakpointsReturn { breakpoints }
@ -118,7 +118,7 @@ pub fn use_breakpoints<K: Eq + Hash + Debug + Clone>(
/// Return type of [`use_breakpoints`] /// Return type of [`use_breakpoints`]
#[derive(Clone)] #[derive(Clone)]
pub struct UseBreakpointsReturn<K: Eq + Hash + Debug + Clone> { pub struct UseBreakpointsReturn<K: Eq + Hash + Debug + Clone + Send + Sync> {
breakpoints: HashMap<K, u32>, breakpoints: HashMap<K, u32>,
} }
@ -184,7 +184,7 @@ macro_rules! impl_cmp_reactively {
}; };
} }
impl<K: Eq + Hash + Debug + Clone> UseBreakpointsReturn<K> { impl<K: Eq + Hash + Debug + Clone + Send + Sync> UseBreakpointsReturn<K> {
fn match_(query: &str) -> bool { fn match_(query: &str) -> bool {
if let Ok(Some(query_list)) = use_window().match_media(query) { if let Ok(Some(query_list)) = use_window().match_media(query) {
return query_list.matches(); return query_list.matches();

View file

@ -4,6 +4,7 @@ use crate::{
use codee::{CodecError, Decoder, Encoder}; use codee::{CodecError, Decoder, Encoder};
use leptos::ev::messageerror; use leptos::ev::messageerror;
use leptos::prelude::*; use leptos::prelude::*;
use send_wrapper::SendWrapper;
use thiserror::Error; use thiserror::Error;
use wasm_bindgen::JsValue; use wasm_bindgen::JsValue;
@ -80,12 +81,15 @@ pub fn use_broadcast_channel<T, C>(
<C as Decoder<T>>::Error, <C as Decoder<T>>::Error,
> >
where where
T: Send + Sync,
C: Encoder<T, Encoded = String> + Decoder<T, Encoded = str>, C: Encoder<T, Encoded = String> + Decoder<T, Encoded = str>,
<C as Encoder<T>>::Error: Send + Sync,
<C as Decoder<T>>::Error: Send + Sync,
{ {
let is_supported = use_supported(|| js!("BroadcastChannel" in &window())); let is_supported = use_supported(|| js!("BroadcastChannel" in &window()));
let (is_closed, set_closed) = signal(false); let (is_closed, set_closed) = signal(false);
let (channel, set_channel) = signal(None::<web_sys::BroadcastChannel>); let (channel, set_channel) = signal(None::<SendWrapper<web_sys::BroadcastChannel>>);
let (message, set_message) = signal(None::<T>); let (message, set_message) = signal(None::<T>);
let (error, set_error) = signal( let (error, set_error) = signal(
None::<UseBroadcastChannelError<<C as Encoder<T>>::Error, <C as Decoder<T>>::Error>>, None::<UseBroadcastChannelError<<C as Encoder<T>>::Error, <C as Decoder<T>>::Error>>,
@ -99,7 +103,9 @@ where
channel channel
.post_message(&msg.into()) .post_message(&msg.into())
.map_err(|err| { .map_err(|err| {
set_error.set(Some(UseBroadcastChannelError::PostMessage(err))) set_error.set(Some(UseBroadcastChannelError::PostMessage(
SendWrapper::new(err),
)))
}) })
.ok(); .ok();
} }
@ -124,7 +130,7 @@ where
if is_supported.get_untracked() { if is_supported.get_untracked() {
let channel_val = web_sys::BroadcastChannel::new(name).ok(); 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 { if let Some(channel) = channel_val {
let _ = use_event_listener_with_options( let _ = use_event_listener_with_options(
@ -151,7 +157,9 @@ where
channel.clone(), channel.clone(),
messageerror, messageerror,
move |event| { move |event| {
set_error.set(Some(UseBroadcastChannelError::MessageEvent(event))); set_error.set(Some(UseBroadcastChannelError::MessageEvent(
SendWrapper::new(event),
)));
}, },
UseEventListenerOptions::default().passive(true), UseEventListenerOptions::default().passive(true),
); );
@ -188,7 +196,7 @@ where
pub is_supported: Signal<bool>, pub is_supported: Signal<bool>,
/// The broadcast channel that is wrapped by this function /// The broadcast channel that is wrapped by this function
pub channel: Signal<Option<web_sys::BroadcastChannel>>, pub channel: Signal<Option<SendWrapper<web_sys::BroadcastChannel>>>,
/// Latest message received from the channel /// Latest message received from the channel
pub message: Signal<Option<T>>, pub message: Signal<Option<T>>,
@ -209,9 +217,9 @@ where
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum UseBroadcastChannelError<E, D> { pub enum UseBroadcastChannelError<E, D> {
#[error("failed to post message")] #[error("failed to post message")]
PostMessage(JsValue), PostMessage(SendWrapper<JsValue>),
#[error("channel message error")] #[error("channel message error")]
MessageEvent(web_sys::MessageEvent), MessageEvent(SendWrapper<web_sys::MessageEvent>),
#[error("failed to (de)encode value")] #[error("failed to (de)encode value")]
Codec(CodecError<E, D>), Codec(CodecError<E, D>),
#[error("received value is not a string")] #[error("received value is not a string")]

View file

@ -36,10 +36,10 @@ use leptos::prelude::wrappers::read::Signal;
pub fn use_device_orientation() -> UseDeviceOrientationReturn { pub fn use_device_orientation() -> UseDeviceOrientationReturn {
cfg_if! { if #[cfg(feature = "ssr")] { cfg_if! { if #[cfg(feature = "ssr")] {
let is_supported = Signal::derive(|| false); let is_supported = Signal::derive(|| false);
let absolute = || false; let absolute = Signal::derive(|| false);
let alpha = || None; let alpha = Signal::derive(|| None);
let beta = || None; let beta = Signal::derive(|| None);
let gamma = || None; let gamma = Signal::derive(|| None);
} else { } else {
use leptos::prelude::*; use leptos::prelude::*;
use crate::{use_event_listener_with_options, UseEventListenerOptions, use_supported, js}; use crate::{use_event_listener_with_options, UseEventListenerOptions, use_supported, js};

View file

@ -5,8 +5,9 @@ use leptos::ev::{pointerdown, pointermove, pointerup};
use leptos::prelude::diagnostics::SpecialNonReactiveZone; use leptos::prelude::diagnostics::SpecialNonReactiveZone;
use leptos::prelude::wrappers::read::Signal; use leptos::prelude::wrappers::read::Signal;
use leptos::prelude::*; use leptos::prelude::*;
use send_wrapper::SendWrapper;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::rc::Rc; use std::sync::Arc;
use wasm_bindgen::JsCast; use wasm_bindgen::JsCast;
use web_sys::PointerEvent; use web_sys::PointerEvent;
@ -92,11 +93,12 @@ where
let target = target.into(); let target = target.into();
let dragging_handle = if let Some(handle) = handle { let dragging_handle = if let Some(handle) = handle {
let handle = (handle).into(); // let handle = Signal::derive(|| SendWrapper::new(handle));
Signal::derive(move || handle.get().map(|handle| handle.into())) let handle: ElementMaybeSignal<_, _> = handle.into();
Signal::derive(move || handle.get().map(|handle| SendWrapper::new(handle.into())))
} else { } else {
let target = target.clone(); 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(); let (position, set_position) = initial_value.into_signal();
@ -280,13 +282,13 @@ where
initial_value: MaybeRwSignal<Position>, initial_value: MaybeRwSignal<Position>,
/// Callback when the dragging starts. Return `false` to prevent dragging. /// Callback when the dragging starts. Return `false` to prevent dragging.
on_start: Rc<dyn Fn(UseDraggableCallbackArgs) -> bool>, on_start: Arc<dyn Fn(UseDraggableCallbackArgs) -> bool + Send + Sync>,
/// Callback during dragging. /// Callback during dragging.
on_move: Rc<dyn Fn(UseDraggableCallbackArgs)>, on_move: Arc<dyn Fn(UseDraggableCallbackArgs) + Send + Sync>,
/// Callback when dragging end. /// Callback when dragging end.
on_end: Rc<dyn Fn(UseDraggableCallbackArgs)>, on_end: Arc<dyn Fn(UseDraggableCallbackArgs) + Send + Sync>,
#[builder(skip)] #[builder(skip)]
_marker1: PhantomData<DragT>, _marker1: PhantomData<DragT>,
@ -306,9 +308,9 @@ impl Default
handle: None, handle: None,
pointer_types: vec![PointerType::Mouse, PointerType::Touch, PointerType::Pen], pointer_types: vec![PointerType::Mouse, PointerType::Touch, PointerType::Pen],
initial_value: MaybeRwSignal::default(), initial_value: MaybeRwSignal::default(),
on_start: Rc::new(|_| true), on_start: Arc::new(|_| true),
on_move: Rc::new(|_| {}), on_move: Arc::new(|_| {}),
on_end: Rc::new(|_| {}), on_end: Arc::new(|_| {}),
_marker1: PhantomData, _marker1: PhantomData,
_marker2: PhantomData, _marker2: PhantomData,
} }

View file

@ -3,8 +3,9 @@ use cfg_if::cfg_if;
use default_struct_builder::DefaultBuilder; use default_struct_builder::DefaultBuilder;
use leptos::prelude::wrappers::read::Signal; use leptos::prelude::wrappers::read::Signal;
use leptos::prelude::*; use leptos::prelude::*;
use send_wrapper::SendWrapper;
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use std::rc::Rc; use std::sync::Arc;
cfg_if! { if #[cfg(not(feature = "ssr"))] { cfg_if! { if #[cfg(not(feature = "ssr"))] {
use crate::use_event_listener; use crate::use_event_listener;
@ -73,7 +74,7 @@ where
T: Into<web_sys::EventTarget> + Clone + 'static, T: Into<web_sys::EventTarget> + Clone + 'static,
{ {
let (is_over_drop_zone, set_over_drop_zone) = signal(false); let (is_over_drop_zone, set_over_drop_zone) = signal(false);
let (files, set_files) = signal(Vec::<web_sys::File>::new()); let (files, set_files) = signal(Vec::<SendWrapper<web_sys::File>>::new());
#[cfg(not(feature = "ssr"))] #[cfg(not(feature = "ssr"))]
{ {
@ -176,22 +177,22 @@ where
#[cfg_attr(feature = "ssr", allow(dead_code))] #[cfg_attr(feature = "ssr", allow(dead_code))]
pub struct UseDropZoneOptions { pub struct UseDropZoneOptions {
/// Event handler for the [`drop`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/drop_event) event /// Event handler for the [`drop`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/drop_event) event
on_drop: Rc<dyn Fn(UseDropZoneEvent)>, on_drop: Arc<dyn Fn(UseDropZoneEvent) + Send + Sync>,
/// Event handler for the [`dragenter`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragenter_event) event /// Event handler for the [`dragenter`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragenter_event) event
on_enter: Rc<dyn Fn(UseDropZoneEvent)>, on_enter: Arc<dyn Fn(UseDropZoneEvent) + Send + Sync>,
/// Event handler for the [`dragleave`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragleave_event) event /// Event handler for the [`dragleave`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragleave_event) event
on_leave: Rc<dyn Fn(UseDropZoneEvent)>, on_leave: Arc<dyn Fn(UseDropZoneEvent) + Send + Sync>,
/// Event handler for the [`dragover`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragover_event) event /// Event handler for the [`dragover`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragover_event) event
on_over: Rc<dyn Fn(UseDropZoneEvent)>, on_over: Arc<dyn Fn(UseDropZoneEvent) + Send + Sync>,
} }
impl Default for UseDropZoneOptions { impl Default for UseDropZoneOptions {
fn default() -> Self { fn default() -> Self {
Self { Self {
on_drop: Rc::new(|_| {}), on_drop: Arc::new(|_| {}),
on_enter: Rc::new(|_| {}), on_enter: Arc::new(|_| {}),
on_leave: Rc::new(|_| {}), on_leave: Arc::new(|_| {}),
on_over: Rc::new(|_| {}), on_over: Arc::new(|_| {}),
} }
} }
} }
@ -214,7 +215,7 @@ pub struct UseDropZoneEvent {
/// Return type of [`use_drop_zone`]. /// Return type of [`use_drop_zone`].
pub struct UseDropZoneReturn { pub struct UseDropZoneReturn {
/// Files being handled /// Files being handled
pub files: Signal<Vec<web_sys::File>>, pub files: Signal<Vec<SendWrapper<web_sys::File>>>,
/// Whether the files (dragged by the pointer) are over the drop zone /// Whether the files (dragged by the pointer) are over the drop zone
pub is_over_drop_zone: Signal<bool>, pub is_over_drop_zone: Signal<bool>,
} }

View file

@ -259,9 +259,9 @@ where
for event_name in named_events.clone() { for event_name in named_events.clone() {
let _ = use_event_listener( let _ = use_event_listener(
es.clone(), es.clone(),
leptos::ev::Custom::<ev::Event>::new(event_name), leptos::ev::Custom::<leptos::ev::Event>::new(event_name),
move |e| { 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()); let data_string = js!(e["data"]).ok().and_then(|d| d.as_string());
set_data_from_string(data_string); set_data_from_string(data_string);
}, },

View file

@ -303,9 +303,11 @@ where
Some(Arc::new(move || { Some(Arc::new(move || {
if !manually_closed_ref.get_value() if !manually_closed_ref.get_value()
&& !reconnect_limit.is_exceeded_by(reconnect_times_ref.get_value()) && !reconnect_limit.is_exceeded_by(reconnect_times_ref.get_value())
&& ws_ref.get_value().map_or(false, |ws: SendWrapper<WebSocket>| { && ws_ref
ws.ready_state() != WebSocket::OPEN .get_value()
}) .map_or(false, |ws: SendWrapper<WebSocket>| {
ws.ready_state() != WebSocket::OPEN
})
{ {
reconnect_timer_ref.set_value( reconnect_timer_ref.set_value(
set_timeout_with_handle( set_timeout_with_handle(
@ -417,7 +419,7 @@ where
on_message(&val); on_message(&val);
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
drop(zone); drop(zone);
set_message.set(Some(val)); set_message.set(Some(val));
} }
@ -628,7 +630,7 @@ impl ReconnectLimit {
} }
} }
type ArcFnBytes = Arc<dyn Fn(&[u8])>; type ArcFnBytes = Arc<dyn Fn(&[u8]) + Send + Sync>;
/// Options for [`use_websocket_with_options`]. /// Options for [`use_websocket_with_options`].
#[derive(DefaultBuilder)] #[derive(DefaultBuilder)]
@ -644,7 +646,7 @@ where
/// `WebSocket` message callback for text. /// `WebSocket` message callback for text.
on_message_raw: Arc<dyn Fn(&str) + Send + Sync>, on_message_raw: Arc<dyn Fn(&str) + Send + Sync>,
/// `WebSocket` message callback for binary. /// `WebSocket` message callback for binary.
on_message_raw_bytes: ArcFnBytes + Send + Sync, on_message_raw_bytes: ArcFnBytes,
/// `WebSocket` error callback. /// `WebSocket` error callback.
#[builder(skip)] #[builder(skip)]
on_error: Arc<dyn Fn(UseWebSocketError<E, D>) + Send + Sync>, on_error: Arc<dyn Fn(UseWebSocketError<E, D>) + Send + Sync>,

View file

@ -15,7 +15,7 @@ macro_rules! signal_filtered {
) -> Signal<T> ) -> Signal<T>
where where
S: Into<Signal<T>>, S: Into<Signal<T>>,
T: Clone + 'static, T: Clone + Send + Sync + 'static,
{ {
[<signal_ $filter_name d_with_options>](value, ms, [<$filter_name:camel Options>]::default()) [<signal_ $filter_name d_with_options>](value, ms, [<$filter_name:camel Options>]::default())
} }
@ -36,7 +36,7 @@ macro_rules! signal_filtered {
) -> Signal<T> ) -> Signal<T>
where where
S: Into<Signal<T>>, S: Into<Signal<T>>,
T: Clone + 'static, T: Clone + Send + Sync + 'static,
{ {
let value = value.into(); let value = value.into();
let ms = ms.into(); let ms = ms.into();