lock_freedom/map/
insertion.rs

1use super::Removed;
2use core::{mem::forget, ptr::NonNull};
3use owned_alloc::{OwnedAlloc, UninitAlloc};
4
5/// A [`insert_with`](super::Map::insert_with) operation result.
6#[derive(Debug, PartialEq, Eq)]
7pub enum Insertion<K, V, E> {
8    /// The entry was created.
9    Created,
10    /// The entry was updated and this was the old pair.
11    Updated(Removed<K, V>),
12    /// The insertion failed and no operation was performed. Failure of an
13    /// insertion might happen because the closure rejected the conditions.
14    /// Another reason is that method-specific contract was not respected (such
15    /// as the one of [`reinsert_with`](super::Map::reinsert_with)).
16    Failed(E),
17}
18
19impl<K, V, E> Insertion<K, V, E> {
20    /// Returns whether the insertion created an entry.
21    pub fn created(&self) -> bool {
22        matches!(self, Insertion::Created)
23    }
24
25    /// Returns whether the insertion updated an entry.
26    pub fn updated(&self) -> Option<&Removed<K, V>> {
27        match self {
28            Insertion::Updated(pair) => Some(pair),
29            _ => None,
30        }
31    }
32
33    /// Tries to take the updated entry of this insertion and encodes it as a
34    /// [`Result`]. [`Ok`] is returned only if this insertion updated a value.
35    pub fn take_updated(self) -> Result<Removed<K, V>, Self> {
36        match self {
37            Insertion::Updated(pair) => Ok(pair),
38            this => Err(this),
39        }
40    }
41
42    /// Returns whether the insertion failed.
43    pub fn failed(&self) -> Option<&E> {
44        match self {
45            Insertion::Failed(err) => Some(err),
46            _ => None,
47        }
48    }
49
50    /// Tries to take the failure of this insertion and encodes it as a
51    /// [`Result`]. [`Ok`] is returned only if this insertion has a failure.
52    pub fn take_failed(self) -> Result<E, Self> {
53        match self {
54            Insertion::Failed(e) => Ok(e),
55            this => Err(this),
56        }
57    }
58}
59
60/// The preview of an _interactive_ insertion. It is used by the
61/// [`insert_with`](super::Map::insert_with) method and it is the return value
62/// of the closure passed to the method.
63#[derive(Debug, Clone, Copy, PartialEq, Eq)]
64pub enum Preview<V> {
65    /// Tells the [`Map`](super::Map) to discard the currently generated value.
66    /// After this return value, the insertion is probably canceled and it
67    /// fails. However, concurrent accesses to the [`Map`](super::Map) may
68    /// cause the conditions to be tested again.
69    Discard,
70    /// Tells the [`Map`](super::Map) to keep the currently generated value. If
71    /// there was no generated value, this has the same effect as
72    /// [`Preview::Discard`].
73    Keep,
74    /// Tells the `Map to use this value instead of the previously generated
75    /// (if any).
76    New(V),
77}
78
79// A trait we use to insert stuff with interactive generation of entries and
80// validation of conditions.
81pub trait Inserter<K, V>: Sized {
82    // Feed the inserter with this found pair, if any.
83    fn input(&mut self, found: Option<&(K, V)>);
84
85    // The pointer to memory allocated via `OwnedAlloc`, given the conditions
86    // fed by `input`. Return `None` to reject the conditions.
87    fn pointer(&self) -> Option<NonNull<(K, V)>>;
88
89    // Simply access the key. Must not fail.
90    fn key(&self) -> &K;
91
92    // Take ownership of the pointer's allocation.
93    fn take_pointer(self) {
94        forget(self);
95    }
96}
97
98// An inserter which inserts a new allocation.
99pub struct InsertNew<F, K, V>
100where
101    F: FnMut(&K, Option<&mut V>, Option<&(K, V)>) -> Preview<V>,
102{
103    interactive: F,
104    nnptr: NonNull<(K, V)>,
105    is_val_init: bool,
106}
107
108impl<F, K, V> InsertNew<F, K, V>
109where
110    F: FnMut(&K, Option<&mut V>, Option<&(K, V)>) -> Preview<V>,
111{
112    pub fn with_key(interactive: F, key: K) -> Self {
113        Self {
114            interactive,
115            // I know it sounds weird, but we need to initialize just the key.
116            // We handle it in drop through the field `is_val_init`.
117            nnptr: unsafe {
118                let alloc =
119                    UninitAlloc::new().init_in_place(|(key_mem, _)| (key_mem as *mut K).write(key));
120                alloc.into_raw()
121            },
122            is_val_init: false,
123        }
124    }
125
126    pub fn with_pair(interactive: F, pair: (K, V)) -> Self {
127        Self {
128            interactive,
129            nnptr: OwnedAlloc::new(pair).forget_inner().into_raw(),
130            is_val_init: true,
131        }
132    }
133
134    pub fn into_pair(self) -> (K, Option<V>) {
135        // Doing this is safe by itself. However, callers should be careful if
136        // they used the pointer.
137        let ((key, val), _) = unsafe { OwnedAlloc::from_raw(self.nnptr) }.move_inner();
138        // Note we check for the case in which val is uninitialized.
139        let val = if self.is_val_init {
140            Some(val)
141        } else {
142            forget(val);
143            None
144        };
145        forget(self);
146        (key, val)
147    }
148}
149
150impl<F, K, V> Drop for InsertNew<F, K, V>
151where
152    F: FnMut(&K, Option<&mut V>, Option<&(K, V)>) -> Preview<V>,
153{
154    fn drop(&mut self) {
155        // Must be safe. Callers should forget the inserter if they are
156        // using the pointer. Note we check if the value is uninitialized.
157        if self.is_val_init {
158            unsafe { OwnedAlloc::from_raw(self.nnptr) };
159        } else {
160            unsafe {
161                {
162                    let (key, _) = self.nnptr.as_mut();
163                    (key as *mut K).drop_in_place();
164                }
165                UninitAlloc::from_raw(self.nnptr);
166            }
167        }
168    }
169}
170
171impl<F, K, V> Inserter<K, V> for InsertNew<F, K, V>
172where
173    F: FnMut(&K, Option<&mut V>, Option<&(K, V)>) -> Preview<V>,
174{
175    fn input(&mut self, found: Option<&(K, V)>) {
176        // This is safe. This allocation is owned by us.
177        let (key, val) = unsafe { self.nnptr.as_mut() };
178
179        let preview = {
180            let val = if self.is_val_init {
181                Some(&mut *val)
182            } else {
183                None
184            };
185            (self.interactive)(key, val, found)
186        };
187
188        match preview {
189            Preview::Discard if self.is_val_init => {
190                self.is_val_init = false;
191                // Safe because we check for the initialization of the value and
192                // we update it too.
193                unsafe { (val as *mut V).drop_in_place() };
194            }
195
196            Preview::New(new_val) => {
197                if self.is_val_init {
198                    *val = new_val;
199                } else {
200                    self.is_val_init = true;
201                    // Safe because we check for the initialization of the value
202                    // and we update it too.
203                    unsafe { (val as *mut V).write(new_val) };
204                }
205            }
206
207            _ => (),
208        }
209    }
210
211    fn pointer(&self) -> Option<NonNull<(K, V)>> {
212        if self.is_val_init {
213            Some(self.nnptr)
214        } else {
215            None
216        }
217    }
218
219    fn key(&self) -> &K {
220        // This is safe. This allocation is owned by us
221        let (key, _) = unsafe { self.nnptr.as_ref() };
222        key
223    }
224}
225
226// An inserter which reinserts a previously removed allocation.
227pub struct Reinsert<F, K, V>
228where
229    F: FnMut(&(K, V), Option<&(K, V)>) -> bool,
230{
231    interactive: F,
232    removed: Removed<K, V>,
233    is_valid: bool,
234}
235
236impl<F, K, V> Reinsert<F, K, V>
237where
238    F: FnMut(&(K, V), Option<&(K, V)>) -> bool,
239{
240    pub fn new(interactive: F, removed: Removed<K, V>) -> Self {
241        Self {
242            interactive,
243            removed,
244            is_valid: false,
245        }
246    }
247
248    pub fn into_removed(self) -> Removed<K, V> {
249        self.removed
250    }
251}
252
253impl<F, K, V> Inserter<K, V> for Reinsert<F, K, V>
254where
255    F: FnMut(&(K, V), Option<&(K, V)>) -> bool,
256{
257    fn input(&mut self, found: Option<&(K, V)>) {
258        self.is_valid = (self.interactive)(&self.removed, found);
259    }
260
261    fn pointer(&self) -> Option<NonNull<(K, V)>> {
262        if self.is_valid {
263            Some(Removed::raw(&self.removed))
264        } else {
265            None
266        }
267    }
268
269    fn key(&self) -> &K {
270        let (key, _) = &*self.removed;
271        key
272    }
273
274    fn take_pointer(self) {
275        forget(Removed::into_alloc(self.removed));
276    }
277}