use std::rc::Rc;
use crate::{Memo, ReadSignal, RwSignal, Scope, UntrackedGettableSignal};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Signal<T>(SignalTypes<T>)
where
T: 'static;
impl<T> UntrackedGettableSignal<T> for Signal<T>
where
T: 'static,
{
fn get_untracked(&self) -> T
where
T: Clone,
{
match &self.0 {
SignalTypes::ReadSignal(s) => s.get_untracked(),
SignalTypes::Memo(m) => m.get_untracked(),
SignalTypes::DerivedSignal(cx, f) => cx.untrack(|| f()),
}
}
fn with_untracked<O>(&self, f: impl FnOnce(&T) -> O) -> O {
match &self.0 {
SignalTypes::ReadSignal(s) => s.with_untracked(f),
SignalTypes::Memo(s) => s.with_untracked(f),
SignalTypes::DerivedSignal(cx, v_f) => {
let mut o = None;
cx.untrack(|| o = Some(f(&v_f())));
o.unwrap()
}
}
}
}
impl<T> Signal<T>
where
T: 'static,
{
pub fn derive(cx: Scope, derived_signal: impl Fn() -> T + 'static) -> Self {
Self(SignalTypes::DerivedSignal(cx, Rc::new(derived_signal)))
}
pub fn with<U>(&self, f: impl FnOnce(&T) -> U) -> U {
match &self.0 {
SignalTypes::ReadSignal(s) => s.with(f),
SignalTypes::Memo(s) => s.with(f),
SignalTypes::DerivedSignal(_, s) => f(&s()),
}
}
pub fn get(&self) -> T
where
T: Clone,
{
match &self.0 {
SignalTypes::ReadSignal(s) => s.get(),
SignalTypes::Memo(s) => s.get(),
SignalTypes::DerivedSignal(_, s) => s(),
}
}
}
impl<T> From<ReadSignal<T>> for Signal<T> {
fn from(value: ReadSignal<T>) -> Self {
Self(SignalTypes::ReadSignal(value))
}
}
impl<T> From<RwSignal<T>> for Signal<T> {
fn from(value: RwSignal<T>) -> Self {
Self(SignalTypes::ReadSignal(value.read_only()))
}
}
impl<T> From<Memo<T>> for Signal<T> {
fn from(value: Memo<T>) -> Self {
Self(SignalTypes::Memo(value))
}
}
#[derive(Clone)]
enum SignalTypes<T>
where
T: 'static,
{
ReadSignal(ReadSignal<T>),
Memo(Memo<T>),
DerivedSignal(Scope, Rc<dyn Fn() -> T>),
}
impl<T> std::fmt::Debug for SignalTypes<T>
where
T: std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::ReadSignal(arg0) => f.debug_tuple("ReadSignal").field(arg0).finish(),
Self::Memo(arg0) => f.debug_tuple("Memo").field(arg0).finish(),
Self::DerivedSignal(_, _) => f.debug_tuple("DerivedSignal").finish(),
}
}
}
impl<T> PartialEq for SignalTypes<T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::ReadSignal(l0), Self::ReadSignal(r0)) => l0 == r0,
(Self::Memo(l0), Self::Memo(r0)) => l0 == r0,
(Self::DerivedSignal(_, l0), Self::DerivedSignal(_, r0)) => std::ptr::eq(l0, r0),
_ => false,
}
}
}
impl<T> Eq for SignalTypes<T> where T: PartialEq {}
#[cfg(not(feature = "stable"))]
impl<T> FnOnce<()> for Signal<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 Signal<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 Signal<T>
where
T: Clone,
{
extern "rust-call" fn call(&self, _args: ()) -> Self::Output {
self.get()
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum MaybeSignal<T>
where
T: 'static,
{
Static(T),
Dynamic(Signal<T>),
}
impl<T> UntrackedGettableSignal<T> for MaybeSignal<T>
where
T: 'static,
{
fn get_untracked(&self) -> T
where
T: Clone,
{
match self {
Self::Static(t) => t.clone(),
Self::Dynamic(s) => s.get_untracked(),
}
}
fn with_untracked<O>(&self, f: impl FnOnce(&T) -> O) -> O {
match self {
Self::Static(t) => f(t),
Self::Dynamic(s) => s.with_untracked(f),
}
}
}
impl<T> MaybeSignal<T>
where
T: 'static,
{
pub fn derive(cx: Scope, derived_signal: impl Fn() -> T + 'static) -> Self {
Self::Dynamic(Signal::derive(cx, derived_signal))
}
pub fn with<U>(&self, f: impl FnOnce(&T) -> U) -> U {
match &self {
Self::Static(value) => f(value),
Self::Dynamic(signal) => signal.with(f),
}
}
pub fn get(&self) -> T
where
T: Clone,
{
match &self {
Self::Static(value) => value.clone(),
Self::Dynamic(signal) => signal.get(),
}
}
}
impl<T> From<T> for MaybeSignal<T> {
fn from(value: T) -> Self {
Self::Static(value)
}
}
impl<T> From<ReadSignal<T>> for MaybeSignal<T> {
fn from(value: ReadSignal<T>) -> Self {
Self::Dynamic(value.into())
}
}
impl<T> From<RwSignal<T>> for MaybeSignal<T> {
fn from(value: RwSignal<T>) -> Self {
Self::Dynamic(value.into())
}
}
impl<T> From<Memo<T>> for MaybeSignal<T> {
fn from(value: Memo<T>) -> Self {
Self::Dynamic(value.into())
}
}
#[cfg(not(feature = "stable"))]
impl<T> FnOnce<()> for MaybeSignal<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 MaybeSignal<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 MaybeSignal<T>
where
T: Clone,
{
extern "rust-call" fn call(&self, _args: ()) -> Self::Output {
self.get()
}
}