frui_core/api/contexts/
build_ctx.rs1use crate::{app::tree::WidgetNodeRef, prelude::InheritedWidget};
2
3use std::{
4 any::Any,
5 cell::{Ref, RefMut},
6 marker::PhantomData,
7 ops::{Deref, DerefMut},
8 sync::atomic::{AtomicBool, Ordering},
9};
10
11pub(crate) static STATE_UPDATE_SUPRESSED: AtomicBool = AtomicBool::new(false);
14
15pub trait WidgetState: Sized {
16 type State: 'static;
17
18 fn create_state(&self) -> Self::State;
19
20 fn mount<'a>(&'a self, ctx: BuildContext<'a, Self>) {
25 let _ = ctx;
26 }
27
28 fn unmount<'a>(&'a self, ctx: BuildContext<'a, Self>) {
34 let _ = ctx;
35 }
36}
37
38pub type BuildContext<'a, T> = &'a _BuildContext<'a, T>;
42
43#[repr(transparent)]
44pub struct _BuildContext<'a, T> {
45 node: WidgetNodeRef,
46 _p: PhantomData<&'a T>,
47}
48
49impl<'a, T> _BuildContext<'a, T> {
50 pub fn state(&self) -> StateGuard<T::State>
51 where
52 T: WidgetState,
53 {
54 StateGuard {
55 guard: Ref::map(self.node.borrow(), |node| node.state.deref()),
56 _p: PhantomData,
57 }
58 }
59
60 pub fn state_mut(&self) -> StateGuardMut<T::State>
61 where
62 T: WidgetState,
63 {
64 if !STATE_UPDATE_SUPRESSED.load(Ordering::SeqCst) {
65 self.node.mark_dirty();
66 }
67
68 StateGuardMut {
69 guard: RefMut::map(self.node.borrow_mut(), |node| node.state.deref_mut()),
70 _p: PhantomData,
71 }
72 }
73
74 pub fn depend_on_inherited_widget<W>(&self) -> Option<InheritedState<W::State>>
79 where
80 W: InheritedWidget + WidgetState,
81 {
82 let node = self
84 .node
85 .depend_on_inherited_widget_of_key::<W::UniqueTypeId>()?;
86
87 Some(InheritedState {
88 node,
89 _p: PhantomData,
90 })
91 }
92}
93
94pub struct StateGuard<'a, T: 'static> {
95 guard: Ref<'a, dyn Any>,
96 _p: PhantomData<&'a T>,
97}
98
99impl<'a, T: 'static> Deref for StateGuard<'a, T> {
100 type Target = T;
101
102 fn deref(&self) -> &Self::Target {
103 self.guard.deref().downcast_ref().unwrap()
104 }
105}
106
107pub struct StateGuardMut<'a, T: 'static> {
108 guard: RefMut<'a, dyn Any>,
109 _p: PhantomData<&'a T>,
110}
111
112impl<'a, T: 'static> Deref for StateGuardMut<'a, T> {
113 type Target = T;
114
115 fn deref(&self) -> &Self::Target {
116 self.guard.deref().downcast_ref().unwrap()
117 }
118}
119
120impl<'a, T: 'static> std::ops::DerefMut for StateGuardMut<'a, T> {
121 fn deref_mut(&mut self) -> &mut Self::Target {
122 self.guard.deref_mut().downcast_mut().unwrap()
123 }
124}
125
126pub struct InheritedState<'a, T: 'static> {
127 pub(crate) node: WidgetNodeRef,
128 pub(crate) _p: PhantomData<&'a T>,
129}
130
131impl<'a, T: 'static> InheritedState<'a, T> {
132 pub fn as_ref(&'a self) -> InheritedStateRef<'a, T> {
133 InheritedStateRef {
134 state: Ref::map(self.node.borrow(), |node| node.state.deref()),
135 _p: PhantomData,
136 }
137 }
138
139 pub fn as_mut(&'a mut self) -> InheritedStateRefMut<'a, T> {
140 if !STATE_UPDATE_SUPRESSED.load(Ordering::SeqCst) {
141 self.node.mark_dirty();
142 self.node.mark_dependent_widgets_as_dirty();
143 }
144
145 InheritedStateRefMut {
146 state: RefMut::map(self.node.borrow_mut(), |node| node.state.deref_mut()),
147 _p: PhantomData,
148 }
149 }
150}
151
152pub struct InheritedStateRef<'a, T: 'static> {
153 state: Ref<'a, dyn Any>,
154 _p: PhantomData<T>,
155}
156
157impl<'a, T> Deref for InheritedStateRef<'a, T> {
158 type Target = T;
159
160 fn deref(&self) -> &Self::Target {
161 self.state.downcast_ref().unwrap()
162 }
163}
164
165pub struct InheritedStateRefMut<'a, T: 'static> {
166 state: RefMut<'a, dyn Any>,
167 _p: PhantomData<T>,
168}
169
170impl<'a, T> Deref for InheritedStateRefMut<'a, T> {
171 type Target = T;
172
173 fn deref(&self) -> &Self::Target {
174 self.state.downcast_ref().unwrap()
175 }
176}
177
178impl<'a, T> DerefMut for InheritedStateRefMut<'a, T> {
179 fn deref_mut(&mut self) -> &mut Self::Target {
180 self.state.downcast_mut().unwrap()
181 }
182}
183
184pub(crate) use sealed::WidgetStateOS;
185
186mod sealed {
187 use std::{
188 any::{Any, TypeId},
189 cell::RefCell,
190 };
191
192 use crate::api::contexts::Context;
193
194 use super::_BuildContext;
195
196 pub trait WidgetStateOS {
198 fn state_type_id(&self) -> TypeId;
199
200 fn create_state(&self) -> Box<dyn Any>;
201 fn mount(&self, build_ctx: &Context);
202 fn unmount(&self, build_ctx: &Context);
203 }
204
205 impl<T> WidgetStateOS for T {
206 default fn state_type_id(&self) -> TypeId {
207 struct WidgetHasNoState;
208 TypeId::of::<WidgetHasNoState>()
209 }
210
211 default fn create_state(&self) -> Box<dyn Any> {
212 Box::new(RefCell::new(()))
213 }
214
215 default fn mount(&self, _ctx: &Context) {}
216 default fn unmount(&self, _ctx: &Context) {}
217 }
218
219 impl<T: super::WidgetState> WidgetStateOS for T {
220 fn state_type_id(&self) -> TypeId {
221 TypeId::of::<T::State>()
222 }
223
224 fn create_state(&self) -> Box<dyn Any> {
225 Box::new(T::create_state(&self))
226 }
227
228 fn mount(&self, ctx: &Context) {
229 let ctx = unsafe { std::mem::transmute::<&Context, &_BuildContext<T>>(ctx) };
230
231 T::mount(&self, ctx)
232 }
233
234 fn unmount(&self, ctx: &Context) {
235 let ctx = unsafe { std::mem::transmute::<&Context, &_BuildContext<T>>(ctx) };
236
237 T::unmount(&self, ctx)
238 }
239 }
240}