radiate_core/domain/sync/
cell.rs1use std::{
2 cell::UnsafeCell,
3 fmt::{Debug, Formatter},
4 ops::Deref,
5 sync::atomic::{AtomicUsize, Ordering},
6};
7struct ArcInner<T> {
8 value: UnsafeCell<T>,
9 ref_count: AtomicUsize,
10}
11
12pub struct MutCell<T> {
13 inner: *const ArcInner<T>,
14 consumed: bool,
15}
16
17unsafe impl<T: Send> Send for MutCell<T> {}
19unsafe impl<T: Sync> Sync for MutCell<T> {}
20
21impl<T> MutCell<T> {
22 pub fn new(value: T) -> Self {
23 Self {
24 inner: Box::into_raw(Box::new(ArcInner {
25 value: UnsafeCell::new(value),
26 ref_count: AtomicUsize::new(1),
27 })),
28 consumed: false,
29 }
30 }
31
32 pub fn is_unique(&self) -> bool {
33 unsafe { (*self.inner).ref_count.load(Ordering::Acquire) == 1 }
35 }
36
37 pub fn is_shared(&self) -> bool {
38 !self.is_unique()
39 }
40
41 pub fn strong_count(&self) -> usize {
42 unsafe { (*self.inner).ref_count.load(Ordering::Acquire) }
44 }
45
46 #[allow(clippy::should_implement_trait)]
49 pub fn borrow(&self) -> &T {
50 assert!(!self.consumed, "Cannot access consumed MutCell");
57 unsafe { &*(*self.inner).value.get() }
58 }
59
60 #[allow(clippy::should_implement_trait)]
63 pub fn borrow_mut(&mut self) -> &mut T {
64 assert!(self.is_unique(), "Cannot mutably borrow shared MutCell");
65 unsafe { &mut *(*self.inner).value.get() }
66 }
67
68 pub fn into_inner(mut self) -> T
69 where
70 T: Clone,
71 {
72 unsafe {
77 if (*self.inner).ref_count.load(Ordering::Acquire) == 1 {
78 self.consumed = true;
79 std::sync::atomic::fence(Ordering::SeqCst);
80 let boxed = Box::from_raw(self.inner as *mut ArcInner<T>);
81 boxed.value.into_inner()
82 } else {
83 let clone = (*(*self.inner).value.get()).clone();
84 (*self.inner).ref_count.fetch_sub(1, Ordering::Release);
85 clone
86 }
87 }
88 }
89}
90
91impl<T> Clone for MutCell<T> {
92 fn clone(&self) -> Self {
93 unsafe {
95 (*self.inner).ref_count.fetch_add(1, Ordering::Relaxed);
96 }
97 Self {
98 inner: self.inner,
99 consumed: false,
100 }
101 }
102}
103
104impl<T> Drop for MutCell<T> {
105 fn drop(&mut self) {
106 if self.consumed {
107 return;
108 }
109
110 unsafe {
113 if (*self.inner).ref_count.fetch_sub(1, Ordering::Release) == 1 {
114 std::sync::atomic::fence(Ordering::Acquire);
115 drop(Box::from_raw(self.inner as *mut ArcInner<T>));
116 }
117 }
118 }
119}
120
121impl<T> Deref for MutCell<T> {
122 type Target = T;
123 fn deref(&self) -> &Self::Target {
124 self.borrow()
125 }
126}
127
128impl<T: PartialEq> PartialEq for MutCell<T> {
129 fn eq(&self, other: &Self) -> bool {
130 self.borrow() == other.borrow()
131 }
132}
133
134impl<T: PartialOrd> PartialOrd for MutCell<T> {
135 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
136 self.borrow().partial_cmp(other.borrow())
137 }
138}
139
140impl<T> From<T> for MutCell<T> {
141 fn from(value: T) -> Self {
142 Self::new(value)
143 }
144}
145
146impl<T: Debug> Debug for MutCell<T> {
147 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
148 write!(f, "{:?}", self.borrow())
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 #[test]
157 fn mutcell_basic_clone_and_mutation_updated() {
158 let mut cell = MutCell::new(5);
159 assert_eq!(*cell, 5);
160
161 *cell.borrow_mut() = 10;
163 assert_eq!(*cell, 10);
164
165 let cell2 = cell.clone();
167 assert_eq!(*cell2, 10);
170 }
171
172 #[test]
173 fn mutcell_into_inner_unique() {
174 let cell = MutCell::new(String::from("hello"));
175 let inner = cell.into_inner();
176 assert_eq!(inner, "hello");
177 }
178
179 #[test]
180 fn mutcell_into_inner_clone_when_multiple() {
181 let cell = MutCell::new(String::from("hello"));
182 let cell2 = cell.clone();
183
184 let inner = cell.into_inner();
185 assert_eq!(inner, "hello");
186
187 drop(cell2);
189 }
190
191 #[test]
192 fn mutcell_partial_eq_and_ord() {
193 let cell1 = MutCell::new(10);
194 let cell2 = MutCell::new(20);
195 let cell3 = MutCell::new(10);
196
197 assert!(cell1 == cell3);
198 assert!(cell1 != cell2);
199 assert!(cell1 < cell2);
200 assert!(cell2 > cell3);
201 }
202
203 #[test]
204 fn mutcell_is_unique_and_shared() {
205 let cell = MutCell::new(42);
206 assert!(cell.is_unique());
207
208 let cell2 = cell.clone();
209
210 assert!(cell.is_shared());
211 assert!(cell2.is_shared());
212 assert!(!cell.is_unique());
213 assert!(!cell2.is_unique());
214 assert_eq!(*cell, 42);
215 assert_eq!(*cell2, 42);
216 assert!(cell.borrow() == cell2.borrow());
217 }
218
219 #[test]
220 fn mut_cell_drop() {
221 let cell = MutCell::new(42);
222 {
223 let _cell2 = cell.clone();
224 assert!(cell.is_shared());
225 } assert!(cell.is_unique());
228 drop(cell); }
230
231 #[test]
232 fn mut_cell_deref() {
233 let mut cell = MutCell::new(42);
234 assert_eq!(*cell, 42);
235 let mut_ref = cell.borrow_mut();
236 *mut_ref = 100;
237 assert_eq!(*cell, 100);
238 }
239}