dioxus_core/
generational_box.rs

1//! Integration with the generational-box crate for copy state management.
2//!
3//! Each scope in dioxus has a single [Owner]
4
5use generational_box::{AnyStorage, Owner, SyncStorage, UnsyncStorage};
6use std::{
7    any::{Any, TypeId},
8    cell::RefCell,
9};
10
11/// Run a closure with the given owner.
12///
13/// This will override the default owner for the current component.
14pub fn with_owner<S: AnyStorage, F: FnOnce() -> R, R>(owner: Owner<S>, f: F) -> R {
15    let old_owner = set_owner(Some(owner));
16    let result = f();
17    set_owner(old_owner);
18    result
19}
20
21/// Set the owner for the current thread.
22fn set_owner<S: AnyStorage>(owner: Option<Owner<S>>) -> Option<Owner<S>> {
23    let id = TypeId::of::<S>();
24    if id == TypeId::of::<SyncStorage>() {
25        SYNC_OWNER.with(|cell| {
26            std::mem::replace(
27                &mut *cell.borrow_mut(),
28                owner.map(|owner| {
29                    *(Box::new(owner) as Box<dyn Any>)
30                        .downcast::<Owner<SyncStorage>>()
31                        .unwrap()
32                }),
33            )
34            .map(|owner| *(Box::new(owner) as Box<dyn Any>).downcast().unwrap())
35        })
36    } else {
37        UNSYNC_OWNER.with(|cell| {
38            std::mem::replace(
39                &mut *cell.borrow_mut(),
40                owner.map(|owner| {
41                    *(Box::new(owner) as Box<dyn Any>)
42                        .downcast::<Owner<UnsyncStorage>>()
43                        .unwrap()
44                }),
45            )
46            .map(|owner| *(Box::new(owner) as Box<dyn Any>).downcast().unwrap())
47        })
48    }
49}
50
51thread_local! {
52    static SYNC_OWNER: RefCell<Option<Owner<SyncStorage>>> = const { RefCell::new(None) };
53    static UNSYNC_OWNER: RefCell<Option<Owner<UnsyncStorage>>> = const { RefCell::new(None) };
54}
55
56/// Returns the current owner. This owner will be used to drop any `Copy` state that is created by the `generational-box` crate.
57///
58/// If an owner has been set with `with_owner`, that owner will be returned. Otherwise, the owner from the current scope will be returned.
59pub fn current_owner<S: AnyStorage>() -> Owner<S> {
60    let id = TypeId::of::<S>();
61    let override_owner = if id == TypeId::of::<SyncStorage>() {
62        SYNC_OWNER.with(|cell| {
63            let owner = cell.borrow();
64
65            owner.clone().map(|owner| {
66                *(Box::new(owner) as Box<dyn Any>)
67                    .downcast::<Owner<S>>()
68                    .unwrap()
69            })
70        })
71    } else {
72        UNSYNC_OWNER.with(|cell| {
73            cell.borrow().clone().map(|owner| {
74                *(Box::new(owner) as Box<dyn Any>)
75                    .downcast::<Owner<S>>()
76                    .unwrap()
77            })
78        })
79    };
80    if let Some(owner) = override_owner {
81        return owner;
82    }
83
84    crate::Runtime::current().current_owner()
85}