1use std::{
39 cell::{BorrowError, BorrowMutError, Ref, RefCell, RefMut},
40 rc::{Rc, Weak},
41};
42
43#[repr(transparent)]
45#[derive(Debug)]
46pub struct SharedCell<T>(Rc<RefCell<T>>);
47
48impl<T> Clone for SharedCell<T> {
49 fn clone(&self) -> Self {
50 Self(self.0.clone())
51 }
52}
53
54impl<T> SharedCell<T> {
55 #[inline]
57 pub fn new(value: T) -> Self {
58 Self(Rc::new(RefCell::new(value)))
59 }
60
61 #[inline]
63 #[must_use]
64 pub fn downgrade(&self) -> WeakCell<T> {
65 WeakCell(Rc::downgrade(&self.0))
66 }
67
68 #[inline]
70 #[must_use]
71 pub fn borrow(&self) -> Ref<'_, T> {
72 self.0.borrow()
73 }
74
75 #[inline]
77 #[must_use]
78 pub fn borrow_mut(&self) -> RefMut<'_, T> {
79 self.0.borrow_mut()
80 }
81
82 #[inline]
88 pub fn try_borrow(&self) -> Result<Ref<'_, T>, BorrowError> {
89 self.0.try_borrow()
90 }
91
92 #[inline]
99 pub fn try_borrow_mut(&self) -> Result<RefMut<'_, T>, BorrowMutError> {
100 self.0.try_borrow_mut()
101 }
102
103 #[inline]
105 #[must_use]
106 pub fn strong_count(&self) -> usize {
107 Rc::strong_count(&self.0)
108 }
109
110 #[inline]
112 #[must_use]
113 pub fn weak_count(&self) -> usize {
114 Rc::weak_count(&self.0)
115 }
116}
117
118impl<T> From<Rc<RefCell<T>>> for SharedCell<T> {
119 fn from(inner: Rc<RefCell<T>>) -> Self {
120 Self(inner)
121 }
122}
123
124impl<T> From<SharedCell<T>> for Rc<RefCell<T>> {
125 fn from(shared: SharedCell<T>) -> Self {
126 shared.0
127 }
128}
129
130impl<T> std::ops::Deref for SharedCell<T> {
131 type Target = Rc<RefCell<T>>;
132
133 fn deref(&self) -> &Self::Target {
134 &self.0
135 }
136}
137
138#[repr(transparent)]
140#[derive(Debug)]
141pub struct WeakCell<T>(Weak<RefCell<T>>);
142
143impl<T> Clone for WeakCell<T> {
144 fn clone(&self) -> Self {
145 Self(self.0.clone())
146 }
147}
148
149impl<T> WeakCell<T> {
150 #[inline]
152 pub fn upgrade(&self) -> Option<SharedCell<T>> {
153 self.0.upgrade().map(SharedCell)
154 }
155
156 #[inline]
158 #[must_use]
159 pub fn is_dropped(&self) -> bool {
160 self.0.strong_count() == 0
161 }
162}
163
164impl<T> From<Weak<RefCell<T>>> for WeakCell<T> {
165 fn from(inner: Weak<RefCell<T>>) -> Self {
166 Self(inner)
167 }
168}
169
170impl<T> From<WeakCell<T>> for Weak<RefCell<T>> {
171 fn from(cell: WeakCell<T>) -> Self {
172 cell.0
173 }
174}
175
176#[cfg(test)]
177mod tests {
178 use rstest::rstest;
179
180 use super::*;
181
182 #[rstest]
183 fn test_shared_cell_new_and_borrow() {
184 let cell = SharedCell::new(42);
185 assert_eq!(*cell.borrow(), 42);
186 }
187
188 #[rstest]
189 fn test_shared_cell_borrow_mut() {
190 let cell = SharedCell::new(0);
191 *cell.borrow_mut() = 99;
192 assert_eq!(*cell.borrow(), 99);
193 }
194
195 #[rstest]
196 fn test_shared_cell_clone_shares_value() {
197 let cell = SharedCell::new(10);
198 let clone = cell.clone();
199 *cell.borrow_mut() = 20;
200 assert_eq!(*clone.borrow(), 20);
201 }
202
203 #[rstest]
204 fn test_shared_cell_strong_weak_counts() {
205 let cell = SharedCell::new(1);
206 assert_eq!(cell.strong_count(), 1);
207 assert_eq!(cell.weak_count(), 0);
208
209 let weak = cell.downgrade();
210 assert_eq!(cell.weak_count(), 1);
211 assert_eq!(cell.strong_count(), 1);
212
213 let clone = cell.clone();
214 assert_eq!(cell.strong_count(), 2);
215 drop(clone);
216 assert_eq!(cell.strong_count(), 1);
217 drop(weak);
218 assert_eq!(cell.weak_count(), 0);
219 }
220
221 #[rstest]
222 fn test_weak_cell_upgrade_succeeds_while_alive() {
223 let cell = SharedCell::new(10);
224 let weak = cell.downgrade();
225 assert!(!weak.is_dropped());
226
227 let upgraded = weak.upgrade();
228 assert!(upgraded.is_some());
229 assert_eq!(*upgraded.unwrap().borrow(), 10);
230 }
231
232 #[rstest]
233 fn test_weak_cell_upgrade_fails_after_drop() {
234 let weak = {
235 let cell = SharedCell::new(10);
236 cell.downgrade()
237 };
238 assert!(weak.is_dropped());
239 assert!(weak.upgrade().is_none());
240 }
241
242 #[rstest]
243 #[expect(clippy::redundant_clone, reason = "Clone is the behavior under test")]
244 fn test_weak_cell_clone() {
245 let cell = SharedCell::new(5);
246 let weak1 = cell.downgrade();
247 let weak2 = weak1.clone();
248 assert_eq!(cell.weak_count(), 2);
249 assert_eq!(*weak2.upgrade().unwrap().borrow(), 5);
250 }
251
252 #[rstest]
253 fn test_try_borrow_fails_while_mutably_borrowed() {
254 let cell = SharedCell::new(0);
255 let _guard = cell.borrow_mut();
256 assert!(cell.try_borrow().is_err());
257 }
258
259 #[rstest]
260 fn test_try_borrow_mut_fails_while_borrowed() {
261 let cell = SharedCell::new(0);
262 let _guard = cell.borrow();
263 assert!(cell.try_borrow_mut().is_err());
264 }
265
266 #[rstest]
267 fn test_from_rc_refcell_roundtrip() {
268 let rc = Rc::new(RefCell::new(5));
269 let cell = SharedCell::from(rc);
270 assert_eq!(*cell.borrow(), 5);
271
272 let back: Rc<RefCell<i32>> = cell.into();
273 assert_eq!(*back.borrow(), 5);
274 }
275
276 #[rstest]
277 fn test_from_weak_refcell_roundtrip() {
278 let rc = Rc::new(RefCell::new(7));
279 let weak_cell = WeakCell::from(Rc::downgrade(&rc));
280 assert_eq!(*weak_cell.upgrade().unwrap().borrow(), 7);
281
282 let back: Weak<RefCell<i32>> = weak_cell.into();
283 assert_eq!(*back.upgrade().unwrap().borrow(), 7);
284 }
285}