use core::panic::Location;
mod computed;
pub use computed::*;
use crate::{
map::{Map, map},
watcher::Context,
};
pub use nami_core::{Signal, SignalIdentity};
pub trait IntoSignal<Output> {
type Signal: Signal<Output = Output>;
fn into_signal(self) -> Self::Signal;
}
pub trait IntoComputed<Output>: IntoSignal<Output> + 'static {
fn into_computed(self) -> Computed<Output>;
}
impl<C, Output> IntoSignal<Output> for C
where
C: Signal,
C::Output: 'static + Clone,
Output: From<C::Output> + 'static,
{
type Signal = Map<C, fn(C::Output) -> Output, Output>;
fn into_signal(self) -> Self::Signal {
map(self, core::convert::Into::into)
}
}
impl<C, Output> IntoComputed<Output> for C
where
C: IntoSignal<Output> + 'static,
C::Signal: Clone + 'static,
{
fn into_computed(self) -> Computed<Output> {
Computed::new(self.into_signal())
}
}
#[derive(Debug, Clone)]
pub struct WithMetadata<C, T> {
metadata: T,
signal: C,
discriminator: usize,
}
impl<C, T: 'static> WithMetadata<C, T> {
#[track_caller]
pub fn new(metadata: T, signal: C) -> Self {
Self {
metadata,
signal,
discriminator: SignalIdentity::call_site_discriminator::<T>(Location::caller()),
}
}
}
impl<C: Signal, T: Clone + 'static> Signal for WithMetadata<C, T> {
type Output = C::Output;
type Guard = C::Guard;
fn get(&self) -> Self::Output {
self.signal.get()
}
fn identity(&self) -> Option<SignalIdentity> {
self.signal
.identity()
.map(|identity| identity.with_discriminator(self.discriminator))
}
fn watch(&self, watcher: impl Fn(Context<Self::Output>) + 'static) -> Self::Guard {
let with = self.metadata.clone();
self.signal
.watch(move |context: Context<<C as Signal>::Output>| {
watcher(context.with(with.clone()));
})
}
}
impl_signal_wrapper_ops!(WithMetadata<C, T>, [C, T], C);