mirror of
https://github.com/leptos-rs/leptos.git
synced 2025-12-27 09:54:41 -05:00
feat: resupport From<Fn() -> T> for Signal<T>, ArcSignal<T>, Callback<T, _> and similar (#4273)
This commit is contained in:
@@ -29,6 +29,7 @@ send_wrapper = { features = [
|
||||
], workspace = true, default-features = true }
|
||||
subsecond = { workspace = true, default-features = true, optional = true }
|
||||
indexmap = { workspace = true, default-features = true }
|
||||
paste = { workspace = true, default-features = true }
|
||||
|
||||
[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
|
||||
web-sys = { version = "0.3.77", features = ["console"] }
|
||||
@@ -40,6 +41,7 @@ tokio = { features = [
|
||||
], workspace = true, default-features = true }
|
||||
tokio-test = { workspace = true, default-features = true }
|
||||
any_spawner = { workspace = true, features = ["futures-executor", "tokio"] }
|
||||
typed-builder.workspace = true
|
||||
|
||||
[build-dependencies]
|
||||
rustc_version = { workspace = true, default-features = true }
|
||||
|
||||
417
reactive_graph/src/callback.rs
Normal file
417
reactive_graph/src/callback.rs
Normal file
@@ -0,0 +1,417 @@
|
||||
//! Callbacks define a standard way to store functions and closures. They are useful
|
||||
//! for component properties, because they can be used to define optional callback functions,
|
||||
//! which generic props don’t support.
|
||||
//!
|
||||
//! The callback types implement [`Copy`], so they can easily be moved into and out of other closures, just like signals.
|
||||
//!
|
||||
//! # Types
|
||||
//! This modules implements 2 callback types:
|
||||
//! - [`Callback`](reactive_graph::callback::Callback)
|
||||
//! - [`UnsyncCallback`](reactive_graph::callback::UnsyncCallback)
|
||||
//!
|
||||
//! Use `SyncCallback` if the function is not `Sync` and `Send`.
|
||||
|
||||
use crate::{
|
||||
owner::{LocalStorage, StoredValue},
|
||||
traits::{Dispose, WithValue},
|
||||
IntoReactiveValue,
|
||||
};
|
||||
use std::{fmt, rc::Rc, sync::Arc};
|
||||
|
||||
/// A wrapper trait for calling callbacks.
|
||||
pub trait Callable<In: 'static, Out: 'static = ()> {
|
||||
/// calls the callback with the specified argument.
|
||||
///
|
||||
/// Returns None if the callback has been disposed
|
||||
fn try_run(&self, input: In) -> Option<Out>;
|
||||
/// calls the callback with the specified argument.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if you try to run a callback that has been disposed
|
||||
fn run(&self, input: In) -> Out;
|
||||
}
|
||||
|
||||
/// A callback type that is not required to be [`Send`] or [`Sync`].
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use reactive_graph::prelude::*; use reactive_graph::callback::*; let owner = reactive_graph::owner::Owner::new(); owner.set();
|
||||
/// let _: UnsyncCallback<()> = UnsyncCallback::new(|_| {});
|
||||
/// let _: UnsyncCallback<(i32, i32)> = (|_x: i32, _y: i32| {}).into();
|
||||
/// let cb: UnsyncCallback<i32, String> = UnsyncCallback::new(|x: i32| x.to_string());
|
||||
/// assert_eq!(cb.run(42), "42".to_string());
|
||||
/// ```
|
||||
pub struct UnsyncCallback<In: 'static, Out: 'static = ()>(
|
||||
StoredValue<Rc<dyn Fn(In) -> Out>, LocalStorage>,
|
||||
);
|
||||
|
||||
impl<In> fmt::Debug for UnsyncCallback<In> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
fmt.write_str("Callback")
|
||||
}
|
||||
}
|
||||
|
||||
impl<In, Out> Copy for UnsyncCallback<In, Out> {}
|
||||
|
||||
impl<In, Out> Clone for UnsyncCallback<In, Out> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<In, Out> Dispose for UnsyncCallback<In, Out> {
|
||||
fn dispose(self) {
|
||||
self.0.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
impl<In, Out> UnsyncCallback<In, Out> {
|
||||
/// Creates a new callback from the given function.
|
||||
pub fn new<F>(f: F) -> UnsyncCallback<In, Out>
|
||||
where
|
||||
F: Fn(In) -> Out + 'static,
|
||||
{
|
||||
Self(StoredValue::new_local(Rc::new(f)))
|
||||
}
|
||||
|
||||
/// Returns `true` if both callbacks wrap the same underlying function pointer.
|
||||
#[inline]
|
||||
pub fn matches(&self, other: &Self) -> bool {
|
||||
self.0.with_value(|self_value| {
|
||||
other
|
||||
.0
|
||||
.with_value(|other_value| Rc::ptr_eq(self_value, other_value))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<In: 'static, Out: 'static> Callable<In, Out> for UnsyncCallback<In, Out> {
|
||||
fn try_run(&self, input: In) -> Option<Out> {
|
||||
self.0.try_with_value(|fun| fun(input))
|
||||
}
|
||||
|
||||
fn run(&self, input: In) -> Out {
|
||||
self.0.with_value(|fun| fun(input))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_unsync_callable_from_fn {
|
||||
($($arg:ident),*) => {
|
||||
impl<F, $($arg,)* T, Out> From<F> for UnsyncCallback<($($arg,)*), Out>
|
||||
where
|
||||
F: Fn($($arg),*) -> T + 'static,
|
||||
T: Into<Out> + 'static,
|
||||
$($arg: 'static,)*
|
||||
{
|
||||
fn from(f: F) -> Self {
|
||||
paste::paste!(
|
||||
Self::new(move |($([<$arg:lower>],)*)| f($([<$arg:lower>]),*).into())
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_unsync_callable_from_fn!();
|
||||
impl_unsync_callable_from_fn!(P1);
|
||||
impl_unsync_callable_from_fn!(P1, P2);
|
||||
impl_unsync_callable_from_fn!(P1, P2, P3);
|
||||
impl_unsync_callable_from_fn!(P1, P2, P3, P4);
|
||||
impl_unsync_callable_from_fn!(P1, P2, P3, P4, P5);
|
||||
impl_unsync_callable_from_fn!(P1, P2, P3, P4, P5, P6);
|
||||
impl_unsync_callable_from_fn!(P1, P2, P3, P4, P5, P6, P7);
|
||||
impl_unsync_callable_from_fn!(P1, P2, P3, P4, P5, P6, P7, P8);
|
||||
impl_unsync_callable_from_fn!(P1, P2, P3, P4, P5, P6, P7, P8, P9);
|
||||
impl_unsync_callable_from_fn!(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10);
|
||||
impl_unsync_callable_from_fn!(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11);
|
||||
impl_unsync_callable_from_fn!(
|
||||
P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12
|
||||
);
|
||||
|
||||
/// A callback type that is [`Send`] + [`Sync`].
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use reactive_graph::prelude::*; use reactive_graph::callback::*; let owner = reactive_graph::owner::Owner::new(); owner.set();
|
||||
/// let _: Callback<()> = Callback::new(|_| {});
|
||||
/// let _: Callback<(i32, i32)> = (|_x: i32, _y: i32| {}).into();
|
||||
/// let cb: Callback<i32, String> = Callback::new(|x: i32| x.to_string());
|
||||
/// assert_eq!(cb.run(42), "42".to_string());
|
||||
/// ```
|
||||
pub struct Callback<In, Out = ()>(
|
||||
StoredValue<Arc<dyn Fn(In) -> Out + Send + Sync>>,
|
||||
)
|
||||
where
|
||||
In: 'static,
|
||||
Out: 'static;
|
||||
|
||||
impl<In, Out> fmt::Debug for Callback<In, Out> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
fmt.write_str("SyncCallback")
|
||||
}
|
||||
}
|
||||
|
||||
impl<In, Out> Callable<In, Out> for Callback<In, Out> {
|
||||
fn try_run(&self, input: In) -> Option<Out> {
|
||||
self.0.try_with_value(|fun| fun(input))
|
||||
}
|
||||
|
||||
fn run(&self, input: In) -> Out {
|
||||
self.0.with_value(|f| f(input))
|
||||
}
|
||||
}
|
||||
|
||||
impl<In, Out> Clone for Callback<In, Out> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<In, Out> Dispose for Callback<In, Out> {
|
||||
fn dispose(self) {
|
||||
self.0.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
impl<In, Out> Copy for Callback<In, Out> {}
|
||||
|
||||
macro_rules! impl_callable_from_fn {
|
||||
($($arg:ident),*) => {
|
||||
impl<F, $($arg,)* T, Out> From<F> for Callback<($($arg,)*), Out>
|
||||
where
|
||||
F: Fn($($arg),*) -> T + Send + Sync + 'static,
|
||||
T: Into<Out> + 'static,
|
||||
$($arg: Send + Sync + 'static,)*
|
||||
{
|
||||
fn from(f: F) -> Self {
|
||||
paste::paste!(
|
||||
Self::new(move |($([<$arg:lower>],)*)| f($([<$arg:lower>]),*).into())
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_callable_from_fn!();
|
||||
impl_callable_from_fn!(P1);
|
||||
impl_callable_from_fn!(P1, P2);
|
||||
impl_callable_from_fn!(P1, P2, P3);
|
||||
impl_callable_from_fn!(P1, P2, P3, P4);
|
||||
impl_callable_from_fn!(P1, P2, P3, P4, P5);
|
||||
impl_callable_from_fn!(P1, P2, P3, P4, P5, P6);
|
||||
impl_callable_from_fn!(P1, P2, P3, P4, P5, P6, P7);
|
||||
impl_callable_from_fn!(P1, P2, P3, P4, P5, P6, P7, P8);
|
||||
impl_callable_from_fn!(P1, P2, P3, P4, P5, P6, P7, P8, P9);
|
||||
impl_callable_from_fn!(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10);
|
||||
impl_callable_from_fn!(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11);
|
||||
impl_callable_from_fn!(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12);
|
||||
|
||||
impl<In: 'static, Out: 'static> Callback<In, Out> {
|
||||
/// Creates a new callback from the given function.
|
||||
#[track_caller]
|
||||
pub fn new<F>(fun: F) -> Self
|
||||
where
|
||||
F: Fn(In) -> Out + Send + Sync + 'static,
|
||||
{
|
||||
Self(StoredValue::new(Arc::new(fun)))
|
||||
}
|
||||
|
||||
/// Returns `true` if both callbacks wrap the same underlying function pointer.
|
||||
#[inline]
|
||||
pub fn matches(&self, other: &Self) -> bool {
|
||||
self.0
|
||||
.try_with_value(|self_value| {
|
||||
other.0.try_with_value(|other_value| {
|
||||
Arc::ptr_eq(self_value, other_value)
|
||||
})
|
||||
})
|
||||
.flatten()
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct __IntoReactiveValueMarkerCallbackSingleParam;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct __IntoReactiveValueMarkerCallbackStrOutputToString;
|
||||
|
||||
impl<I, O, F>
|
||||
IntoReactiveValue<
|
||||
Callback<I, O>,
|
||||
__IntoReactiveValueMarkerCallbackSingleParam,
|
||||
> for F
|
||||
where
|
||||
F: Fn(I) -> O + Send + Sync + 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
fn into_reactive_value(self) -> Callback<I, O> {
|
||||
Callback::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, O, F>
|
||||
IntoReactiveValue<
|
||||
UnsyncCallback<I, O>,
|
||||
__IntoReactiveValueMarkerCallbackSingleParam,
|
||||
> for F
|
||||
where
|
||||
F: Fn(I) -> O + 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
fn into_reactive_value(self) -> UnsyncCallback<I, O> {
|
||||
UnsyncCallback::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, F>
|
||||
IntoReactiveValue<
|
||||
Callback<I, String>,
|
||||
__IntoReactiveValueMarkerCallbackStrOutputToString,
|
||||
> for F
|
||||
where
|
||||
F: Fn(I) -> &'static str + Send + Sync + 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
fn into_reactive_value(self) -> Callback<I, String> {
|
||||
Callback::new(move |i| self(i).to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, F>
|
||||
IntoReactiveValue<
|
||||
UnsyncCallback<I, String>,
|
||||
__IntoReactiveValueMarkerCallbackStrOutputToString,
|
||||
> for F
|
||||
where
|
||||
F: Fn(I) -> &'static str + 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
fn into_reactive_value(self) -> UnsyncCallback<I, String> {
|
||||
UnsyncCallback::new(move |i| self(i).to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Callable;
|
||||
use crate::{
|
||||
callback::{Callback, UnsyncCallback},
|
||||
owner::Owner,
|
||||
traits::Dispose,
|
||||
IntoReactiveValue,
|
||||
};
|
||||
|
||||
struct NoClone {}
|
||||
|
||||
#[test]
|
||||
fn clone_callback() {
|
||||
let owner = Owner::new();
|
||||
owner.set();
|
||||
|
||||
let callback = Callback::new(move |_no_clone: NoClone| NoClone {});
|
||||
let _cloned = callback;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clone_unsync_callback() {
|
||||
let owner = Owner::new();
|
||||
owner.set();
|
||||
|
||||
let callback =
|
||||
UnsyncCallback::new(move |_no_clone: NoClone| NoClone {});
|
||||
let _cloned = callback;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runback_from() {
|
||||
let owner = Owner::new();
|
||||
owner.set();
|
||||
|
||||
let _callback: Callback<(), String> = (|| "test").into();
|
||||
let _callback: Callback<(i32, String), String> =
|
||||
(|num, s| format!("{num} {s}")).into();
|
||||
// Single params should work without needing the (foo,) tuple using IntoReactiveValue:
|
||||
let _callback: Callback<usize, &'static str> =
|
||||
(|_usize| "test").into_reactive_value();
|
||||
let _callback: Callback<usize, String> =
|
||||
(|_usize| "test").into_reactive_value();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_callback_from() {
|
||||
let owner = Owner::new();
|
||||
owner.set();
|
||||
|
||||
let _callback: UnsyncCallback<(), String> = (|| "test").into();
|
||||
let _callback: UnsyncCallback<(i32, String), String> =
|
||||
(|num, s| format!("{num} {s}")).into();
|
||||
// Single params should work without needing the (foo,) tuple using IntoReactiveValue:
|
||||
let _callback: UnsyncCallback<usize, &'static str> =
|
||||
(|_usize| "test").into_reactive_value();
|
||||
let _callback: UnsyncCallback<usize, String> =
|
||||
(|_usize| "test").into_reactive_value();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_callback_try_run() {
|
||||
let owner = Owner::new();
|
||||
owner.set();
|
||||
|
||||
let callback = Callback::new(move |arg| arg);
|
||||
assert_eq!(callback.try_run((0,)), Some((0,)));
|
||||
callback.dispose();
|
||||
assert_eq!(callback.try_run((0,)), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsync_callback_try_run() {
|
||||
let owner = Owner::new();
|
||||
owner.set();
|
||||
|
||||
let callback = UnsyncCallback::new(move |arg| arg);
|
||||
assert_eq!(callback.try_run((0,)), Some((0,)));
|
||||
callback.dispose();
|
||||
assert_eq!(callback.try_run((0,)), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn callback_matches_same() {
|
||||
let owner = Owner::new();
|
||||
owner.set();
|
||||
|
||||
let callback1 = Callback::new(|x: i32| x * 2);
|
||||
let callback2 = callback1;
|
||||
assert!(callback1.matches(&callback2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn callback_matches_different() {
|
||||
let owner = Owner::new();
|
||||
owner.set();
|
||||
|
||||
let callback1 = Callback::new(|x: i32| x * 2);
|
||||
let callback2 = Callback::new(|x: i32| x + 1);
|
||||
assert!(!callback1.matches(&callback2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsync_callback_matches_same() {
|
||||
let owner = Owner::new();
|
||||
owner.set();
|
||||
|
||||
let callback1 = UnsyncCallback::new(|x: i32| x * 2);
|
||||
let callback2 = callback1;
|
||||
assert!(callback1.matches(&callback2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsync_callback_matches_different() {
|
||||
let owner = Owner::new();
|
||||
owner.set();
|
||||
|
||||
let callback1 = UnsyncCallback::new(|x: i32| x * 2);
|
||||
let callback2 = UnsyncCallback::new(|x: i32| x + 1);
|
||||
assert!(!callback1.matches(&callback2));
|
||||
}
|
||||
}
|
||||
67
reactive_graph/src/into_reactive_value.rs
Normal file
67
reactive_graph/src/into_reactive_value.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
#[doc(hidden)]
|
||||
pub struct __IntoReactiveValueMarkerBaseCase;
|
||||
|
||||
/// A helper trait that works like `Into<T>` but uses a marker generic
|
||||
/// to allow more `From` implementations than would be allowed with just `Into<T>`.
|
||||
pub trait IntoReactiveValue<T, M> {
|
||||
/// Converts `self` into a `T`.
|
||||
fn into_reactive_value(self) -> T;
|
||||
}
|
||||
|
||||
// The base case, which allows anything which implements .into() to work:
|
||||
impl<T, I> IntoReactiveValue<T, __IntoReactiveValueMarkerBaseCase> for I
|
||||
where
|
||||
I: Into<T>,
|
||||
{
|
||||
fn into_reactive_value(self) -> T {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
into_reactive_value::IntoReactiveValue,
|
||||
owner::{LocalStorage, Owner},
|
||||
traits::GetUntracked,
|
||||
wrappers::read::Signal,
|
||||
};
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
#[test]
|
||||
fn test_into_signal_compiles() {
|
||||
let owner = Owner::new();
|
||||
owner.set();
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
let _: Signal<usize> = (|| 2).into_reactive_value();
|
||||
let _: Signal<usize, LocalStorage> = 2.into_reactive_value();
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
let _: Signal<usize, LocalStorage> = (|| 2).into_reactive_value();
|
||||
let _: Signal<String> = "str".into_reactive_value();
|
||||
let _: Signal<String, LocalStorage> = "str".into_reactive_value();
|
||||
|
||||
#[derive(TypedBuilder)]
|
||||
struct Foo {
|
||||
#[builder(setter(
|
||||
fn transform<M>(value: impl IntoReactiveValue<Signal<usize>, M>) {
|
||||
value.into_reactive_value()
|
||||
}
|
||||
))]
|
||||
sig: Signal<usize>,
|
||||
}
|
||||
|
||||
assert_eq!(Foo::builder().sig(2).build().sig.get_untracked(), 2);
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
assert_eq!(Foo::builder().sig(|| 2).build().sig.get_untracked(), 2);
|
||||
assert_eq!(
|
||||
Foo::builder()
|
||||
.sig(Signal::stored(2))
|
||||
.build()
|
||||
.sig
|
||||
.get_untracked(),
|
||||
2
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -90,6 +90,12 @@ pub mod traits;
|
||||
pub mod transition;
|
||||
pub mod wrappers;
|
||||
|
||||
mod into_reactive_value;
|
||||
pub use into_reactive_value::*;
|
||||
|
||||
/// A standard way to wrap functions and closures to pass them to components.
|
||||
pub mod callback;
|
||||
|
||||
use computed::ScopedFuture;
|
||||
|
||||
#[cfg(all(feature = "nightly", rustc_nightly))]
|
||||
@@ -97,7 +103,9 @@ mod nightly;
|
||||
|
||||
/// Reexports frequently-used traits.
|
||||
pub mod prelude {
|
||||
pub use crate::{owner::FromLocal, traits::*};
|
||||
pub use crate::{
|
||||
into_reactive_value::IntoReactiveValue, owner::FromLocal, traits::*,
|
||||
};
|
||||
}
|
||||
|
||||
// TODO remove this, it's just useful while developing
|
||||
|
||||
@@ -324,6 +324,22 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> From<&'static str> for ArcSignal<String, S>
|
||||
where
|
||||
S: Storage<&'static str> + Storage<String>,
|
||||
{
|
||||
#[track_caller]
|
||||
fn from(value: &'static str) -> Self {
|
||||
Self {
|
||||
inner: SignalTypes::Stored(ArcStoredValue::new(
|
||||
value.to_string(),
|
||||
)),
|
||||
#[cfg(any(debug_assertions, leptos_debuginfo))]
|
||||
defined_at: std::panic::Location::caller(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> DefinedAt for ArcSignal<T, S>
|
||||
where
|
||||
S: Storage<T>,
|
||||
@@ -1049,6 +1065,13 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Signal<&'static str, LocalStorage>> for Signal<String, LocalStorage> {
|
||||
#[track_caller]
|
||||
fn from(value: Signal<&'static str, LocalStorage>) -> Self {
|
||||
Signal::derive_local(move || value.read().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Signal<&'static str>> for Signal<String, LocalStorage> {
|
||||
#[track_caller]
|
||||
fn from(value: Signal<&'static str>) -> Self {
|
||||
@@ -1077,6 +1100,15 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Signal<Option<&'static str>, LocalStorage>>
|
||||
for Signal<Option<String>, LocalStorage>
|
||||
{
|
||||
#[track_caller]
|
||||
fn from(value: Signal<Option<&'static str>, LocalStorage>) -> Self {
|
||||
Signal::derive_local(move || value.read().map(str::to_string))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Signal<Option<&'static str>>>
|
||||
for Signal<Option<String>, LocalStorage>
|
||||
{
|
||||
@@ -1086,6 +1118,192 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
#[doc(hidden)]
|
||||
pub struct __IntoReactiveValueMarkerSignalFromReactiveClosure;
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
#[doc(hidden)]
|
||||
pub struct __IntoReactiveValueMarkerSignalStrOutputToString;
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
#[doc(hidden)]
|
||||
pub struct __IntoReactiveValueMarkerOptionalSignalFromReactiveClosureAlways;
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
impl<T, F>
|
||||
crate::IntoReactiveValue<
|
||||
Signal<T, SyncStorage>,
|
||||
__IntoReactiveValueMarkerSignalFromReactiveClosure,
|
||||
> for F
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
F: Fn() -> T + Send + Sync + 'static,
|
||||
{
|
||||
fn into_reactive_value(self) -> Signal<T, SyncStorage> {
|
||||
Signal::derive(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
impl<T, F>
|
||||
crate::IntoReactiveValue<
|
||||
ArcSignal<T, SyncStorage>,
|
||||
__IntoReactiveValueMarkerSignalFromReactiveClosure,
|
||||
> for F
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
F: Fn() -> T + Send + Sync + 'static,
|
||||
{
|
||||
fn into_reactive_value(self) -> ArcSignal<T, SyncStorage> {
|
||||
ArcSignal::derive(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
impl<T, F>
|
||||
crate::IntoReactiveValue<
|
||||
Signal<T, LocalStorage>,
|
||||
__IntoReactiveValueMarkerSignalFromReactiveClosure,
|
||||
> for F
|
||||
where
|
||||
T: 'static,
|
||||
F: Fn() -> T + 'static,
|
||||
{
|
||||
fn into_reactive_value(self) -> Signal<T, LocalStorage> {
|
||||
Signal::derive_local(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
impl<T, F>
|
||||
crate::IntoReactiveValue<
|
||||
ArcSignal<T, LocalStorage>,
|
||||
__IntoReactiveValueMarkerSignalFromReactiveClosure,
|
||||
> for F
|
||||
where
|
||||
T: 'static,
|
||||
F: Fn() -> T + 'static,
|
||||
{
|
||||
fn into_reactive_value(self) -> ArcSignal<T, LocalStorage> {
|
||||
ArcSignal::derive_local(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
impl<F>
|
||||
crate::IntoReactiveValue<
|
||||
Signal<String, SyncStorage>,
|
||||
__IntoReactiveValueMarkerSignalStrOutputToString,
|
||||
> for F
|
||||
where
|
||||
F: Fn() -> &'static str + Send + Sync + 'static,
|
||||
{
|
||||
fn into_reactive_value(self) -> Signal<String, SyncStorage> {
|
||||
Signal::derive(move || self().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
impl<F>
|
||||
crate::IntoReactiveValue<
|
||||
ArcSignal<String, SyncStorage>,
|
||||
__IntoReactiveValueMarkerSignalStrOutputToString,
|
||||
> for F
|
||||
where
|
||||
F: Fn() -> &'static str + Send + Sync + 'static,
|
||||
{
|
||||
fn into_reactive_value(self) -> ArcSignal<String, SyncStorage> {
|
||||
ArcSignal::derive(move || self().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
impl<F>
|
||||
crate::IntoReactiveValue<
|
||||
Signal<String, LocalStorage>,
|
||||
__IntoReactiveValueMarkerSignalStrOutputToString,
|
||||
> for F
|
||||
where
|
||||
F: Fn() -> &'static str + 'static,
|
||||
{
|
||||
fn into_reactive_value(self) -> Signal<String, LocalStorage> {
|
||||
Signal::derive_local(move || self().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
impl<F>
|
||||
crate::IntoReactiveValue<
|
||||
ArcSignal<String, LocalStorage>,
|
||||
__IntoReactiveValueMarkerSignalStrOutputToString,
|
||||
> for F
|
||||
where
|
||||
F: Fn() -> &'static str + 'static,
|
||||
{
|
||||
fn into_reactive_value(self) -> ArcSignal<String, LocalStorage> {
|
||||
ArcSignal::derive_local(move || self().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
impl<T, F>
|
||||
crate::IntoReactiveValue<
|
||||
Signal<Option<T>, SyncStorage>,
|
||||
__IntoReactiveValueMarkerOptionalSignalFromReactiveClosureAlways,
|
||||
> for F
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
F: Fn() -> T + Send + Sync + 'static,
|
||||
{
|
||||
fn into_reactive_value(self) -> Signal<Option<T>, SyncStorage> {
|
||||
Signal::derive(move || Some(self()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
impl<T, F>
|
||||
crate::IntoReactiveValue<
|
||||
ArcSignal<Option<T>, SyncStorage>,
|
||||
__IntoReactiveValueMarkerOptionalSignalFromReactiveClosureAlways,
|
||||
> for F
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
F: Fn() -> T + Send + Sync + 'static,
|
||||
{
|
||||
fn into_reactive_value(self) -> ArcSignal<Option<T>, SyncStorage> {
|
||||
ArcSignal::derive(move || Some(self()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
impl<T, F>
|
||||
crate::IntoReactiveValue<
|
||||
Signal<Option<T>, LocalStorage>,
|
||||
__IntoReactiveValueMarkerOptionalSignalFromReactiveClosureAlways,
|
||||
> for F
|
||||
where
|
||||
T: 'static,
|
||||
F: Fn() -> T + 'static,
|
||||
{
|
||||
fn into_reactive_value(self) -> Signal<Option<T>, LocalStorage> {
|
||||
Signal::derive_local(move || Some(self()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
impl<T, F>
|
||||
crate::IntoReactiveValue<
|
||||
ArcSignal<Option<T>, LocalStorage>,
|
||||
__IntoReactiveValueMarkerOptionalSignalFromReactiveClosureAlways,
|
||||
> for F
|
||||
where
|
||||
T: 'static,
|
||||
F: Fn() -> T + 'static,
|
||||
{
|
||||
fn into_reactive_value(self) -> ArcSignal<Option<T>, LocalStorage> {
|
||||
ArcSignal::derive_local(move || Some(self()))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> From<MaybeSignal<T>> for Signal<T>
|
||||
where
|
||||
|
||||
Reference in New Issue
Block a user