idr_ebr/
handles.rs

1use std::{fmt, mem, ops::Deref};
2
3use crate::{
4    config::Config,
5    key::Key,
6    page::{self, Page},
7    slot::Slot,
8    EbrGuard,
9};
10
11// === VacantEntry ===
12
13/// A handle to a vacant entry in an IDR.
14///
15/// It allows constructing values with the key that they will be assigned to.
16///
17/// See [`Idr::vacant_entry()`] for more details.
18///
19/// [`Idr::vacant_entry()`]: crate::Idr::vacant_entry
20#[must_use]
21pub struct VacantEntry<'s, T: 'static, C: Config> {
22    page: &'s Page<T, C>,
23    slot: &'s Slot<T, C>,
24    key: Key,
25}
26
27impl<'s, T: 'static, C: Config> VacantEntry<'s, T, C> {
28    pub(crate) fn new(page: &'s Page<T, C>, slot: &'s Slot<T, C>, key: Key) -> Self {
29        Self { page, slot, key }
30    }
31
32    /// Returns the key at which this entry will be inserted.
33    ///
34    /// An entry stored in this entry will be associated with this key.
35    #[must_use]
36    #[inline]
37    pub fn key(&self) -> Key {
38        self.key
39    }
40
41    /// Inserts a value in the IDR.
42    ///
43    /// This method is wait-free.
44    ///
45    /// To get the key at which this value will be inserted, use
46    /// [`VacantEntry::key()`] prior to calling this method.
47    #[inline]
48    pub fn insert(self, value: T) {
49        self.slot.init(value);
50        mem::forget(self);
51    }
52}
53
54impl<T: 'static, C: Config> Drop for VacantEntry<'_, T, C> {
55    #[inline]
56    fn drop(&mut self) {
57        // SAFETY: The slot belongs to this page by construction.
58        unsafe { self.page.add_free(self.slot) };
59    }
60}
61
62impl<T, C: Config> fmt::Debug for VacantEntry<'_, T, C> {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        f.debug_struct("VacantEntry")
65            .field("key", &self.key)
66            .finish_non_exhaustive()
67    }
68}
69
70// === BorrowedEntry ===
71
72/// A borrowed handle that allows access to an occupied entry in an IDR.
73///
74/// See [`Idr::get()`] for more details.
75///
76/// [`Idr::get()`]: crate::Idr::get
77#[must_use]
78pub struct BorrowedEntry<'g, T>(sdd::Ptr<'g, T> /* non-null */);
79
80impl<'g, T> BorrowedEntry<'g, T> {
81    pub(crate) fn new(ptr: sdd::Ptr<'g, T>) -> Option<Self> {
82        (!ptr.is_null()).then_some(Self(ptr))
83    }
84
85    /// Creates an owned handle to the entry.
86    ///
87    /// It returns `None` if the entry has been removed from the IDR.
88    ///
89    /// This method is lock-free, but it modifies the memory by incrementing the
90    /// reference counter.
91    ///
92    /// See [`OwnedEntry`] for more details.
93    #[inline]
94    pub fn to_owned(self) -> Option<OwnedEntry<T>> {
95        self.0.get_shared().map(OwnedEntry)
96    }
97}
98
99impl<T> Copy for BorrowedEntry<'_, T> {}
100
101impl<T> Clone for BorrowedEntry<'_, T> {
102    #[inline]
103    fn clone(&self) -> Self {
104        *self
105    }
106}
107
108impl<T> Deref for BorrowedEntry<'_, T> {
109    type Target = T;
110
111    #[inline]
112    fn deref(&self) -> &Self::Target {
113        let maybe_ref = self.0.as_ref();
114
115        // SAFETY: The pointer is non-null, checked in `new()`.
116        unsafe { maybe_ref.unwrap_unchecked() }
117    }
118}
119
120impl<T: fmt::Debug> fmt::Debug for BorrowedEntry<'_, T> {
121    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122        fmt::Debug::fmt(&**self, f)
123    }
124}
125
126impl<T: PartialEq<T>> PartialEq<T> for BorrowedEntry<'_, T> {
127    #[inline]
128    fn eq(&self, other: &T) -> bool {
129        (**self).eq(other)
130    }
131}
132
133// === OwnedEntry ===
134
135/// An owned handle that allows access to an occupied entry in an IDR.
136///
137/// See [`Idr::get_owned()`] for more details.
138///
139/// [`Idr::get_owned()`]: crate::Idr::get_owned
140#[must_use]
141pub struct OwnedEntry<T>(sdd::Shared<T>);
142
143impl<T> Clone for OwnedEntry<T> {
144    #[inline]
145    fn clone(&self) -> Self {
146        Self(self.0.clone())
147    }
148}
149
150impl<T> Deref for OwnedEntry<T> {
151    type Target = T;
152
153    #[inline]
154    fn deref(&self) -> &Self::Target {
155        &self.0
156    }
157}
158
159impl<T: fmt::Debug> fmt::Debug for OwnedEntry<T> {
160    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161        fmt::Debug::fmt(&*self.0, f)
162    }
163}
164
165impl<T: PartialEq<T>> PartialEq<T> for OwnedEntry<T> {
166    #[inline]
167    fn eq(&self, other: &T) -> bool {
168        self.0.eq(other)
169    }
170}
171
172// === Iter ===
173
174/// A fused iterator over all occupied entries in the IDR.
175///
176/// See [`Idr::iter()`] for more details.
177///
178/// [`Idr::iter()`]: crate::Idr::iter
179#[must_use]
180pub struct Iter<'g, 's, T, C> {
181    pages: &'s [Page<T, C>],
182    slots: Option<page::Iter<'g, 's, T, C>>,
183    guard: &'g EbrGuard,
184}
185
186impl<'g, 's, T: 'static, C: Config> Iter<'g, 's, T, C> {
187    pub(crate) fn new(pages: &'s [Page<T, C>], guard: &'g EbrGuard) -> Self {
188        let (first, rest) = pages.split_first().expect("invalid MAX_PAGES");
189
190        Self {
191            pages: rest,
192            slots: first.iter(guard),
193            guard,
194        }
195    }
196}
197
198impl<'g, T: 'static, C: Config> Iterator for Iter<'g, '_, T, C> {
199    type Item = (Key, BorrowedEntry<'g, T>);
200
201    fn next(&mut self) -> Option<Self::Item> {
202        loop {
203            let slots = self.slots.as_mut()?;
204
205            if let Some(pair) = slots.next() {
206                return Some(pair);
207            }
208
209            let (slots, rest) = self
210                .pages
211                .split_first()
212                .map(|(next, rest)| (next.iter(self.guard), rest))
213                .unwrap_or_default();
214
215            self.pages = rest;
216            self.slots = slots;
217        }
218    }
219}
220
221impl<T: 'static, C: Config> std::iter::FusedIterator for Iter<'_, '_, T, C> {}
222
223impl<T, C> fmt::Debug for Iter<'_, '_, T, C> {
224    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225        f.debug_struct("Iter").finish_non_exhaustive()
226    }
227}