1use std::{
2 any::{Any, TypeId},
3 cell::{Cell, RefCell, UnsafeCell},
4 collections::HashMap,
5 fmt,
6 hash::{Hash, Hasher},
7 marker::PhantomData,
8 mem,
9 ops::Deref,
10 rc::Rc,
11};
12
13pub use actuate_macros::Data;
14use thiserror::Error;
15
16pub mod prelude {
17 pub use crate::{
18 use_context, use_drop, use_memo, use_mut, use_provider, use_ref, Compose, Cow, Data,
19 DataField, DynCompose, FieldWrap, FnField, Map, Memo, Mut, Ref, RefMap, Scope, ScopeState,
20 StateField, StaticField,
21 };
22}
23
24pub enum Cow<'a, T> {
29 Borrowed(RefMap<'a, T>),
30 Owned(T),
31}
32
33impl<'a, T> Cow<'a, T> {
34 pub fn into_owned(self) -> T
35 where
36 T: Clone,
37 {
38 match self {
39 Cow::Borrowed(value) => (*value).clone(),
40 Cow::Owned(value) => value,
41 }
42 }
43}
44
45impl<T> Deref for Cow<'_, T> {
46 type Target = T;
47
48 fn deref(&self) -> &Self::Target {
49 match self {
50 Cow::Borrowed(ref_map) => &*ref_map,
51 Cow::Owned(value) => &value,
52 }
53 }
54}
55
56impl<'a, T> From<RefMap<'a, T>> for Cow<'a, T> {
57 fn from(value: RefMap<'a, T>) -> Self {
58 Cow::Borrowed(value)
59 }
60}
61
62impl<'a, T> From<Ref<'a, T>> for Cow<'a, T> {
63 fn from(value: Ref<'a, T>) -> Self {
64 RefMap::from(value).into()
65 }
66}
67
68impl<'a, T> From<Map<'a, T>> for Cow<'a, T> {
69 fn from(value: Map<'a, T>) -> Self {
70 RefMap::from(value).into()
71 }
72}
73
74pub enum RefMap<'a, T: ?Sized> {
76 Ref(Ref<'a, T>),
77 Map(Map<'a, T>),
78}
79
80impl<T: ?Sized> Clone for RefMap<'_, T> {
81 fn clone(&self) -> Self {
82 match self {
83 RefMap::Ref(r) => RefMap::Ref(r.clone()),
84 RefMap::Map(map) => RefMap::Map(map.clone()),
85 }
86 }
87}
88
89impl<T: ?Sized> Deref for RefMap<'_, T> {
90 type Target = T;
91
92 fn deref(&self) -> &Self::Target {
93 match self {
94 RefMap::Ref(r) => &*r,
95 RefMap::Map(map) => &*map,
96 }
97 }
98}
99
100impl<T: Hash + ?Sized> Hash for RefMap<'_, T> {
101 fn hash<H: Hasher>(&self, state: &mut H) {
102 (**self).hash(state);
103 }
104}
105
106impl<'a, T: ?Sized> From<Ref<'a, T>> for RefMap<'a, T> {
107 fn from(value: Ref<'a, T>) -> Self {
108 RefMap::Ref(value)
109 }
110}
111
112impl<'a, T: ?Sized> From<Map<'a, T>> for RefMap<'a, T> {
113 fn from(value: Map<'a, T>) -> Self {
114 RefMap::Map(value)
115 }
116}
117
118unsafe impl<T: Data> Data for RefMap<'_, T> {
119 type Id = RefMap<'static, T::Id>;
120}
121
122impl<C: Compose> Compose for RefMap<'_, C> {
123 fn compose(cx: Scope<Self>) -> impl Compose {
124 cx.is_container.set(true);
125
126 let state = use_ref(&cx, || {
127 let mut state = ScopeData::default();
128 state.contexts = cx.contexts.clone();
129 state
130 });
131
132 state.is_parent_changed.set(cx.is_parent_changed.get());
133
134 unsafe { (**cx.me()).any_compose(state) }
135 }
136}
137
138pub struct Map<'a, T: ?Sized> {
140 ptr: *const (),
141 map_fn: *const (),
142 deref_fn: fn(*const (), *const ()) -> &'a T,
143}
144
145impl<T: ?Sized> Clone for Map<'_, T> {
146 fn clone(&self) -> Self {
147 Self {
148 ptr: self.ptr,
149 map_fn: self.map_fn,
150 deref_fn: self.deref_fn,
151 }
152 }
153}
154
155impl<T: ?Sized> Copy for Map<'_, T> {}
156
157impl<'a, T: ?Sized> Deref for Map<'a, T> {
158 type Target = T;
159
160 fn deref(&self) -> &Self::Target {
161 (self.deref_fn)(self.ptr, self.map_fn)
162 }
163}
164
165impl<T: Hash + ?Sized> Hash for Map<'_, T> {
166 fn hash<H: Hasher>(&self, state: &mut H) {
167 (**self).hash(state);
168 }
169}
170
171impl<C: Compose> Compose for Map<'_, C> {
174 fn compose(cx: Scope<Self>) -> impl Compose {
175 cx.is_container.set(true);
176
177 let state = use_ref(&cx, || {
178 let mut state = ScopeData::default();
179 state.contexts = cx.contexts.clone();
180 state
181 });
182
183 state.is_parent_changed.set(cx.is_parent_changed.get());
184
185 unsafe { (**cx.me()).any_compose(state) }
186 }
187
188 #[cfg(feature = "tracing")]
189 fn name() -> std::borrow::Cow<'static, str> {
190 C::name()
191 }
192}
193
194#[derive(Hash)]
196pub struct Ref<'a, T: ?Sized> {
197 value: &'a T,
198 generation: *const Cell<u64>,
199}
200
201impl<'a, T> Ref<'a, T> {
202 pub fn map<U: ?Sized>(me: Self, f: fn(&T) -> &U) -> Map<'a, U> {
204 Map {
205 ptr: me.value as *const _ as _,
206 map_fn: f as _,
207 deref_fn: |ptr, g| unsafe {
208 let g: fn(&T) -> &U = mem::transmute(g);
209 g(&*(ptr as *const T))
210 },
211 }
212 }
213}
214
215impl<T: ?Sized> Clone for Ref<'_, T> {
216 fn clone(&self) -> Self {
217 Self {
218 value: self.value,
219 generation: self.generation,
220 }
221 }
222}
223
224impl<T: ?Sized> Copy for Ref<'_, T> {}
225
226impl<T: ?Sized> Deref for Ref<'_, T> {
227 type Target = T;
228
229 fn deref(&self) -> &Self::Target {
230 self.value
231 }
232}
233
234impl<T> Memoize for Ref<'_, T> {
235 type Value = u64;
236
237 fn memoized(self) -> Self::Value {
238 unsafe { &*self.generation }.get()
239 }
240}
241
242pub struct Mut<'a, T> {
244 ptr: *mut T,
245 scope_is_changed: *const Cell<bool>,
246 generation: *const Cell<u64>,
247 phantom: PhantomData<&'a ()>,
248}
249
250impl<'a, T: 'static> Mut<'a, T> {
251 pub fn update(self, f: impl FnOnce(&mut T) + 'static) {
253 let ptr = self.ptr;
254 let is_changed = self.scope_is_changed;
255 let generation = self.generation;
256
257 Runtime::current().update(move || {
258 let value = unsafe { &mut *ptr };
259 f(value);
260
261 unsafe {
262 (*is_changed).set(true);
263
264 let g = &*generation;
265 g.set(g.get() + 1)
266 }
267 });
268 }
269
270 pub fn with(self, f: impl FnOnce(&mut T) + 'static) {
272 let mut cell = Some(f);
273 let ptr = self.ptr;
274
275 Runtime::current().update(move || {
276 let value = unsafe { &mut *ptr };
277 cell.take().unwrap()(value);
278 });
279 }
280
281 pub fn as_ref(self) -> Ref<'a, T> {
283 Ref {
284 value: unsafe { &*self.ptr },
285 generation: self.generation,
286 }
287 }
288}
289
290impl<T> Clone for Mut<'_, T> {
291 fn clone(&self) -> Self {
292 Self {
293 ptr: self.ptr,
294 scope_is_changed: self.scope_is_changed,
295 generation: self.generation,
296 phantom: self.phantom,
297 }
298 }
299}
300
301impl<T> Copy for Mut<'_, T> {}
302
303impl<T> Deref for Mut<'_, T> {
304 type Target = T;
305
306 fn deref(&self) -> &Self::Target {
307 unsafe { &*self.ptr }
308 }
309}
310
311impl<T> Hash for Mut<'_, T> {
312 fn hash<H: Hasher>(&self, state: &mut H) {
313 self.ptr.hash(state);
314 self.generation.hash(state);
315 }
316}
317
318pub struct Update {
320 f: Box<dyn FnOnce()>,
321}
322
323impl Update {
324 pub unsafe fn apply(self) {
329 (self.f)();
330 }
331}
332
333#[derive(Clone)]
335pub struct Runtime {
336 updater: Rc<dyn Updater>,
337}
338
339impl Runtime {
340 pub fn current() -> Self {
345 RUNTIME.with(|runtime| {
346 runtime
347 .borrow()
348 .as_ref()
349 .expect("Runtime::current() called outside of a runtime")
350 .clone()
351 })
352 }
353
354 pub fn enter(&self) {
356 RUNTIME.with(|runtime| {
357 *runtime.borrow_mut() = Some(self.clone());
358 });
359 }
360
361 pub fn update(&self, f: impl FnOnce() + 'static) {
363 self.updater.update(Update { f: Box::new(f) });
364 }
365}
366
367thread_local! {
368 static RUNTIME: RefCell<Option<Runtime>> = RefCell::new(None);
369}
370
371#[derive(Clone, Default)]
373struct Contexts {
374 values: HashMap<TypeId, Rc<dyn Any>>,
375}
376
377pub type ScopeState<'a> = &'a ScopeData<'a>;
378
379#[derive(Default)]
381pub struct ScopeData<'a> {
382 hooks: UnsafeCell<Vec<Box<dyn Any>>>,
383 hook_idx: Cell<usize>,
384 is_changed: Cell<bool>,
385 is_parent_changed: Cell<bool>,
386 is_empty: Cell<bool>,
387 is_container: Cell<bool>,
388 contexts: RefCell<Contexts>,
389 drops: RefCell<Vec<usize>>,
390 generation: Cell<u64>,
391 _marker: PhantomData<&'a fn(ScopeData<'a>) -> ScopeData<'a>>,
392}
393
394impl ScopeData<'_> {
395 pub fn set_changed(&self) {
396 self.is_changed.set(true);
397 }
398
399 pub fn is_parent_changed(&self) -> bool {
400 self.is_parent_changed.get()
401 }
402}
403
404impl Drop for ScopeData<'_> {
405 fn drop(&mut self) {
406 for idx in &*self.drops.borrow() {
407 let hooks = unsafe { &mut *self.hooks.get() };
408 let any = hooks.get_mut(*idx).unwrap();
409 (**any).downcast_mut::<Box<dyn FnMut()>>().unwrap()();
410 }
411 }
412}
413
414pub struct Scope<'a, C: ?Sized> {
416 me: &'a C,
417 state: ScopeState<'a>,
418}
419
420impl<'a, C> Scope<'a, C> {
421 pub fn me(&self) -> Ref<'a, C> {
422 Ref {
423 value: self.me,
424 generation: &self.state.generation,
425 }
426 }
427
428 pub unsafe fn me_as_ref(self) -> &'a C {
429 self.me
430 }
431
432 pub fn state(&self) -> &'a ScopeData {
433 self.state
434 }
435}
436
437impl<C> Clone for Scope<'_, C> {
438 fn clone(&self) -> Self {
439 Self {
440 me: self.me,
441 state: self.state,
442 }
443 }
444}
445
446impl<C> Copy for Scope<'_, C> {}
447
448impl<'a, C> Deref for Scope<'a, C> {
449 type Target = ScopeState<'a>;
450
451 fn deref(&self) -> &Self::Target {
452 &self.state
453 }
454}
455
456pub fn use_ref<T: 'static>(cx: ScopeState, make_value: impl FnOnce() -> T) -> &T {
460 let hooks = unsafe { &mut *cx.hooks.get() };
461
462 let idx = cx.hook_idx.get();
463 cx.hook_idx.set(idx + 1);
464
465 let any = if idx >= hooks.len() {
466 hooks.push(Box::new(make_value()));
467 hooks.last().unwrap()
468 } else {
469 hooks.get(idx).unwrap()
470 };
471 (**any).downcast_ref().unwrap()
472}
473
474struct MutState<T> {
475 value: T,
476 generation: Cell<u64>,
477}
478
479pub fn use_mut<T: 'static>(cx: ScopeState, make_value: impl FnOnce() -> T) -> Mut<'_, T> {
483 let hooks = unsafe { &mut *cx.hooks.get() };
484
485 let idx = cx.hook_idx.get();
486 cx.hook_idx.set(idx + 1);
487
488 let any = if idx >= hooks.len() {
489 let state = MutState {
490 value: make_value(),
491 generation: Cell::new(0),
492 };
493 hooks.push(Box::new(state));
494 hooks.last_mut().unwrap()
495 } else {
496 hooks.get_mut(idx).unwrap()
497 };
498 let state: &mut MutState<T> = any.downcast_mut().unwrap();
499
500 Mut {
501 ptr: &mut state.value as *mut T,
502 scope_is_changed: &cx.is_changed,
503 generation: &state.generation,
504 phantom: PhantomData::<&()>,
505 }
506}
507
508pub fn use_callback<'a, T, R>(
509 cx: ScopeState<'a>,
510 f: impl FnMut(T) -> R + 'a,
511) -> &'a Rc<dyn Fn(T) -> R + 'a>
512where
513 T: 'static,
514 R: 'static,
515{
516 let f_cell: Option<Box<dyn FnMut(T) -> R + 'a>> = Some(Box::new(f));
517 let mut f_cell: Option<Box<dyn FnMut(T) -> R>> = unsafe { mem::transmute(f_cell) };
518
519 let callback = use_ref(cx, || Rc::new(RefCell::new(f_cell.take().unwrap()))).clone();
520
521 if let Some(f) = f_cell {
522 *callback.borrow_mut() = f;
523 }
524
525 use_ref(cx, move || {
526 let f = callback.clone();
527 Rc::new(move |input| f.borrow_mut()(input)) as Rc<dyn Fn(T) -> R>
528 })
529}
530
531#[derive(Error)]
532pub struct ContextError<T> {
533 _marker: PhantomData<T>,
534}
535
536impl<T> fmt::Debug for ContextError<T> {
537 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
538 f.debug_tuple("ContextError")
539 .field(&std::any::type_name::<T>())
540 .finish()
541 }
542}
543
544impl<T> fmt::Display for ContextError<T> {
545 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
546 f.write_str(&format!(
547 "Context value not found for type: {}",
548 std::any::type_name::<T>()
549 ))
550 }
551}
552
553pub fn use_context<T: 'static>(cx: &ScopeData) -> Result<Rc<T>, ContextError<T>> {
558 let Some(any) = cx.contexts.borrow().values.get(&TypeId::of::<T>()).cloned() else {
559 return Err(ContextError {
560 _marker: PhantomData,
561 });
562 };
563
564 Ok(any.downcast().unwrap())
565}
566
567pub fn use_provider<'a, T: 'static>(cx: ScopeState<'_>, make_value: impl FnOnce() -> T) -> Rc<T> {
571 let r = use_ref(cx, || {
573 let value = Rc::new(make_value());
574 cx.contexts
575 .borrow_mut()
576 .values
577 .insert(TypeId::of::<T>(), value.clone());
578 value
579 });
580 (*r).clone()
581}
582
583pub trait Memoize {
584 type Value: PartialEq + 'static;
585
586 fn memoized(self) -> Self::Value;
587}
588
589impl<T: PartialEq + 'static> Memoize for T {
590 type Value = T;
591
592 fn memoized(self) -> Self::Value {
593 self
594 }
595}
596
597impl<T> Memoize for Mut<'_, T> {
598 type Value = u64;
599
600 fn memoized(self) -> Self::Value {
601 unsafe { &*self.generation }.get()
602 }
603}
604
605pub fn use_memo<'a, D, T>(
609 cx: ScopeState<'_>,
610 dependency: D,
611 make_value: impl FnOnce() -> T,
612) -> Ref<T>
613where
614 D: Memoize,
615 T: 'static,
616{
617 let mut dependency_cell = Some(dependency.memoized());
618
619 let mut make_value_cell = Some(make_value);
620 let value_mut = use_mut(cx, || make_value_cell.take().unwrap()());
621
622 let hash_mut = use_mut(cx, || dependency_cell.take().unwrap());
623
624 if let Some(make_value) = make_value_cell {
625 if let Some(dependency) = dependency_cell.take() {
626 if dependency != *hash_mut {
627 let value = make_value();
628 value_mut.with(move |update| *update = value);
629
630 hash_mut.with(move |dst| *dst = dependency);
631 }
632 }
633 }
634
635 value_mut.as_ref()
636}
637
638pub fn use_drop<'a>(cx: ScopeState<'_>, f: impl FnOnce() + 'static) {
639 let mut f_cell = Some(f);
640
641 let idx = cx.hook_idx.get();
642 use_ref(cx, || {
643 cx.drops.borrow_mut().push(idx);
644 let f = Box::new(move || {
645 f_cell.take().unwrap()();
646 }) as Box<dyn FnMut()>;
647 f
648 });
649}
650
651pub unsafe trait Data: Sized {
655 type Id: 'static;
656
657 unsafe fn reborrow(self, ptr: *mut ()) {
658 let x = ptr as *mut Self;
659 *x = self;
660 }
661}
662
663unsafe impl Data for () {
664 type Id = ();
665}
666
667unsafe impl Data for i32 {
669 type Id = i32;
670}
671
672unsafe impl Data for String {
673 type Id = Self;
674}
675
676unsafe impl Data for &str {
677 type Id = &'static str;
678}
679
680unsafe impl<T: Data> Data for Vec<T> {
681 type Id = Vec<T::Id>;
682}
683
684unsafe impl<T: ?Sized + Data> Data for &T {
685 type Id = &'static T::Id;
686}
687
688unsafe impl<T: Data> Data for Option<T> {
689 type Id = Option<T::Id>;
690}
691
692unsafe impl<T: Data + ?Sized> Data for Ref<'_, T> {
693 type Id = PhantomData<Ref<'static, T::Id>>;
694}
695
696unsafe impl<T: Data + ?Sized> Data for Map<'_, T> {
697 type Id = PhantomData<Map<'static, T::Id>>;
698}
699
700unsafe impl<T: Data> Data for Mut<'_, T> {
701 type Id = PhantomData<Mut<'static, T::Id>>;
702}
703
704unsafe impl Data for DynCompose<'_> {
705 type Id = PhantomData<DynCompose<'static>>;
706}
707
708pub struct FieldWrap<T>(pub T);
709
710#[doc(hidden)]
711pub unsafe trait StateField {
712 fn check(&self) {
713 let _ = self;
714 }
715}
716
717unsafe impl<T: 'static> StateField for FieldWrap<&T> {}
718
719#[doc(hidden)]
720pub unsafe trait FnField<Marker> {
721 fn check(&self) {
722 let _ = self;
723 }
724}
725
726macro_rules! impl_data_for_fns {
727 ($($t:tt),*) => {
728 unsafe impl<$($t,)* F: Fn($($t,)*)> FnField<fn($($t,)*)> for &FieldWrap<F> {}
729 }
730}
731
732impl_data_for_fns!();
733impl_data_for_fns!(T1);
734impl_data_for_fns!(T1, T2);
735impl_data_for_fns!(T1, T2, T3);
736impl_data_for_fns!(T1, T2, T3, T4);
737impl_data_for_fns!(T1, T2, T3, T4, T5);
738impl_data_for_fns!(T1, T2, T3, T4, T5, T6);
739impl_data_for_fns!(T1, T2, T3, T4, T5, T6, T7);
740impl_data_for_fns!(T1, T2, T3, T4, T5, T6, T7, T8);
741
742#[doc(hidden)]
743pub unsafe trait DataField {
744 fn check(&self) {
745 let _ = self;
746 }
747}
748
749unsafe impl<T: Data> DataField for &FieldWrap<T> {}
750
751#[doc(hidden)]
752pub unsafe trait StaticField {
753 fn check(&self) {
754 let _ = self;
755 }
756}
757
758unsafe impl<T: 'static> StaticField for &&FieldWrap<T> {}
759
760pub trait Compose: Data {
764 fn compose(cx: Scope<Self>) -> impl Compose;
765
766 #[cfg(feature = "tracing")]
767 #[doc(hidden)]
768 fn name() -> std::borrow::Cow<'static, str> {
769 std::any::type_name::<Self>().into()
770 }
771}
772
773impl Compose for () {
774 fn compose(cx: Scope<Self>) -> impl Compose {
775 cx.is_empty.set(true);
776 }
777}
778
779impl<C: Compose> Compose for &C {
780 fn compose(cx: Scope<Self>) -> impl Compose {
781 unsafe {
782 (**cx.me()).any_compose(&cx);
783 }
784 }
785}
786
787impl<C: Compose> Compose for Option<C> {
788 fn compose(cx: Scope<Self>) -> impl Compose {
789 cx.is_container.set(true);
790
791 let state_cell: &RefCell<Option<ScopeData>> = use_ref(&cx, || RefCell::new(None));
792 let mut state_cell = state_cell.borrow_mut();
793
794 if let Some(content) = &*cx.me() {
795 if let Some(state) = &*state_cell {
796 state.is_parent_changed.set(cx.is_parent_changed.get());
797 unsafe {
798 content.any_compose(state);
799 }
800 } else {
801 let mut state = ScopeData::default();
802 state.contexts = cx.contexts.clone();
803 *state_cell = Some(state);
804 unsafe {
805 content.any_compose(&*state_cell.as_ref().unwrap());
806 }
807 }
808 } else {
809 *state_cell = None;
810 }
811 }
812}
813
814pub fn from_iter<'a, I, C>(iter: I, f: impl Fn(I::Item) -> C + 'a) -> FromIter<'a, I, I::Item, C>
815where
816 I: IntoIterator + Clone + Data,
817 I::Item: Clone + Data,
818 C: Compose,
819{
820 FromIter {
821 iter,
822 f: Box::new(f),
823 }
824}
825
826pub struct FromIter<'a, I, Item, C> {
827 iter: I,
828 f: Box<dyn Fn(Item) -> C + 'a>,
829}
830
831unsafe impl<I, Item, C> Data for FromIter<'_, I, Item, C>
832where
833 I: Data,
834 Item: Data,
835 C: Data,
836{
837 type Id = FromIter<'static, I::Id, Item::Id, C::Id>;
838}
839
840impl<I, Item, C> Compose for FromIter<'_, I, Item, C>
841where
842 I: IntoIterator<Item = Item> + Clone + Data,
843 Item: Clone + Data,
844 C: Compose,
845{
846 fn compose(cx: Scope<Self>) -> impl Compose {
847 cx.is_container.set(true);
848
849 let states = use_ref(&cx, || RefCell::new(Vec::new()));
850 let mut states = states.borrow_mut();
851
852 let items: Vec<_> = cx.me().iter.clone().into_iter().collect();
853 if items.len() >= states.len() {
854 for _ in states.len()..items.len() {
855 states.push(ScopeData::default());
856 }
857 } else {
858 for _ in items.len()..states.len() {
859 states.pop();
860 }
861 }
862
863 for (item, state) in items.into_iter().zip(&*states) {
864 *state.contexts.borrow_mut() = cx.contexts.borrow().clone();
865 state.is_parent_changed.set(cx.is_parent_changed.get());
866
867 unsafe { (cx.me().f)(item).any_compose(state) }
868 }
869 }
870}
871
872#[derive(Data)]
873pub struct Memo<T, C> {
874 dependency: T,
875 content: C,
876}
877
878impl<T, C> Memo<T, C> {
879 pub fn new(dependency: impl Memoize<Value = T>, content: C) -> Self {
880 Self {
881 dependency: dependency.memoized(),
882 content,
883 }
884 }
885}
886
887impl<T, C> Compose for Memo<T, C>
888where
889 T: Clone + Data + PartialEq + 'static,
890 C: Compose,
891{
892 fn compose(cx: Scope<Self>) -> impl Compose {
893 let last = use_ref(&cx, RefCell::default);
894 let mut last = last.borrow_mut();
895 if let Some(last) = &mut *last {
896 if cx.me().dependency != *last {
897 *last = cx.me().dependency.clone();
898 cx.is_parent_changed.set(true);
899 }
900 } else {
901 *last = Some(cx.me().dependency.clone());
902 cx.is_parent_changed.set(true);
903 }
904
905 Ref::map(cx.me(), |me| &me.content)
906 }
907
908 #[cfg(feature = "tracing")]
909 fn name() -> std::borrow::Cow<'static, str> {
910 format!("Memo<{}>", C::name()).into()
911 }
912}
913
914pub struct DynCompose<'a> {
916 compose: UnsafeCell<Option<Box<dyn AnyCompose + 'a>>>,
917}
918
919impl<'a> DynCompose<'a> {
920 pub fn new(content: impl Compose + 'a) -> Self {
921 Self {
922 compose: UnsafeCell::new(Some(Box::new(content))),
923 }
924 }
925}
926
927struct DynComposeState {
928 compose: Box<dyn AnyCompose>,
929 data_id: TypeId,
930}
931
932impl<'a> Compose for DynCompose<'a> {
933 fn compose(cx: Scope<Self>) -> impl Compose {
934 cx.is_container.set(true);
935
936 let cell: &UnsafeCell<Option<DynComposeState>> = use_ref(&cx, || UnsafeCell::new(None));
937 let cell = unsafe { &mut *cell.get() };
938
939 let inner = unsafe { &mut *cx.me().compose.get() };
940
941 let child_state = use_ref(&cx, ScopeData::default);
942
943 *child_state.contexts.borrow_mut() = cx.contexts.borrow().clone();
944 child_state
945 .is_parent_changed
946 .set(cx.is_parent_changed.get());
947
948 if let Some(any_compose) = inner.take() {
949 let mut compose: Box<dyn AnyCompose> = unsafe { mem::transmute(any_compose) };
950
951 if let Some(state) = cell {
952 if state.data_id != compose.data_id() {
953 todo!()
954 }
955
956 let ptr = (*state.compose).as_ptr_mut();
957
958 unsafe {
959 compose.reborrow(ptr);
960 }
961 } else {
962 *cell = Some(DynComposeState {
963 data_id: compose.data_id(),
964 compose,
965 })
966 }
967 }
968
969 unsafe { cell.as_mut().unwrap().compose.any_compose(child_state) }
970 }
971}
972
973macro_rules! impl_tuples {
974 ($($t:tt : $idx:tt),*) => {
975 unsafe impl<$($t: Data),*> Data for ($($t,)*) {
976 type Id = ($($t::Id,)*);
977 }
978
979 impl<$($t: Compose),*> Compose for ($($t,)*) {
980 fn compose(cx: Scope<Self>) -> impl Compose {
981 cx.is_container.set(true);
982
983 $(
984 let state = use_ref(&cx, || {
985 ScopeData::default()
986 });
987
988 *state.contexts.borrow_mut() = cx.contexts.borrow().clone();
989 state.is_parent_changed.set(cx.is_parent_changed.get());
990
991 unsafe { cx.me().$idx.any_compose(state) }
992 )*
993 }
994
995 fn name() -> std::borrow::Cow<'static, str> {
996 let mut s = String::from('(');
997
998 $(s.push_str(&$t::name());)*
999
1000 s.push(')');
1001 s.into()
1002 }
1003 }
1004 };
1005}
1006
1007impl_tuples!(T1:0);
1008impl_tuples!(T1:0, T2:1);
1009impl_tuples!(T1:0, T2:1, T3:2);
1010impl_tuples!(T1:0, T2:1, T3:2, T4:3);
1011impl_tuples!(T1:0, T2:1, T3:2, T4:3, T5:4);
1012impl_tuples!(T1:0, T2:1, T3:2, T4:3, T5:4, T6:5);
1013impl_tuples!(T1:0, T2:1, T3:2, T4:3, T5:4, T6:5, T7:6);
1014impl_tuples!(T1:0, T2:1, T3:2, T4:3, T5:4, T6:5, T7:6, T8:7);
1015
1016trait AnyCompose {
1017 fn data_id(&self) -> TypeId;
1018
1019 fn as_ptr_mut(&mut self) -> *mut ();
1020
1021 unsafe fn reborrow(&mut self, ptr: *mut ());
1022
1023 unsafe fn any_compose(&self, state: &ScopeData);
1024
1025 #[cfg(feature = "tracing")]
1026 fn name(&self) -> std::borrow::Cow<'static, str>;
1027}
1028
1029impl<C> AnyCompose for C
1030where
1031 C: Compose + Data,
1032{
1033 fn data_id(&self) -> TypeId {
1034 TypeId::of::<C::Id>()
1035 }
1036
1037 fn as_ptr_mut(&mut self) -> *mut () {
1038 self as *mut Self as *mut ()
1039 }
1040
1041 unsafe fn reborrow(&mut self, ptr: *mut ()) {
1042 std::ptr::swap(self, ptr as _);
1043 }
1044
1045 unsafe fn any_compose(&self, state: &ScopeData) {
1046 state.hook_idx.set(0);
1047
1048 let cx: Scope<'_, C> = Scope {
1050 me: unsafe { mem::transmute(self) },
1051 state: unsafe { mem::transmute(state) },
1052 };
1053 let cx: Scope<'_, C> = unsafe { mem::transmute(cx) };
1054
1055 let cell: &UnsafeCell<Option<Box<dyn AnyCompose>>> = use_ref(&cx, || UnsafeCell::new(None));
1056 let cell = unsafe { &mut *cell.get() };
1057
1058 let child_state = use_ref(&cx, ScopeData::default);
1059
1060 if cell.is_none()
1061 || cx.is_changed.take()
1062 || cx.is_parent_changed.get()
1063 || cx.is_container.get()
1064 {
1065 let child = C::compose(cx);
1066
1067 cx.is_parent_changed.set(false);
1068 if cx.state.is_empty.take() {
1069 return;
1070 }
1071
1072 #[cfg(feature = "tracing")]
1073 if !cx.is_container.get() {
1074 tracing::trace!("Compose::compose: {}", self.name());
1075 }
1076
1077 *child_state.contexts.borrow_mut() = cx.contexts.borrow().clone();
1078 child_state.is_parent_changed.set(true);
1079
1080 unsafe {
1081 if let Some(ref mut content) = cell {
1082 child.reborrow((**content).as_ptr_mut());
1083 } else {
1084 let boxed: Box<dyn AnyCompose> = Box::new(child);
1085 *cell = Some(mem::transmute(boxed));
1086 }
1087 }
1088 } else {
1089 child_state.is_parent_changed.set(false);
1090 }
1091
1092 let child = cell.as_mut().unwrap();
1093 (*child).any_compose(child_state);
1094 }
1095
1096 #[cfg(feature = "tracing")]
1097 fn name(&self) -> std::borrow::Cow<'static, str> {
1098 C::name().into()
1099 }
1100}
1101
1102pub trait Updater {
1104 fn update(&self, update: Update);
1105}
1106
1107struct DefaultUpdater;
1108
1109impl Updater for DefaultUpdater {
1110 fn update(&self, update: crate::Update) {
1111 unsafe {
1112 update.apply();
1113 }
1114 }
1115}
1116
1117pub struct Composer {
1119 compose: Box<dyn AnyCompose>,
1120 scope_state: Box<ScopeData<'static>>,
1121 rt: Runtime,
1122}
1123
1124impl Composer {
1125 pub fn new(content: impl Compose + 'static) -> Self {
1127 Self::with_updater(content, DefaultUpdater)
1128 }
1129
1130 pub fn with_updater(content: impl Compose + 'static, updater: impl Updater + 'static) -> Self {
1132 let updater = Rc::new(updater);
1133 Self {
1134 compose: Box::new(content),
1135 scope_state: Box::new(ScopeData::default()),
1136 rt: Runtime {
1137 updater: updater.clone(),
1138 },
1139 }
1140 }
1141
1142 pub fn compose(&mut self) {
1144 self.rt.enter();
1145
1146 unsafe { self.compose.any_compose(&*self.scope_state) }
1147 }
1148}
1149
1150#[cfg(test)]
1151mod tests {
1152 use crate::{prelude::*, Composer};
1153 use std::{
1154 cell::{Cell, RefCell},
1155 rc::Rc,
1156 };
1157
1158 #[derive(Data)]
1159 struct Counter {
1160 x: Rc<Cell<i32>>,
1161 }
1162
1163 impl Compose for Counter {
1164 fn compose(cx: Scope<Self>) -> impl Compose {
1165 cx.me().x.set(cx.me().x.get() + 1);
1166
1167 cx.set_changed();
1168 }
1169 }
1170
1171 #[test]
1172 fn it_composes() {
1173 #[derive(Data)]
1174 struct Wrap {
1175 x: Rc<Cell<i32>>,
1176 }
1177
1178 impl Compose for Wrap {
1179 fn compose(cx: Scope<Self>) -> impl Compose {
1180 Counter {
1181 x: cx.me().x.clone(),
1182 }
1183 }
1184 }
1185
1186 let x = Rc::new(Cell::new(0));
1187 let mut composer = Composer::new(Wrap { x: x.clone() });
1188
1189 composer.compose();
1190 assert_eq!(x.get(), 1);
1191
1192 composer.compose();
1193 assert_eq!(x.get(), 2);
1194 }
1195
1196 #[test]
1197 fn it_composes_any_compose() {
1198 #[derive(Data)]
1199 struct Wrap {
1200 x: Rc<Cell<i32>>,
1201 }
1202
1203 impl Compose for Wrap {
1204 fn compose(cx: crate::Scope<Self>) -> impl Compose {
1205 DynCompose::new(Counter {
1206 x: cx.me().x.clone(),
1207 })
1208 }
1209 }
1210
1211 let x = Rc::new(Cell::new(0));
1212 let mut composer = Composer::new(Wrap { x: x.clone() });
1213
1214 composer.compose();
1215 assert_eq!(x.get(), 1);
1216
1217 composer.compose();
1218 assert_eq!(x.get(), 2);
1219 }
1220
1221 #[test]
1222 fn it_memoizes_composables() {
1223 #[derive(Data)]
1224 struct B {
1225 x: Rc<RefCell<i32>>,
1226 }
1227
1228 impl Compose for B {
1229 fn compose(cx: Scope<Self>) -> impl Compose {
1230 *cx.me().x.borrow_mut() += 1;
1231 }
1232 }
1233
1234 #[derive(Data)]
1235 struct A {
1236 x: Rc<RefCell<i32>>,
1237 }
1238
1239 impl Compose for A {
1240 fn compose(cx: Scope<Self>) -> impl Compose {
1241 let x = cx.me().x.clone();
1242 Memo::new((), B { x })
1243 }
1244 }
1245
1246 let x = Rc::new(RefCell::new(0));
1247 let mut compsoer = Composer::new(A { x: x.clone() });
1248
1249 compsoer.compose();
1250 assert_eq!(*x.borrow(), 1);
1251
1252 compsoer.compose();
1253 assert_eq!(*x.borrow(), 1);
1254 }
1255}