|
7 | 7 | use crate::{ |
8 | 8 | alloc, |
9 | 9 | prelude::*, |
10 | | - types::{ForeignOwnable, NotThreadSafe, Opaque}, |
| 10 | + types::{ForeignOwnable, NotThreadSafe, Opaque, ScopeGuard}, |
11 | 11 | }; |
12 | 12 | use core::{ |
13 | 13 | fmt, iter, |
@@ -131,6 +131,36 @@ impl<T: ForeignOwnable> XArray<T> { |
131 | 131 | .map_while(|ptr| NonNull::new(ptr.cast())) |
132 | 132 | } |
133 | 133 |
|
| 134 | + /// Looks up and returns a reference to the lowest entry in the array between index and max, |
| 135 | + /// returning a tuple of its index and a `Guard` if one exists. |
| 136 | + /// |
| 137 | + /// This guard blocks all other actions on the `XArray`. Callers are expected to drop the |
| 138 | + /// `Guard` eagerly to avoid blocking other users, such as by taking a clone of the value. |
| 139 | + pub fn find(&self, index: usize, max: usize) -> Option<(usize, ValueGuard<'_, T>)> { |
| 140 | + let mut index: usize = index; |
| 141 | + |
| 142 | + // SAFETY: `self.xa` is always valid by the type invariant. |
| 143 | + unsafe { bindings::xa_lock(self.xa.get()) }; |
| 144 | + |
| 145 | + // SAFETY: `self.xa` is always valid by the type invariant. |
| 146 | + let guard = ScopeGuard::new(|| unsafe { bindings::xa_unlock(self.xa.get()) }); |
| 147 | + |
| 148 | + // SAFETY: `self.xa` is always valid by the type invariant. |
| 149 | + let p = unsafe { bindings::xa_find(self.xa.get(), &mut index, max, bindings::XA_PRESENT) }; |
| 150 | + |
| 151 | + NonNull::new(p as *mut T).map(|ptr| { |
| 152 | + guard.dismiss(); |
| 153 | + ( |
| 154 | + index, |
| 155 | + ValueGuard { |
| 156 | + xa: self, |
| 157 | + ptr, |
| 158 | + _not_send: NotThreadSafe, |
| 159 | + }, |
| 160 | + ) |
| 161 | + }) |
| 162 | + } |
| 163 | + |
134 | 164 | fn with_guard<F, U>(&self, guard: Option<&mut Guard<'_, T>>, f: F) -> U |
135 | 165 | where |
136 | 166 | F: FnOnce(&mut Guard<'_, T>) -> U, |
@@ -187,6 +217,37 @@ impl<T: ForeignOwnable> Drop for Guard<'_, T> { |
187 | 217 | } |
188 | 218 | } |
189 | 219 |
|
| 220 | +/// A lock guard. |
| 221 | +/// |
| 222 | +/// The lock is unlocked when the guard goes out of scope. |
| 223 | +#[must_use = "the lock unlocks immediately when the guard is unused"] |
| 224 | +pub struct ValueGuard<'a, T: ForeignOwnable> { |
| 225 | + xa: &'a XArray<T>, |
| 226 | + ptr: NonNull<T>, |
| 227 | + _not_send: NotThreadSafe, |
| 228 | +} |
| 229 | + |
| 230 | +impl<'a, T: ForeignOwnable> ValueGuard<'a, T> { |
| 231 | + /// Borrow the underlying value wrapped by the `Guard`. |
| 232 | + /// |
| 233 | + /// Returns a `T::Borrowed` type for the owned `ForeignOwnable` type. |
| 234 | + pub fn borrow(&self) -> T::Borrowed<'_> { |
| 235 | + // SAFETY: The value is owned by the `XArray`, the lifetime it is borrowed for must not |
| 236 | + // outlive the `XArray` itself, nor the Guard that holds the lock ensuring the value |
| 237 | + // remains in the `XArray`. |
| 238 | + unsafe { T::borrow(self.ptr.as_ptr() as _) } |
| 239 | + } |
| 240 | +} |
| 241 | + |
| 242 | +impl<T: ForeignOwnable> Drop for ValueGuard<'_, T> { |
| 243 | + fn drop(&mut self) { |
| 244 | + // SAFETY: |
| 245 | + // - `self.xa.xa` is always valid by the type invariant. |
| 246 | + // - The caller holds the lock, so it is safe to unlock it. |
| 247 | + unsafe { bindings::xa_unlock(self.xa.xa.get()) }; |
| 248 | + } |
| 249 | +} |
| 250 | + |
190 | 251 | /// The error returned by [`store`](Guard::store). |
191 | 252 | /// |
192 | 253 | /// Contains the underlying error and the value that was not stored. |
|
0 commit comments