wakflo_common/utils/
vault.rs1use std::ptr::NonNull;
19use std::sync::atomic::{self, AtomicBool, AtomicUsize, Ordering};
20
21#[test]
22fn test_unit() {
23 let mut u = Vault::new(0);
24 {
25 *(u.as_mut()) = 1;
26 assert_eq!(u.as_vault_ref(), &1);
27 assert_eq!(u.sealed.get_mut(), &false);
28 let mut up = u.as_mut();
29 *up += 1;
30 assert_eq!(*up, 2);
31 }
32 assert_eq!(*u, 2);
33 assert_eq!(u.sealed.get_mut(), &false);
34}
35
36#[derive(std::fmt::Debug)]
38pub struct Vault<U> {
39 sealed: AtomicBool,
40 inner: NonNull<Inner<U>>,
41}
42
43unsafe impl<U> Send for Vault<U> {}
44
45unsafe impl<U> Sync for Vault<U> {}
46
47struct Inner<U> {
48 cn: AtomicUsize,
49 data: U,
50}
51
52impl<U> Clone for Vault<U> {
53 fn clone(&self) -> Self {
54 self.inner().cn.fetch_add(1, Ordering::Relaxed);
55 Self::from_inner(self.inner)
56 }
57}
58
59impl<U> std::ops::Deref for Vault<U> {
60 type Target = U;
61
62 fn deref(&self) -> &Self::Target {
63 &self.inner().data
64 }
65}
66
67impl<U> std::ops::DerefMut for Vault<U> {
68 fn deref_mut(&mut self) -> &mut U {
69 unsafe { &mut self.inner.as_mut().data }
70 }
71}
72
73impl<U: Default> Default for Vault<U> {
74 fn default() -> Self {
75 Vault::new(U::default())
76 }
77}
78
79impl<U> Drop for Vault<U> {
80 fn drop(&mut self) {
81 if self.inner().cn.fetch_sub(1, Ordering::Release) != 1 {
82 return;
84 }
85 atomic::fence(Ordering::Acquire);
87 self.drop_slow()
89 }
90}
91
92impl<U> Vault<U> {
93 pub fn new(d: U) -> Self {
94 let dm: Box<_> = Box::new(Inner {
95 cn: AtomicUsize::new(1),
96 data: d,
97 });
98 Self::from_inner(Box::leak(dm).into())
99 }
100
101 pub fn take(&mut self) -> U
102 where
103 U: Default,
104 {
105 self.replace(U::default())
106 }
107
108 pub fn replace(&mut self, src: U) -> U {
109 std::mem::replace(&mut **self, src)
110 }
111
112 #[allow(dead_code)]
113 pub fn swap(&mut self, dst: &mut U) {
114 std::mem::swap(&mut **self, dst);
115 }
116
117 #[allow(dead_code)]
118 pub fn map<R, F>(&mut self, mut f: F) -> R
119 where
120 F: FnMut(&mut U) -> R,
121 {
122 unsafe { f(&mut self.inner.as_mut().data) }
123 }
124
125 #[allow(dead_code)]
126 fn from_ptr(ptr: *mut Inner<U>) -> Self {
127 unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) }
128 }
129
130 fn inner(&self) -> &Inner<U> {
131 unsafe { self.inner.as_ref() }
132 }
133
134 pub fn as_mut(&mut self) -> Vaulted<U> {
135 while self.sealed.load(Ordering::Acquire) {
136 std::hint::spin_loop()
137 }
138 self.sealed.store(true, Ordering::Release);
139 Vaulted(self)
140 }
141
142 #[allow(dead_code)]
143 pub fn as_vault_ref(&self) -> &U {
144 while self.sealed.load(Ordering::Relaxed) {
145 std::hint::spin_loop()
146 }
147 unsafe { &self.inner.as_ref().data }
148 }
149
150 #[allow(dead_code)]
151 pub(crate) fn update<F, R>(&mut self, mut f: F) -> R
152 where
153 F: FnMut(&mut U) -> R,
154 {
155 while self.sealed.load(Ordering::Acquire) {
156 std::hint::spin_loop()
157 }
158 f(&mut *self)
159 }
160
161 #[allow(dead_code)]
162 pub(crate) fn try_unseal(&mut self) {
163 if self.sealed.load(Ordering::Acquire) {
164 self.sealed.store(false, Ordering::Release);
165 }
166 }
167
168 #[allow(dead_code)]
169 pub(crate) fn unseal(&mut self) {
170 while self.sealed.load(Ordering::Acquire) {
171 self.sealed.store(false, Ordering::Release);
172 }
173 }
174
175 unsafe fn get_mut_unchecked(this: &mut Self) -> &mut U {
176 &mut (*this.inner.as_ptr()).data
177 }
178
179 fn drop_slow(&mut self) {
180 unsafe { std::ptr::drop_in_place(Self::get_mut_unchecked(self)) };
181 }
182
183 fn from_inner(ptr: NonNull<Inner<U>>) -> Self {
184 Self {
185 sealed: AtomicBool::new(false),
186 inner: ptr,
187 }
188 }
189}
190
191pub struct Vaulted<'a, U>(&'a mut Vault<U>);
194
195impl<'a, U> Vaulted<'a, U> {
196 #[allow(dead_code)]
197 fn new(d: &'a mut Vault<U>) -> Self {
198 Vaulted(d)
199 }
200}
201
202impl<U> std::ops::Deref for Vaulted<'_, U> {
203 type Target = U;
204
205 fn deref(&self) -> &Self::Target {
206 &self.0.inner().data
207 }
208}
209
210impl<U> std::ops::DerefMut for Vaulted<'_, U> {
211 fn deref_mut(&mut self) -> &mut U {
212 unsafe { &mut self.0.inner.as_mut().data }
213 }
214}
215
216impl<U> Drop for Vaulted<'_, U> {
217 fn drop(&mut self) {
218 while !self.0.sealed.load(Ordering::Acquire) {
219 std::hint::spin_loop()
220 }
221 self.0.sealed.store(false, Ordering::Release);
222 }
223}