#![forbid(unsafe_code)]
use crate::{store_value, RwSignal, Scope, StoredValue, WriteSignal};
pub trait IntoSignalSetter<T>: Sized {
fn mapped_signal_setter(self, cx: Scope) -> SignalSetter<T>;
}
impl<F, T> IntoSignalSetter<T> for F
where
F: Fn(T) + 'static,
{
fn mapped_signal_setter(self, cx: Scope) -> SignalSetter<T> {
SignalSetter::map(cx, self)
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct SignalSetter<T>
where
T: 'static,
{
inner: SignalSetterTypes<T>,
#[cfg(debug_assertions)]
defined_at: &'static std::panic::Location<'static>,
}
impl<T> Clone for SignalSetter<T> {
fn clone(&self) -> Self {
Self {
inner: self.inner,
#[cfg(debug_assertions)]
defined_at: self.defined_at,
}
}
}
impl<T: Default + 'static> Default for SignalSetter<T> {
#[track_caller]
fn default() -> Self {
Self {
inner: SignalSetterTypes::Default,
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
}
impl<T> Copy for SignalSetter<T> {}
impl<T> SignalSetter<T>
where
T: 'static,
{
#[track_caller]
#[cfg_attr(
debug_assertions,
instrument(
level = "trace",
skip_all,
fields(
cx = ?cx.id,
)
)
)]
pub fn map(cx: Scope, mapped_setter: impl Fn(T) + 'static) -> Self {
Self {
inner: SignalSetterTypes::Mapped(cx, store_value(cx, Box::new(mapped_setter))),
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
#[cfg_attr(
debug_assertions,
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(|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(debug_assertions)]
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(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
}
enum SignalSetterTypes<T>
where
T: 'static,
{
Write(WriteSignal<T>),
Mapped(Scope, StoredValue<Box<dyn Fn(T)>>),
Default,
}
impl<T> Clone for SignalSetterTypes<T> {
fn clone(&self) -> Self {
match self {
Self::Write(arg0) => Self::Write(*arg0),
Self::Mapped(cx, f) => Self::Mapped(*cx, *f),
Self::Default => Self::Default,
}
}
}
impl<T> Copy for SignalSetterTypes<T> {}
impl<T> std::fmt::Debug for SignalSetterTypes<T>
where
T: std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::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 {}
#[cfg(not(feature = "stable"))]
impl<T> FnOnce<(T,)> for SignalSetter<T>
where
T: 'static,
{
type Output = ();
extern "rust-call" fn call_once(self, args: (T,)) -> Self::Output {
self.set(args.0)
}
}
#[cfg(not(feature = "stable"))]
impl<T> FnMut<(T,)> for SignalSetter<T>
where
T: 'static,
{
extern "rust-call" fn call_mut(&mut self, args: (T,)) -> Self::Output {
self.set(args.0)
}
}
#[cfg(not(feature = "stable"))]
impl<T> Fn<(T,)> for SignalSetter<T>
where
T: 'static,
{
extern "rust-call" fn call(&self, args: (T,)) -> Self::Output {
self.set(args.0)
}
}