#![forbid(unsafe_code)]
use crate::{ReadSignal, Scope, SignalError, UntrackedGettableSignal};
use std::fmt::Debug;
#[cfg_attr(
debug_assertions,
instrument(
level = "trace",
skip_all,
fields(
cx = ?cx.id,
)
)
)]
pub fn create_memo<T>(cx: Scope, f: impl Fn(Option<&T>) -> T + 'static) -> Memo<T>
where
T: PartialEq + 'static,
{
cx.runtime.create_memo(f)
}
#[derive(Debug, PartialEq, Eq)]
pub struct Memo<T>(
pub(crate) ReadSignal<Option<T>>,
#[cfg(debug_assertions)] pub(crate) &'static std::panic::Location<'static>,
)
where
T: 'static;
impl<T> Clone for Memo<T>
where
T: 'static,
{
fn clone(&self) -> Self {
Self(
self.0,
#[cfg(debug_assertions)]
self.1,
)
}
}
impl<T> Copy for Memo<T> {}
impl<T> UntrackedGettableSignal<T> for Memo<T> {
#[cfg_attr(
debug_assertions,
instrument(
level = "trace",
name = "Memo::get_untracked()",
skip_all,
fields(
id = ?self.0.id,
defined_at = %self.1,
ty = %std::any::type_name::<T>()
)
)
)]
fn get_untracked(&self) -> T
where
T: Clone,
{
self.0.get_untracked().unwrap()
}
#[cfg_attr(
debug_assertions,
instrument(
level = "trace",
name = "Memo::with_untracked()",
skip_all,
fields(
id = ?self.0.id,
defined_at = %self.1,
ty = %std::any::type_name::<T>()
)
)
)]
fn with_untracked<O>(&self, f: impl FnOnce(&T) -> O) -> O {
self.0.with_untracked(|v| f(v.as_ref().unwrap()))
}
}
impl<T> Memo<T>
where
T: 'static,
{
#[cfg_attr(
debug_assertions,
instrument(
name = "Memo::get()",
level = "trace",
skip_all,
fields(
id = ?self.0.id,
defined_at = %self.1
)
)
)]
pub fn get(&self) -> T
where
T: Clone,
{
self.with(T::clone)
}
#[cfg_attr(
debug_assertions,
instrument(
name = "Memo::with()",
level = "trace",
skip_all,
fields(
id = ?self.0.id,
defined_at = %self.1,
ty = %std::any::type_name::<T>()
)
)
)]
pub fn with<U>(&self, f: impl FnOnce(&T) -> U) -> U {
self.0
.with(|n| f(n.as_ref().expect("Memo is missing its initial value")))
}
pub(crate) fn try_with<U>(&self, f: impl Fn(&T) -> U) -> Result<U, SignalError> {
self.0
.try_with(|n| f(n.as_ref().expect("Memo is missing its initial value")))
}
#[cfg(feature = "hydrate")]
pub(crate) fn subscribe(&self) {
self.0.subscribe()
}
}
#[cfg(not(feature = "stable"))]
impl<T> FnOnce<()> for Memo<T>
where
T: Clone,
{
type Output = T;
extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
self.get()
}
}
#[cfg(not(feature = "stable"))]
impl<T> FnMut<()> for Memo<T>
where
T: Clone,
{
extern "rust-call" fn call_mut(&mut self, _args: ()) -> Self::Output {
self.get()
}
}
#[cfg(not(feature = "stable"))]
impl<T> Fn<()> for Memo<T>
where
T: Clone,
{
extern "rust-call" fn call(&self, _args: ()) -> Self::Output {
self.get()
}
}