actuate_core/
lib.rs

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
24/// Clone-on-write value.
25///
26/// This represents either a borrowed or owned value.
27/// A borrowed value is stored as a [`RefMap`], which can be either a reference or a mapped reference.
28pub 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
74/// Immutable reference or mapped reference to a value.
75pub 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
138/// Mapped immutable reference to a value of type `T`.
139pub 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
171// Safety: The `Map` is dereferenced every re-compose, so it's guranteed not to point to
172// an invalid memory location (e.g. an `Option` that previously returned `Some` is now `None`).
173impl<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/// Immutable reference to a value of type `T`.
195#[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    /// Map this reference to a value of type `U`.
203    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
242/// Mutable reference to a value of type `T`.
243pub 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    /// Queue an update to this value, triggering an update to the component owning this value.
252    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    /// Queue an update to this value wtihout triggering an update.
271    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    /// Convert this mutable reference to an immutable reference.
282    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
318/// An update to apply to a composable.
319pub struct Update {
320    f: Box<dyn FnOnce()>,
321}
322
323impl Update {
324    /// Apply this update.
325    ///
326    /// # Safety
327    /// The caller must ensure the composable triggering this update still exists.
328    pub unsafe fn apply(self) {
329        (self.f)();
330    }
331}
332
333/// Runtime for a [`Composer`].
334#[derive(Clone)]
335pub struct Runtime {
336    updater: Rc<dyn Updater>,
337}
338
339impl Runtime {
340    /// Get the current [`Runtime`].
341    ///
342    /// # Panics
343    /// Panics if called outside of a runtime.
344    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    /// Enter this runtime, making it available to [`Runtime::current`].
355    pub fn enter(&self) {
356        RUNTIME.with(|runtime| {
357            *runtime.borrow_mut() = Some(self.clone());
358        });
359    }
360
361    /// Queue an update to run after [`Composer::compose`].
362    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/// Map of [`TypeId`] to context values.
372#[derive(Clone, Default)]
373struct Contexts {
374    values: HashMap<TypeId, Rc<dyn Any>>,
375}
376
377pub type ScopeState<'a> = &'a ScopeData<'a>;
378
379/// State of a composable.
380#[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
414/// Composable scope.
415pub 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
456/// Use an immutable reference to a value of type `T`.
457///
458/// `make_value` will only be called once to initialize this value.
459pub 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
479/// Use a mutable reference to a value of type `T`.
480///
481/// `make_value` will only be called once to initialize this value.
482pub 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
553/// Use a context value of type `T`.
554///
555/// # Panics
556/// Panics if the context value is not found.
557pub 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
567/// Provide a context value of type `T`.
568///
569/// This value will be available to [`use_context`] to all children of this composable.
570pub fn use_provider<'a, T: 'static>(cx: ScopeState<'_>, make_value: impl FnOnce() -> T) -> Rc<T> {
571    // TODO
572    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
605/// Use a memoized value of type `T` with a dependency of type `D`.
606///
607/// `make_value` will update the returned value whenver `dependency` is changed.
608pub 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
651/// Composable data.
652///
653/// This trait should be derived with `#[derive(Data)]`.
654pub 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
667// TODO
668unsafe 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
760/// A composable function.
761///
762/// For a dynamically-typed composable, see [`DynCompose`].
763pub 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
914/// Dynamically-typed composable.
915pub 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        // Transmute the lifetime of `&Self`, `&ScopeData`, and the `Scope` containing both to the same`'a`.
1049        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
1102/// Updater for a [`Composer`].
1103pub 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
1117/// Composer for composable content.
1118pub struct Composer {
1119    compose: Box<dyn AnyCompose>,
1120    scope_state: Box<ScopeData<'static>>,
1121    rt: Runtime,
1122}
1123
1124impl Composer {
1125    /// Create a new [`Composer`] with the given content and default updater.
1126    pub fn new(content: impl Compose + 'static) -> Self {
1127        Self::with_updater(content, DefaultUpdater)
1128    }
1129
1130    /// Create a new [`Composer`] with the given content and default updater.
1131    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    /// Compose the content of this composer.
1143    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}