use core::{marker::PhantomData, panic::Location};
use crate::{Signal, SignalIdentity, watcher::Context};
#[derive(Debug)]
pub struct Map<C, F, Output> {
source: C,
f: F,
discriminator: usize,
_marker: PhantomData<Output>,
}
impl<C, F, Output> Map<C, F, Output>
where
C: Signal,
F: 'static + Clone + Fn(C::Output) -> Output,
Output: 'static, {
#[track_caller]
pub fn new(source: C, f: F) -> Self {
Self {
source,
f,
discriminator: SignalIdentity::call_site_discriminator::<(F, Output)>(
Location::caller(),
),
_marker: PhantomData,
}
}
}
#[track_caller]
pub fn map<C, F, Output>(source: C, f: F) -> Map<C, F, Output>
where
C: Signal + 'static,
Output: 'static,
F: 'static + Clone + Fn(C::Output) -> Output,
{
Map::new(source, f)
}
impl<C: Clone, F: Clone, Output> Clone for Map<C, F, Output> {
fn clone(&self) -> Self {
Self {
source: self.source.clone(),
f: self.f.clone(),
discriminator: self.discriminator,
_marker: PhantomData,
}
}
}
impl<C, F, Output> Signal for Map<C, F, Output>
where
C: Signal,
F: 'static + Clone + Fn(C::Output) -> Output,
Output: 'static,
{
type Output = Output;
type Guard = C::Guard;
fn get(&self) -> Output {
(self.f)(self.source.get())
}
fn identity(&self) -> Option<SignalIdentity> {
self.source
.identity()
.map(|identity| identity.with_discriminator(self.discriminator))
}
fn watch(&self, watcher: impl Fn(Context<Self::Output>) + 'static) -> Self::Guard {
let this = self.clone();
self.source.watch(move |context| {
let context = context.map(|value| (this.f)(value));
watcher(context);
})
}
}
impl_signal_ops!(Map<C, F, Output>, [C, F, Output], Output);