use crate::{store_value, RwSignal, SignalSet, StoredValue, WriteSignal};
pub trait IntoSignalSetter<T>: Sized {
#[deprecated = "Will be removed in `leptos v0.6`. Please use \
`IntoSignalSetter::into_signal_setter()` instead."]
fn mapped_signal_setter(self) -> SignalSetter<T>;
fn into_signal_setter(self) -> SignalSetter<T>;
}
impl<F, T> IntoSignalSetter<T> for F
where
F: Fn(T) + 'static,
{
fn mapped_signal_setter(self) -> SignalSetter<T> {
self.into_signal_setter()
}
fn into_signal_setter(self) -> SignalSetter<T> {
SignalSetter::map(self)
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct SignalSetter<T>
where
T: 'static,
{
inner: SignalSetterTypes<T>,
#[cfg(any(debug_assertions, feature = "ssr"))]
defined_at: &'static std::panic::Location<'static>,
}
impl<T> Clone for SignalSetter<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: Default + 'static> Default for SignalSetter<T> {
#[track_caller]
fn default() -> Self {
Self {
inner: SignalSetterTypes::Default,
#[cfg(any(debug_assertions, feature = "ssr"))]
defined_at: std::panic::Location::caller(),
}
}
}
impl<T> Copy for SignalSetter<T> {}
impl<T> SignalSet for SignalSetter<T> {
type Value = T;
fn set(&self, new_value: T) {
match self.inner {
SignalSetterTypes::Default => {}
SignalSetterTypes::Write(w) => w.set(new_value),
SignalSetterTypes::Mapped(s) => {
s.with_value(|setter| setter(new_value))
}
}
}
fn try_set(&self, new_value: T) -> Option<T> {
match self.inner {
SignalSetterTypes::Default => Some(new_value),
SignalSetterTypes::Write(w) => w.try_set(new_value),
SignalSetterTypes::Mapped(s) => {
let mut new_value = Some(new_value);
let _ = s
.try_with_value(|setter| setter(new_value.take().unwrap()));
new_value
}
}
}
}
impl<T> SignalSetter<T>
where
T: 'static,
{
#[track_caller]
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", skip_all)
)]
pub fn map(mapped_setter: impl Fn(T) + 'static) -> Self {
Self {
inner: SignalSetterTypes::Mapped(store_value(Box::new(
mapped_setter,
))),
#[cfg(any(debug_assertions, feature = "ssr"))]
defined_at: std::panic::Location::caller(),
}
}
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(
level = "trace",
skip_all,
fields(
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
)]
pub fn set(&self, value: T) {
match &self.inner {
SignalSetterTypes::Write(s) => s.set(value),
SignalSetterTypes::Mapped(s) => s.with_value(|s| s(value)),
SignalSetterTypes::Default => {}
}
}
}
impl<T> From<WriteSignal<T>> for SignalSetter<T> {
#[track_caller]
fn from(value: WriteSignal<T>) -> Self {
Self {
inner: SignalSetterTypes::Write(value),
#[cfg(any(debug_assertions, feature = "ssr"))]
defined_at: std::panic::Location::caller(),
}
}
}
impl<T> From<RwSignal<T>> for SignalSetter<T> {
#[track_caller]
fn from(value: RwSignal<T>) -> Self {
Self {
inner: SignalSetterTypes::Write(value.write_only()),
#[cfg(any(debug_assertions, feature = "ssr"))]
defined_at: std::panic::Location::caller(),
}
}
}
enum SignalSetterTypes<T>
where
T: 'static,
{
Write(WriteSignal<T>),
Mapped(StoredValue<Box<dyn Fn(T)>>),
Default,
}
impl<T> Clone for SignalSetterTypes<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for SignalSetterTypes<T> {}
impl<T> core::fmt::Debug for SignalSetterTypes<T>
where
T: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Write(arg0) => {
f.debug_tuple("WriteSignal").field(arg0).finish()
}
Self::Mapped(_) => f.debug_tuple("Mapped").finish(),
Self::Default => f.debug_tuple("SignalSetter<Default>").finish(),
}
}
}
impl<T> PartialEq for SignalSetterTypes<T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Write(l0), Self::Write(r0)) => l0 == r0,
(Self::Mapped(l0), Self::Mapped(r0)) => std::ptr::eq(l0, r0),
_ => false,
}
}
}
impl<T> Eq for SignalSetterTypes<T> where T: PartialEq {}
impl_set_fn_traits![SignalSetter];