euv_core/reactive/lazy/
impl.rs1use super::*;
2
3impl<T> Default for LoadState<T> {
4 fn default() -> Self {
5 LoadState::Pending
6 }
7}
8
9impl<T: PartialEq> PartialEq for LoadState<T> {
10 fn eq(&self, other: &Self) -> bool {
11 match (self, other) {
12 (LoadState::Pending, LoadState::Pending) => true,
13 (LoadState::Loading, LoadState::Loading) => true,
14 (LoadState::Loaded(a), LoadState::Loaded(b)) => a == b,
15 (LoadState::Failed(a), LoadState::Failed(b)) => a == b,
16 _ => false,
17 }
18 }
19}
20
21impl<T: Clone + PartialEq + 'static> LazyComponent<T> {
22 pub fn new(factory: impl Fn() -> T + 'static) -> Self {
25 Self {
26 state: Signal::create(LoadState::Pending),
27 factory: Rc::new(factory),
28 }
29 }
30
31 pub fn state(&self) -> Signal<LoadState<T>> {
35 self.state.clone()
36 }
37
38 pub fn current(&self) -> LoadState<T> {
41 self.state.get()
42 }
43
44 pub fn is_resolved(&self) -> bool {
47 matches!(
48 self.state.get(),
49 LoadState::Loaded(_) | LoadState::Failed(_)
50 )
51 }
52
53 pub fn is_pending(&self) -> bool {
56 matches!(self.state.get(), LoadState::Pending)
57 }
58
59 pub fn prefetch(&self) {
63 match self.state.get() {
64 LoadState::Pending => {
65 self.state.set(LoadState::Loading);
66 self.invoke_factory();
71 }
72 _ => {}
73 }
74 }
75
76 pub fn get(&self) -> Option<T> {
79 match self.state.get() {
80 LoadState::Loaded(value) => Some(value),
81 LoadState::Failed(_) => None,
82 LoadState::Pending | LoadState::Loading => {
83 self.invoke_factory();
84 match self.state.get() {
85 LoadState::Loaded(value) => Some(value),
86 _ => None,
87 }
88 }
89 }
90 }
91
92 pub fn loaded(&self) -> Option<T> {
101 match self.state.get() {
102 LoadState::Loaded(value) => Some(value),
103 LoadState::Pending | LoadState::Loading | LoadState::Failed(_) => None,
104 }
105 }
106
107 pub fn reset(&self) {
110 self.state.set(LoadState::Pending);
111 }
112
113 pub fn change_factory(&self, factory: impl Fn() -> T + 'static) {
117 let _ = factory;
124 self.reset();
125 }
126
127 fn invoke_factory(&self) {
128 let result: Result<T, Box<dyn std::any::Any + Send>> =
129 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| (self.factory)()));
130 match result {
131 Ok(value) => {
132 self.state.set(LoadState::Loaded(value));
133 }
134 Err(payload) => {
135 let message: String = if let Some(s) = payload.downcast_ref::<&'static str>() {
136 (*s).to_string()
137 } else if let Some(s) = payload.downcast_ref::<String>() {
138 s.clone()
139 } else {
140 String::from("factory panicked")
141 };
142 self.state.set(LoadState::Failed(message));
143 }
144 }
145 }
146}
147
148impl<T: Clone + PartialEq + 'static> Clone for LazyComponent<T> {
149 fn clone(&self) -> Self {
150 Self {
151 state: self.state.clone(),
152 factory: self.factory.clone(),
153 }
154 }
155}
156
157impl<T: Clone + PartialEq + std::fmt::Debug + 'static> std::fmt::Debug for LazyComponent<T> {
158 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159 f.debug_struct("LazyComponent")
160 .field("state", &self.state.get())
161 .finish()
162 }
163}