hooks/
gen_ref.rs

1use std::cell::RefCell;
2
3use hooks_gen::{local, Key, Owner, Store};
4
5pub struct GenRefOwner<T: 'static>(local::Owner<RefCell<T>>);
6
7impl<T: 'static> Clone for GenRefOwner<T> {
8    fn clone(&self) -> Self {
9        Self(self.0.clone())
10    }
11}
12
13impl<T: 'static> GenRefOwner<T> {
14    pub fn new(initial_value: T) -> Self {
15        Self(local::Store.insert(RefCell::new(initial_value)))
16    }
17
18    /// The opposite of [`GenRefKey::upgrade`].
19    pub fn key(&self) -> GenRefKey<T> {
20        GenRefKey(self.0.key())
21    }
22}
23
24impl<T: 'static> Unpin for GenRefOwner<T> {}
25
26hooks_core::impl_hook!(
27    impl<T: 'static> GenRefOwner<T> {
28        fn unmount() {}
29
30        fn poll_next_update(self, _cx: _) {
31            std::task::Poll::Ready(false)
32        }
33
34        #[inline]
35        fn use_hook(self) -> GenRefKey<T> {
36            GenRefKey(self.0.key())
37        }
38    }
39);
40
41pub struct GenRefKey<T: 'static>(local::Key<RefCell<T>>);
42
43impl<T: 'static> GenRefKey<T> {
44    pub fn upgrade(self) -> GenRefOwner<T> {
45        let owner = self.0.owner();
46        GenRefOwner(owner)
47    }
48}
49
50impl<T: 'static> Copy for GenRefKey<T> {}
51impl<T: 'static> Clone for GenRefKey<T> {
52    fn clone(&self) -> Self {
53        *self
54    }
55}
56
57impl<T: 'static> Eq for GenRefKey<T> {}
58impl<T: 'static> PartialEq for GenRefKey<T> {
59    fn eq(&self, other: &Self) -> bool {
60        self.0 == other.0
61    }
62}
63
64#[cfg(feature = "ShareValue")]
65impl<T: 'static> crate::ShareValue for GenRefOwner<T> {
66    type Value = T;
67
68    crate::proxy_share_value!(|self| -> GenRefKey<T> { &self.key() }, |other| {
69        &other.key()
70    });
71
72    fn try_unwrap(self) -> Result<Self::Value, Self> {
73        Err(self)
74    }
75}
76
77#[cfg(feature = "ShareValue")]
78impl<T: 'static> crate::ToOwnedShareValue for GenRefOwner<T> {
79    type OwnedShareValue = GenRefKey<T>;
80
81    fn to_owned_share_value(&self) -> Self::OwnedShareValue {
82        self.key()
83    }
84}
85
86#[cfg(feature = "ShareValue")]
87impl<T: 'static> crate::ShareValue for GenRefKey<T> {
88    type Value = T;
89
90    fn try_unwrap(self) -> Result<Self::Value, Self>
91    where
92        Self: Sized,
93    {
94        Err(self)
95    }
96
97    fn map<R>(&self, f: impl FnOnce(&Self::Value) -> R) -> R {
98        self.0.map(|v| f(&v.borrow()))
99    }
100
101    fn map_mut<R>(&self, f: impl FnOnce(&mut Self::Value) -> R) -> R {
102        self.0.map(|v| f(&mut v.borrow_mut()))
103    }
104
105    fn equivalent_to(&self, other: &Self) -> bool {
106        *self == *other
107    }
108}
109
110#[cfg(feature = "ShareValue")]
111impl<T: 'static> crate::ToOwnedShareValue for GenRefKey<T> {
112    type OwnedShareValue = Self;
113
114    fn to_owned_share_value(&self) -> Self::OwnedShareValue {
115        *self
116    }
117}
118
119pub struct UseGenRef<T: 'static>(pub T);
120
121hooks_core::impl_hook!(
122    impl<T: 'static> UseGenRef<T> {
123        fn into_hook(self) -> GenRefOwner<T> {
124            GenRefOwner::new(self.0)
125        }
126
127        fn update_hook(self, _hook: _) {}
128
129        fn h(self, hook: crate::utils::UninitializedHook<GenRefOwner<T>>) {
130            hook.get_mut().use_into_or_update_hook(self)
131        }
132    }
133);
134
135pub struct UseGenRefWith<F>(pub F);
136
137hooks_core::impl_hook!(
138    impl<T: 'static, F: FnOnce() -> T> UseGenRefWith<F> {
139        fn into_hook(self) -> GenRefOwner<T> {
140            GenRefOwner::new(self.0())
141        }
142
143        fn update_hook(self, _hook: _) {}
144
145        fn h(self, hook: crate::utils::UninitializedHook<GenRefOwner<T>>) {
146            hook.get_mut().use_into_or_update_hook(self)
147        }
148    }
149);
150
151#[cfg(test)]
152#[cfg(feature = "ShareValue")]
153#[cfg(feature = "futures-core")]
154mod tests {
155    use futures_lite::StreamExt;
156
157    use crate::{GenRefOwner, ShareValue};
158
159    #[test]
160    #[cfg(feature = "use_effect")]
161    fn ref_is_not_reactive() {
162        use hooks_core::{hook_fn, IntoHook};
163
164        use crate::{use_effect, use_gen_ref, ShareValue};
165
166        hook_fn!(
167            fn use_test() -> i32 {
168                let ref_num = h![use_gen_ref(0)];
169
170                let value = ref_num.get();
171
172                h![use_effect(
173                    move |v: &_| {
174                        if *v < 2 {
175                            ref_num.set(*v + 1);
176                        }
177                    },
178                    value,
179                )];
180
181                value
182            }
183        );
184
185        futures_lite::future::block_on(async {
186            let values = use_test().into_hook_values();
187
188            let values = values.collect::<Vec<_>>().await;
189            assert_eq!(values, [0]);
190        });
191    }
192
193    mod nested_share_value {
194        use crate::{GenRefOwner, ShareValue};
195
196        #[test]
197        fn nested_map() {
198            // self
199            {
200                let ref_num = GenRefOwner::new(0);
201                ref_num.key().map(|_| ref_num.key().map(|_| {}));
202            }
203            // two
204            {
205                let ref_num = GenRefOwner::new(0);
206                let ref_num_2 = GenRefOwner::new(0);
207
208                ref_num.key().map(|_| ref_num_2.key().map(|_| {}));
209                ref_num_2.key().map(|_| ref_num.key().map(|_| {}));
210            }
211        }
212
213        #[test]
214        #[should_panic(expected = "already borrowed: BorrowMutError")]
215        fn nested_self_map_mut_should_panic() {
216            let ref_num = GenRefOwner::new(0);
217            ref_num.key().map_mut(|_| ref_num.key().map_mut(|_| {}));
218        }
219
220        #[test]
221        #[should_panic(expected = "already mutably borrowed: BorrowError")]
222        fn nested_self_map_mut_and_map_should_panic() {
223            let ref_num = GenRefOwner::new(0);
224            ref_num.key().map_mut(|_| ref_num.key().map(|_| {}));
225            ref_num.key().map(|_| ref_num.key().map_mut(|_| {}));
226        }
227
228        #[test]
229        #[should_panic(expected = "already borrowed: BorrowMutError")]
230        fn nested_self_map_and_map_mut_should_panic() {
231            let ref_num = GenRefOwner::new(0);
232            ref_num.key().map(|_| ref_num.key().map_mut(|_| {}));
233        }
234
235        #[test]
236        fn nested_map_mut() {
237            // two
238            {
239                let ref_num = GenRefOwner::new(0);
240                let ref_num_2 = GenRefOwner::new(0);
241
242                ref_num.key().map_mut(|_| ref_num_2.key().map_mut(|_| {}));
243                ref_num_2.key().map_mut(|_| ref_num.key().map_mut(|_| {}));
244            }
245        }
246    }
247
248    #[test]
249    #[should_panic(expected = "already borrowed: BorrowMutError")]
250    // This might be implemented with [elsa](https://docs.rs/elsa).
251    // The type map of store is FrozenMap<TypeId, Box<Store>>.
252    // The store is implemented with FrozenSlab,
253    // which can be implemented with FrozenVec<Box<Chunk<Item>>>.
254    // The chunk size increases exponentially
255    fn insert_while_map() {
256        let ref_num = GenRefOwner::new(0);
257        ref_num.key().map(|_| {
258            GenRefOwner::new(0);
259        })
260    }
261}