Skip to main content

wakflo_common/utils/
vault.rs

1//! A Lock-Free and Thread-Safe reference-counting pointer data container.
2//!
3//! Similar to [Arc]<[Mutex]>,
4//! it not only provides shared owership of a value,
5//! protects the data from mutation, but also **NOT BLOCKING** the thread and can send between
6//! thread safely.
7//!
8//! [Clone::clone] return an `Vault<U>` instance which points to the heap-allocated source data
9//! with reference counter increaced by 1.
10//! when borrowed as mutable, it is sealed as [Vaulted],
11//! only one mutable reference are allowed.
12//!
13//! it only get dropped when all clones dropped
14//!
15//! [Arc]: std::sync::Arc
16//! [Mutex]: std::sync::Mutex
17//!
18use 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/// A Lock-Free and Thread-Safe reference-counting data container
37#[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            //println!("droping vault: {:?}, Not Dropped", self.inner().cn);
83            return;
84        }
85        //println!("droping vault: {:?}, Dropped", self.inner().cn);
86        atomic::fence(Ordering::Acquire);
87        //self.inner().cn.load(Ordering::Acquire);
88        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
191/// Serve as a `scoped lock` of [Vault], when it is dropped(falls out of scope), [Vault] will be
192/// Available
193pub 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}