use leptos::reactive_graph::{ computed::Memo, signal::{ReadSignal, RwSignal, WriteSignal}, traits::{Get, GetUntracked, Set, With, WithUntracked}, wrappers::read::Signal, }; pub enum OptionModel where T: 'static, { T(Signal, WriteSignal, Option>), Option( Signal>, WriteSignal>, Option>>, ), } impl Default for OptionModel { fn default() -> Self { Self::new(Default::default()) } } impl Clone for OptionModel { fn clone(&self) -> Self { *self } } impl Copy for OptionModel {} impl OptionModel { fn new(value: T) -> Self { let rw_signal = RwSignal::new(Some(value)); rw_signal.into() } fn new_option(value: Option) -> Self { let rw_signal = RwSignal::new(value); rw_signal.into() } pub fn with(&self, fun: impl FnOnce(Option<&T>) -> O) -> O { match self { Self::T(read, _, _) => read.with(|value| fun(Some(value))), Self::Option(read, _, _) => read.with(|value| fun(value.as_ref())), } } pub fn with_untracked(&self, fun: impl FnOnce(Option<&T>) -> O) -> O { match self { Self::T(read, _, _) => read.with_untracked(|value| fun(Some(value))), Self::Option(read, _, _) => read.with_untracked(|value| fun(value.as_ref())), } } } impl OptionModel { pub fn get(&self) -> Option { match self { Self::T(read, _, _) => Some(read.get()), Self::Option(read, _, _) => read.get(), } } pub fn get_untracked(&self) -> Option { match self { Self::T(read, _, _) => Some(read.get_untracked()), Self::Option(read, _, _) => read.get_untracked(), } } } impl OptionModel { pub fn set(&self, value: Option) { match self { Self::T(read, write, on_write) => { write.set(value.unwrap_or_default()); if let Some(on_write) = on_write.as_ref() { on_write.set(read.get_untracked()); } } Self::Option(read, write, on_write) => { write.set(value); if let Some(on_write) = on_write.as_ref() { on_write.set(read.get_untracked()); } } } } } impl From for OptionModel { fn from(value: T) -> Self { Self::new(value) } } impl From> for OptionModel { fn from(rw_signal: RwSignal) -> Self { let (read, write) = rw_signal.split(); Self::T(read.into(), write, None) } } impl From>> for OptionModel { fn from(rw_signal: RwSignal>) -> Self { let (read, write) = rw_signal.split(); Self::Option(read.into(), write, None) } } impl From<(Signal, WriteSignal)> for OptionModel { fn from((read, write): (Signal, WriteSignal)) -> Self { Self::T(read, write, None) } } impl From<(Signal>, WriteSignal>)> for OptionModel { fn from((read, write): (Signal>, WriteSignal>)) -> Self { Self::Option(read, write, None) } } impl From<(ReadSignal, WriteSignal)> for OptionModel { fn from((read, write): (ReadSignal, WriteSignal)) -> Self { Self::T(read.into(), write, None) } } impl From<(ReadSignal>, WriteSignal>)> for OptionModel { fn from((read, write): (ReadSignal>, WriteSignal>)) -> Self { Self::Option(read.into(), write, None) } } impl From<(Memo, WriteSignal)> for OptionModel { fn from((read, write): (Memo, WriteSignal)) -> Self { Self::T(read.into(), write, None) } } impl From<(Memo>, WriteSignal>)> for OptionModel { fn from((read, write): (Memo>, WriteSignal>)) -> Self { Self::Option(read.into(), write, None) } } impl From<(Option, WriteSignal)> for OptionModel { fn from((read, write): (Option, WriteSignal)) -> Self { let mut model = Self::new(read.unwrap_or_default()); if let OptionModel::T(_, _, on_write) = &mut model { *on_write = Some(write); } model } } impl From<(Option>, WriteSignal>)> for OptionModel { fn from((read, write): (Option>, WriteSignal>)) -> Self { let mut model = Self::new_option(read.unwrap_or_default()); if let OptionModel::Option(_, _, on_write) = &mut model { *on_write = Some(write); } model } }