maycoon_core/signal/
mod.rs1use crate::app::context::AppContext;
2use crate::reference::Ref;
3use crate::signal::fixed::FixedSignal;
4use crate::signal::listener::Listener;
5use crate::signal::map::MapSignal;
6use std::rc::Rc;
7
8pub mod fixed;
10
11pub mod memoized;
13
14pub mod state;
16
17pub mod map;
19
20pub mod eval;
22
23pub mod listener;
25
26pub type BoxedSignal<T> = Box<dyn Signal<T>>;
28
29pub trait Signal<T: 'static>: 'static {
44 fn get(&self) -> Ref<'_, T>;
46
47 fn set_value(&self, value: T);
51
52 fn listen(self, listener: Box<dyn Fn(Ref<'_, T>)>) -> Self
54 where
55 Self: Sized;
56
57 fn notify(&self);
60
61 #[inline(always)]
63 fn set(&self, value: T) {
64 tracing::trace_span!("set signal").in_scope(|| {
65 self.set_value(value);
66 self.notify();
67 });
68 }
69
70 #[inline(always)]
72 fn maybe(&self) -> MaybeSignal<T>
73 where
74 Self: Sized,
75 {
76 MaybeSignal::signal(self.dyn_clone())
77 }
78
79 #[inline(always)]
81 fn map<U: 'static>(&self, map: impl Fn(Ref<T>) -> Ref<U> + 'static) -> MapSignal<T, U>
82 where
83 Self: Sized,
84 {
85 MapSignal::new(self.dyn_clone(), map)
86 }
87
88 #[inline(always)]
92 fn hook(self, context: &AppContext) -> Self
93 where
94 Self: Sized,
95 {
96 context.use_signal(self)
97 }
98
99 fn dyn_clone(&self) -> Box<dyn Signal<T>>;
103}
104
105pub enum MaybeSignal<T: 'static> {
107 Signal(BoxedSignal<T>),
109 Value(Rc<T>),
111}
112
113impl<T: 'static> MaybeSignal<T> {
114 #[inline(always)]
116 pub const fn signal(signal: BoxedSignal<T>) -> Self {
117 Self::Signal(signal)
118 }
119
120 #[inline(always)]
122 pub fn value(value: T) -> Self {
123 Self::Value(Rc::new(value))
124 }
125
126 #[inline(always)]
131 pub fn get(&self) -> Ref<'_, T> {
132 match self {
133 MaybeSignal::Signal(signal) => signal.get(),
134 MaybeSignal::Value(value) => Ref::Borrow(value.as_ref()),
135 }
136 }
137
138 #[inline(always)]
140 pub fn as_signal(&self) -> Option<BoxedSignal<T>> {
141 match self {
142 MaybeSignal::Signal(signal) => Some(signal.dyn_clone()),
143 _ => None,
144 }
145 }
146
147 #[inline(always)]
151 pub fn into_signal(self) -> BoxedSignal<T> {
152 match self {
153 MaybeSignal::Signal(signal) => signal,
154 MaybeSignal::Value(value) => Box::new(FixedSignal::from(value)),
155 }
156 }
157
158 #[inline(always)]
162 pub fn map<U: 'static>(self, map: impl Fn(Ref<T>) -> Ref<U> + 'static) -> MaybeSignal<U> {
163 let signal = self.into_signal();
164
165 MaybeSignal::signal(Box::new(MapSignal::new(signal, map)))
166 }
167}
168
169impl<T: Default + 'static> Default for MaybeSignal<T> {
170 #[inline(always)]
171 fn default() -> Self {
172 Self::value(T::default())
173 }
174}
175
176impl<T: 'static> From<T> for MaybeSignal<T> {
177 #[inline(always)]
178 fn from(value: T) -> Self {
179 Self::value(value)
180 }
181}
182
183impl<T: 'static> From<BoxedSignal<T>> for MaybeSignal<T> {
184 #[inline(always)]
185 fn from(signal: BoxedSignal<T>) -> Self {
186 Self::signal(signal)
187 }
188}
189
190impl<'a, T: 'static> From<&'a BoxedSignal<T>> for MaybeSignal<T> {
191 #[inline(always)]
192 fn from(value: &'a BoxedSignal<T>) -> Self {
193 Self::signal(value.dyn_clone())
194 }
195}
196
197impl<T: 'static, U: 'static> From<MapSignal<T, U>> for MaybeSignal<U> {
198 #[inline(always)]
199 fn from(value: MapSignal<T, U>) -> Self {
200 Self::signal(Box::new(value))
201 }
202}