1use core::ops::{Deref, DerefMut};
2
3#[cfg(feature = "std")]
4type Inner<T> = std::sync::RwLock<T>;
5
6#[cfg(not(feature = "std"))]
7type Inner<T> = core::cell::RefCell<T>;
8
9#[derive(Debug, Default)]
15pub struct Stem<T>(Inner<T>);
16
17impl<T> Stem<T> {
18 pub const fn new(t: T) -> Self {
20 Self(Inner::new(t))
21 }
22
23 pub fn map_ref<F, R>(&self, f: F) -> R
30 where F: for<'a> FnMut(&'a T) -> R
31 {
32 self.0.map_ref(f)
33 }
34
35 pub fn map_mut<F, R>(&self, f: F) -> R
39 where F: for<'a> FnMut(&'a mut T) -> R
40 {
41 self.0.map_mut(f)
42 }
43}
44
45pub trait StemCellBehavior<T> {
54 fn new(t: T) -> Self
56 where Self: Sized;
57
58 fn map_ref<F, R>(&self, f: F) -> R
63 where F: for<'a> FnMut(&'a T) -> R;
64
65 fn map_mut<F, R>(&self, f: F) -> R
70 where F: for<'a> FnMut(&'a mut T) -> R;
71}
72
73#[cfg(feature = "std")]
74impl<T> StemCellBehavior<T> for std::sync::RwLock<T> {
75 fn new(t: T) -> Self {
76 Self::new(t)
77 }
78
79 fn map_ref<F, R>(&self, mut f: F) -> R
80 where F: for<'a> FnMut(&'a T) -> R
81 {
82 f(self.read().unwrap().deref())
83 }
84
85 fn map_mut<F, R>(&self, mut f: F) -> R
86 where F: for<'a> FnMut(&'a mut T) -> R
87 {
88 f(self.write().unwrap().deref_mut())
89 }
90}
91
92impl<T> StemCellBehavior<T> for core::cell::RefCell<T> {
93 fn new(t: T) -> Self {
94 Self::new(t)
95 }
96
97 fn map_ref<F, R>(&self, mut f: F) -> R
98 where F: for<'a> FnMut(&'a T) -> R
99 {
100 f(self.borrow().deref())
101 }
102
103 fn map_mut<F, R>(&self, mut f: F) -> R
104 where F: for<'a> FnMut(&'a mut T) -> R
105 {
106 f(self.borrow_mut().deref_mut())
107 }
108}
109
110#[cfg(test)]
111mod test {
112 use core::cell::RefCell;
113 use std::sync::{Arc, Barrier, RwLock};
114
115 use super::*;
116
117 #[test]
118 fn refcell_modify() {
119 let s = RefCell::new(Vec::<usize>::new());
120 s.map_mut(|v| v.push(12));
121 s.map_ref(|v| assert_eq!(v, &vec![12usize]));
122 }
123
124 #[test]
125 fn refcell_concurrent_read_does_not_panic() {
126 let s = RefCell::new(Vec::<usize>::new());
127 s.map_ref(|_| s.map_ref(|_| ()));
128 }
129
130 #[test]
131 fn rwlock_modify() {
132 let s = RwLock::new(Vec::<usize>::new());
133 s.map_mut(|v| v.push(12));
134 s.map_ref(|v| assert_eq!(v, &vec![12usize]));
135 }
136
137 #[test]
138 fn rwlock_concurrent_read_does_not_panic() {
139 let s = RwLock::new(Vec::<usize>::new());
140 s.map_ref(|_| s.map_ref(|_| ()));
141 }
142
143 #[test]
144 fn stem_modify_blocks_until_refs_dropped() {
145 unsafe {
146 static VEC: Stem<Vec<usize>> = Stem::new(Vec::new());
147
148 static mut START: Option<Arc<Barrier>> = None;
149 static mut READING: Option<Arc<Barrier>> = None;
150 static mut READING_DONE: Option<Arc<Barrier>> = None;
151 static mut MODIFY_DONE: Option<Arc<Barrier>> = None;
152
153 START = Some(Arc::new(Barrier::new(3)));
154 READING = Some(Arc::new(Barrier::new(3)));
155 READING_DONE = Some(Arc::new(Barrier::new(2)));
156 MODIFY_DONE = Some(Arc::new(Barrier::new(3)));
157
158 macro_rules! wait {
159 ($b:ident) => {
160 $b.as_ref().unwrap().clone().wait();
161 };
162 }
163
164 std::thread::spawn(|| {
165 wait!(START);
166 VEC.map_ref(|v| {
167 assert!(v.is_empty());
168 wait!(READING);
169 wait!(READING_DONE);
170 });
171
172 wait!(MODIFY_DONE);
173 });
174
175 std::thread::spawn(|| {
176 wait!(START);
177 wait!(READING);
178 VEC.map_mut(|v| v.push(12)); wait!(MODIFY_DONE);
180 });
181
182 wait!(START);
183 wait!(READING);
184 wait!(READING_DONE);
185 wait!(MODIFY_DONE);
186 VEC.map_ref(|v| assert_eq!(v, &vec![12]));
187 }
188 }
189}