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 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 {
200 let ref_num = GenRefOwner::new(0);
201 ref_num.key().map(|_| ref_num.key().map(|_| {}));
202 }
203 {
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 {
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 fn insert_while_map() {
256 let ref_num = GenRefOwner::new(0);
257 ref_num.key().map(|_| {
258 GenRefOwner::new(0);
259 })
260 }
261}