Skip to main content

arctic/concurrent/
value.rs

1//! Values that can safely be stored in a [`ConcurrentMap`][crate::concurrent::Map],
2//! and referenced behind an [`smr::Guard`].
3
4use core::borrow::Borrow;
5use core::fmt::Debug;
6use core::mem::ManuallyDrop;
7use core::ops::Deref;
8
9use crate::concurrent::smr;
10use crate::concurrent::smr::Guard as _;
11use crate::sequential;
12pub use crate::sequential::value::Arc;
13
14/// Values that can safely be stored in a [`ConcurrentMap`][crate::concurrent::Map].
15///
16/// Values may be either inline or indirect. An inline
17/// value (e.g., [`u64`]) is stored directly in an edge and can be freely
18/// copied. An indirect value (e.g., [`Box<T>`]) is a pointer to a separate
19/// allocation; the pointer is stored in an edge.
20///
21/// Note: we don't need [`Send`] or [`Sync`] bounds here.
22/// It's fine to create a concurrent map with non-Sync
23/// values; the map instance just won't implement Sync.
24pub trait Value: sequential::Value + Borrow<Self::Borrowed> {
25    /// Whether this is an indirect value (otherwise it is inline).
26    const INDIRECT: bool;
27
28    /// We need this extra layer of indirection relative to [`SequentialMap`][crate::sequential::Map]
29    /// because edges can be concurrently modified.
30    ///
31    /// For an inline value, the sequential map can return a reference
32    /// to the edge containing the value; the borrow checker ensures
33    /// the edge is immutable. This is not true for the concurrent map,
34    /// which instead needs to copy out the value and return a reference to
35    /// the copy.
36    ///
37    /// For an indirect value, the concurrent map copies out a pointer
38    /// and interprets it as reference.
39    type Borrowed;
40
41    /// This is a type-level function that allows inline values to
42    /// discard a [`smr::Guard`].
43    type Guard<G>: smr::Guard<Self> + From<G>
44    where
45        G: smr::Guard<Self>;
46
47    /// # Safety
48    ///
49    /// Caller must guarantee the following:
50    /// - `raw` was created from [sequential::Value::into_raw`]
51    /// - There are no calls to [`sequential::Value::from_raw_unchecked`] while `raw` is live
52    /// - This value is not mutated while `raw` is live
53    unsafe fn borrow_from_raw_unchecked(raw: &u64) -> &Self::Borrowed;
54}
55
56macro_rules! impl_integer {
57    ($($ty:ty),*) => {
58        $(
59            impl Value for $ty {
60                const INDIRECT: bool = false;
61
62                type Borrowed = Self;
63
64                type Guard<G>
65                    = smr::no_op::Guard<G, Self>
66                where
67                    G: smr::Guard<Self>;
68
69                #[inline]
70                unsafe fn borrow_from_raw_unchecked(raw: &u64) -> &Self::Borrowed {
71                    unsafe { core::mem::transmute::<&u64, &Self>(raw) }
72                }
73            }
74        )*
75    };
76}
77
78impl_integer!(u64, i64);
79
80// Note: references are inline values because a
81// `&T` itself can be freely copied, even if
82// `T` is not `Copy`.
83impl<'v, T: 'v + Sized> Value for &'v T {
84    const INDIRECT: bool = false;
85
86    type Borrowed = Self;
87
88    type Guard<G>
89        = smr::no_op::Guard<G, Self>
90    where
91        G: smr::Guard<Self>;
92
93    #[inline]
94    unsafe fn borrow_from_raw_unchecked(raw: &u64) -> &Self::Borrowed {
95        unsafe { core::mem::transmute::<&u64, &Self>(raw) }
96    }
97}
98
99impl<T: Sized> Value for Box<T> {
100    const INDIRECT: bool = true;
101
102    type Borrowed = T;
103
104    type Guard<G>
105        = G
106    where
107        G: smr::Guard<Self>;
108
109    #[inline]
110    unsafe fn borrow_from_raw_unchecked(raw: &u64) -> &Self::Borrowed {
111        let borrow = unsafe { core::ptr::with_exposed_provenance::<T>((*raw) as usize).as_ref() };
112        if_validate!(borrow.unwrap(), unsafe { borrow.unwrap_unchecked() })
113    }
114}
115
116impl<T: Sized> Value for Arc<T> {
117    const INDIRECT: bool = true;
118
119    type Borrowed = ArcRef<T>;
120
121    type Guard<G>
122        = G
123    where
124        G: smr::Guard<Self>;
125
126    #[inline]
127    unsafe fn borrow_from_raw_unchecked(raw: &u64) -> &Self::Borrowed {
128        let borrow = unsafe {
129            core::ptr::with_exposed_provenance::<T>((*raw) as usize)
130                .cast::<ArcRef<T>>()
131                .as_ref()
132        };
133        if_validate!(borrow.unwrap(), unsafe { borrow.unwrap_unchecked() })
134    }
135}
136
137impl<T> Borrow<ArcRef<T>> for crate::sequential::value::Arc<T> {
138    fn borrow(&self) -> &ArcRef<T> {
139        unsafe { core::mem::transmute::<&T, &ArcRef<T>>(self.0.as_ref()) }
140    }
141}
142
143/// Transparent wrapper for [`Arc<T>`] pointee that can
144/// be safely cloned into an [`Arc<T>`] via [`ToOwned`].
145#[repr(transparent)]
146#[derive(Debug)]
147pub struct ArcRef<T>(T);
148
149impl<T> Deref for ArcRef<T> {
150    type Target = T;
151    #[inline]
152    fn deref(&self) -> &Self::Target {
153        &self.0
154    }
155}
156
157impl<T> ToOwned for ArcRef<T> {
158    type Owned = Arc<T>;
159    /// Clone into an owned `Arc` by incrementing the strong reference count.
160    fn to_owned(&self) -> Self::Owned {
161        // SAFETY: `ArcRef` is `repr(transparent)`
162        let ptr = unsafe { core::mem::transmute::<&Self, &T>(self) };
163
164        // SAFETY: SMR guarantees `ptr` is not yet freed,
165        // so strong count must be >= 1
166        unsafe { crate::sync::Arc::increment_strong_count(ptr) };
167
168        // SAFETY: `ptr` was returned from `Arc::into_raw`
169        Arc(unsafe { crate::sync::Arc::from_raw(ptr) })
170    }
171}
172
173/// Guard that provides read-only access to a removed value while
174/// preventing the value from being freed. Retires the value on drop.
175///
176/// Note: this value may still be concurrently accessed by other
177/// threads, so this guard cannot safely provide mutable access.
178pub struct Owned<G: smr::Guard<V>, V: Value> {
179    guard: V::Guard<G>,
180    raw: u64,
181}
182
183impl<G, V> Owned<G, V>
184where
185    G: smr::Guard<V>,
186    V: Value,
187{
188    pub(crate) unsafe fn wrap(guard: G, raw: u64) -> Self {
189        Self {
190            guard: V::Guard::<G>::from(guard),
191            raw,
192        }
193    }
194}
195
196impl<G, V> Deref for Owned<G, V>
197where
198    G: smr::Guard<V>,
199    V: Value,
200{
201    type Target = V::Borrowed;
202
203    #[inline]
204    fn deref(&self) -> &Self::Target {
205        unsafe { V::borrow_from_raw_unchecked(&self.raw) }
206    }
207}
208
209impl<G: smr::Guard<V>, V: Value> Drop for Owned<G, V> {
210    fn drop(&mut self) {
211        unsafe { self.guard.retire_value(self.raw) }
212    }
213}
214
215impl<G, V> Debug for Owned<G, V>
216where
217    G: smr::Guard<V>,
218    V: Value,
219    V::Borrowed: Debug,
220{
221    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222        self.deref().fmt(f)
223    }
224}
225
226/// Guard that provides read-only access to a value while
227/// preventing the value from being freed.
228pub struct Shared<G: smr::Guard<V>, V: Value> {
229    _guard: V::Guard<G>,
230    raw: u64,
231}
232
233impl<G, V> Shared<G, V>
234where
235    G: smr::Guard<V>,
236    V: Value,
237{
238    pub(crate) unsafe fn wrap(guard: G, raw: u64) -> Self {
239        Self {
240            _guard: V::Guard::<G>::from(guard),
241            raw,
242        }
243    }
244}
245
246impl<G, V> Deref for Shared<G, V>
247where
248    G: smr::Guard<V>,
249    V: Value,
250{
251    type Target = V::Borrowed;
252
253    #[inline]
254    fn deref(&self) -> &Self::Target {
255        unsafe { V::borrow_from_raw_unchecked(&self.raw) }
256    }
257}
258
259impl<G, V> Debug for Shared<G, V>
260where
261    G: smr::Guard<V>,
262    V: Value,
263    V::Borrowed: Debug,
264{
265    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
266        self.deref().fmt(f)
267    }
268}
269
270/// Guard that provides read-only access to both the old
271/// and new values of an atomic update operation,
272/// preventing both from being freed.
273///
274/// Retires the old value on drop.
275pub struct Updated<G: smr::Guard<V>, V: Value> {
276    guard: V::Guard<G>,
277    old: u64,
278    new: u64,
279}
280
281impl<G, V> Updated<G, V>
282where
283    G: smr::Guard<V>,
284    V: Value,
285{
286    pub(crate) unsafe fn wrap(guard: G, old: u64, new: u64) -> Self {
287        Self {
288            guard: V::Guard::<G>::from(guard),
289            old,
290            new,
291        }
292    }
293
294    /// Return the old value before updating.
295    #[inline]
296    pub fn old(&self) -> &V::Borrowed {
297        unsafe { V::borrow_from_raw_unchecked(&self.old) }
298    }
299
300    /// Return the new value after updating.
301    #[inline]
302    #[expect(clippy::new_ret_no_self)]
303    pub fn new(&self) -> &V::Borrowed {
304        unsafe { V::borrow_from_raw_unchecked(&self.new) }
305    }
306}
307
308impl<G: smr::Guard<V>, V: Value> Drop for Updated<G, V> {
309    fn drop(&mut self) {
310        unsafe { self.guard.retire_value(self.old) }
311    }
312}
313
314impl<G, V> Debug for Updated<G, V>
315where
316    G: smr::Guard<V>,
317    V: Value,
318    V::Borrowed: Debug,
319{
320    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
321        f.debug_struct("Updated")
322            .field("old", self.old())
323            .field("new", self.new())
324            .finish()
325    }
326}
327
328/// Guard that provides read-only access to both the old
329/// and new values of an atomic upsert operation,
330/// preventing both from being freed.
331///
332/// Retires the old value on drop, if it existed.
333pub struct Upserted<G: smr::Guard<V>, V: Value> {
334    guard: V::Guard<G>,
335    old: Option<u64>,
336    new: u64,
337}
338
339impl<G, V> Upserted<G, V>
340where
341    G: smr::Guard<V>,
342    V: Value,
343{
344    pub(crate) unsafe fn wrap(guard: G, old: Option<u64>, new: u64) -> Self {
345        Self {
346            guard: V::Guard::<G>::from(guard),
347            old,
348            new,
349        }
350    }
351
352    pub(crate) fn try_into_inserted(self) -> Result<Shared<G, V>, Self> {
353        // https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216
354        let upserted = ManuallyDrop::new(self);
355
356        match upserted.old {
357            None => Ok(Shared {
358                // HACK: work around not being able to move out of deref
359                _guard: unsafe { core::ptr::read(&upserted.guard) },
360                raw: upserted.new,
361            }),
362            Some(_) => Err(ManuallyDrop::into_inner(upserted)),
363        }
364    }
365
366    /// Return the old value before upserting.
367    #[inline]
368    pub fn old(&self) -> Option<&V::Borrowed> {
369        self.old
370            .as_ref()
371            .map(|old| unsafe { V::borrow_from_raw_unchecked(old) })
372    }
373
374    /// Return the new value after upserting.
375    #[inline]
376    #[expect(clippy::new_ret_no_self)]
377    pub fn new(&self) -> &V::Borrowed {
378        unsafe { V::borrow_from_raw_unchecked(&self.new) }
379    }
380}
381
382impl<G: smr::Guard<V>, V: Value> Drop for Upserted<G, V> {
383    fn drop(&mut self) {
384        let Some(old) = self.old else { return };
385        unsafe { self.guard.retire_value(old) }
386    }
387}
388
389impl<G, V> Debug for Upserted<G, V>
390where
391    G: smr::Guard<V>,
392    V: Value,
393    V::Borrowed: Debug,
394{
395    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
396        f.debug_struct("Upserted")
397            .field("old", &self.old())
398            .field("new", self.new())
399            .finish()
400    }
401}