|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
| 2 | + |
| 3 | +// Copyright (C) 2024 Google LLC. |
| 4 | + |
| 5 | +//! A wrapper around `Arc` for linked lists. |
| 6 | +
|
| 7 | +use crate::alloc::{AllocError, Flags}; |
| 8 | +use crate::prelude::*; |
| 9 | +use crate::sync::{Arc, ArcBorrow, UniqueArc}; |
| 10 | +use core::marker::Unsize; |
| 11 | +use core::ops::Deref; |
| 12 | +use core::pin::Pin; |
| 13 | + |
| 14 | +/// Declares that this type has some way to ensure that there is exactly one `ListArc` instance for |
| 15 | +/// this id. |
| 16 | +pub trait ListArcSafe<const ID: u64 = 0> { |
| 17 | + /// Informs the tracking inside this type that it now has a [`ListArc`] reference. |
| 18 | + /// |
| 19 | + /// This method may be called even if the tracking inside this type thinks that a `ListArc` |
| 20 | + /// reference exists. (But only if that's not actually the case.) |
| 21 | + /// |
| 22 | + /// # Safety |
| 23 | + /// |
| 24 | + /// Must not be called if a [`ListArc`] already exist for this value. |
| 25 | + unsafe fn on_create_list_arc_from_unique(self: Pin<&mut Self>); |
| 26 | + |
| 27 | + /// Informs the tracking inside this type that there is no [`ListArc`] reference anymore. |
| 28 | + /// |
| 29 | + /// # Safety |
| 30 | + /// |
| 31 | + /// Must only be called if there is no [`ListArc`] reference, but the tracking thinks there is. |
| 32 | + unsafe fn on_drop_list_arc(&self); |
| 33 | +} |
| 34 | + |
| 35 | +/// Declares that this type supports [`ListArc`]. |
| 36 | +/// |
| 37 | +/// When using this macro, it will only be possible to create a [`ListArc`] from a [`UniqueArc`]. |
| 38 | +#[macro_export] |
| 39 | +macro_rules! impl_list_arc_safe { |
| 40 | + (impl$({$($generics:tt)*})? ListArcSafe<$num:tt> for $t:ty { untracked; } $($rest:tt)*) => { |
| 41 | + impl$(<$($generics)*>)? $crate::list::ListArcSafe<$num> for $t { |
| 42 | + unsafe fn on_create_list_arc_from_unique(self: ::core::pin::Pin<&mut Self>) {} |
| 43 | + unsafe fn on_drop_list_arc(&self) {} |
| 44 | + } |
| 45 | + $crate::list::impl_list_arc_safe! { $($rest)* } |
| 46 | + }; |
| 47 | + |
| 48 | + () => {}; |
| 49 | +} |
| 50 | +pub use impl_list_arc_safe; |
| 51 | + |
| 52 | +/// A wrapper around [`Arc`] that's guaranteed unique for the given id. |
| 53 | +/// |
| 54 | +/// The `ListArc` type can be thought of as a special reference to a refcounted object that owns the |
| 55 | +/// permission to manipulate the `next`/`prev` pointers stored in the refcounted object. By ensuring |
| 56 | +/// that each object has only one `ListArc` reference, the owner of that reference is assured |
| 57 | +/// exclusive access to the `next`/`prev` pointers. When a `ListArc` is inserted into a `List`, the |
| 58 | +/// `List` takes ownership of the `ListArc` reference. |
| 59 | +/// |
| 60 | +/// There are various strategies to ensuring that a value has only one `ListArc` reference. The |
| 61 | +/// simplest is to convert a [`UniqueArc`] into a `ListArc`. However, the refcounted object could |
| 62 | +/// also keep track of whether a `ListArc` exists using a boolean, which could allow for the |
| 63 | +/// creation of new `ListArc` references from an [`Arc`] reference. Whatever strategy is used, the |
| 64 | +/// relevant tracking is referred to as "the tracking inside `T`", and the [`ListArcSafe`] trait |
| 65 | +/// (and its subtraits) are used to update the tracking when a `ListArc` is created or destroyed. |
| 66 | +/// |
| 67 | +/// Note that we allow the case where the tracking inside `T` thinks that a `ListArc` exists, but |
| 68 | +/// actually, there isn't a `ListArc`. However, we do not allow the opposite situation where a |
| 69 | +/// `ListArc` exists, but the tracking thinks it doesn't. This is because the former can at most |
| 70 | +/// result in us failing to create a `ListArc` when the operation could succeed, whereas the latter |
| 71 | +/// can result in the creation of two `ListArc` references. |
| 72 | +/// |
| 73 | +/// # Invariants |
| 74 | +/// |
| 75 | +/// * Each reference counted object has at most one `ListArc` for each value of `ID`. |
| 76 | +/// * The tracking inside `T` is aware that a `ListArc` reference exists. |
| 77 | +#[repr(transparent)] |
| 78 | +pub struct ListArc<T, const ID: u64 = 0> |
| 79 | +where |
| 80 | + T: ListArcSafe<ID> + ?Sized, |
| 81 | +{ |
| 82 | + arc: Arc<T>, |
| 83 | +} |
| 84 | + |
| 85 | +impl<T: ListArcSafe<ID>, const ID: u64> ListArc<T, ID> { |
| 86 | + /// Constructs a new reference counted instance of `T`. |
| 87 | + #[inline] |
| 88 | + pub fn new(contents: T, flags: Flags) -> Result<Self, AllocError> { |
| 89 | + Ok(Self::from_unique(UniqueArc::new(contents, flags)?)) |
| 90 | + } |
| 91 | + |
| 92 | + /// Use the given initializer to in-place initialize a `T`. |
| 93 | + /// |
| 94 | + /// If `T: !Unpin` it will not be able to move afterwards. |
| 95 | + // We don't implement `InPlaceInit` because `ListArc` is implicitly pinned. This is similar to |
| 96 | + // what we do for `Arc`. |
| 97 | + #[inline] |
| 98 | + pub fn pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self, E> |
| 99 | + where |
| 100 | + E: From<AllocError>, |
| 101 | + { |
| 102 | + Ok(Self::from_pin_unique(UniqueArc::try_pin_init(init, flags)?)) |
| 103 | + } |
| 104 | + |
| 105 | + /// Use the given initializer to in-place initialize a `T`. |
| 106 | + /// |
| 107 | + /// This is equivalent to [`ListArc<T>::pin_init`], since a [`ListArc`] is always pinned. |
| 108 | + #[inline] |
| 109 | + pub fn init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E> |
| 110 | + where |
| 111 | + E: From<AllocError>, |
| 112 | + { |
| 113 | + Ok(Self::from_unique(UniqueArc::try_init(init, flags)?)) |
| 114 | + } |
| 115 | +} |
| 116 | + |
| 117 | +impl<T, const ID: u64> ListArc<T, ID> |
| 118 | +where |
| 119 | + T: ListArcSafe<ID> + ?Sized, |
| 120 | +{ |
| 121 | + /// Convert a [`UniqueArc`] into a [`ListArc`]. |
| 122 | + #[inline] |
| 123 | + pub fn from_unique(unique: UniqueArc<T>) -> Self { |
| 124 | + Self::from_pin_unique(Pin::from(unique)) |
| 125 | + } |
| 126 | + |
| 127 | + /// Convert a pinned [`UniqueArc`] into a [`ListArc`]. |
| 128 | + #[inline] |
| 129 | + pub fn from_pin_unique(mut unique: Pin<UniqueArc<T>>) -> Self { |
| 130 | + // SAFETY: We have a `UniqueArc`, so there is no `ListArc`. |
| 131 | + unsafe { T::on_create_list_arc_from_unique(unique.as_mut()) }; |
| 132 | + let arc = Arc::from(unique); |
| 133 | + // SAFETY: We just called `on_create_list_arc_from_unique` on an arc without a `ListArc`, |
| 134 | + // so we can create a `ListArc`. |
| 135 | + unsafe { Self::transmute_from_arc(arc) } |
| 136 | + } |
| 137 | + |
| 138 | + /// Like [`from_unique`], but creates two `ListArcs`. |
| 139 | + /// |
| 140 | + /// The two ids must be different. |
| 141 | + /// |
| 142 | + /// [`from_unique`]: ListArc::from_unique |
| 143 | + #[inline] |
| 144 | + pub fn pair_from_unique<const ID2: u64>(unique: UniqueArc<T>) -> (Self, ListArc<T, ID2>) |
| 145 | + where |
| 146 | + T: ListArcSafe<ID2>, |
| 147 | + { |
| 148 | + Self::pair_from_pin_unique(Pin::from(unique)) |
| 149 | + } |
| 150 | + |
| 151 | + /// Like [`pair_from_unique`], but uses a pinned arc. |
| 152 | + /// |
| 153 | + /// The two ids must be different. |
| 154 | + /// |
| 155 | + /// [`pair_from_unique`]: ListArc::pair_from_unique |
| 156 | + #[inline] |
| 157 | + pub fn pair_from_pin_unique<const ID2: u64>( |
| 158 | + mut unique: Pin<UniqueArc<T>>, |
| 159 | + ) -> (Self, ListArc<T, ID2>) |
| 160 | + where |
| 161 | + T: ListArcSafe<ID2>, |
| 162 | + { |
| 163 | + build_assert!(ID != ID2); |
| 164 | + |
| 165 | + // SAFETY: We have a `UniqueArc`, so there is no `ListArc`. |
| 166 | + unsafe { <T as ListArcSafe<ID>>::on_create_list_arc_from_unique(unique.as_mut()) }; |
| 167 | + // SAFETY: We have a `UniqueArc`, so there is no `ListArc`. |
| 168 | + unsafe { <T as ListArcSafe<ID2>>::on_create_list_arc_from_unique(unique.as_mut()) }; |
| 169 | + |
| 170 | + let arc1 = Arc::from(unique); |
| 171 | + let arc2 = Arc::clone(&arc1); |
| 172 | + |
| 173 | + // SAFETY: We just called `on_create_list_arc_from_unique` on an arc without a `ListArc` |
| 174 | + // for both IDs (which are different), so we can create two `ListArc`s. |
| 175 | + unsafe { |
| 176 | + ( |
| 177 | + Self::transmute_from_arc(arc1), |
| 178 | + ListArc::transmute_from_arc(arc2), |
| 179 | + ) |
| 180 | + } |
| 181 | + } |
| 182 | + |
| 183 | + /// Transmutes an [`Arc`] into a `ListArc` without updating the tracking inside `T`. |
| 184 | + /// |
| 185 | + /// # Safety |
| 186 | + /// |
| 187 | + /// * The value must not already have a `ListArc` reference. |
| 188 | + /// * The tracking inside `T` must think that there is a `ListArc` reference. |
| 189 | + #[inline] |
| 190 | + unsafe fn transmute_from_arc(arc: Arc<T>) -> Self { |
| 191 | + // INVARIANT: By the safety requirements, the invariants on `ListArc` are satisfied. |
| 192 | + Self { arc } |
| 193 | + } |
| 194 | + |
| 195 | + /// Transmutes a `ListArc` into an [`Arc`] without updating the tracking inside `T`. |
| 196 | + /// |
| 197 | + /// After this call, the tracking inside `T` will still think that there is a `ListArc` |
| 198 | + /// reference. |
| 199 | + #[inline] |
| 200 | + fn transmute_to_arc(self) -> Arc<T> { |
| 201 | + // SAFETY: ListArc is repr(transparent). |
| 202 | + unsafe { core::mem::transmute(self) } |
| 203 | + } |
| 204 | + |
| 205 | + /// Convert ownership of this `ListArc` into a raw pointer. |
| 206 | + /// |
| 207 | + /// The returned pointer is indistinguishable from pointers returned by [`Arc::into_raw`]. The |
| 208 | + /// tracking inside `T` will still think that a `ListArc` exists after this call. |
| 209 | + #[inline] |
| 210 | + pub fn into_raw(self) -> *const T { |
| 211 | + Arc::into_raw(Self::transmute_to_arc(self)) |
| 212 | + } |
| 213 | + |
| 214 | + /// Take ownership of the `ListArc` from a raw pointer. |
| 215 | + /// |
| 216 | + /// # Safety |
| 217 | + /// |
| 218 | + /// * `ptr` must satisfy the safety requirements of [`Arc::from_raw`]. |
| 219 | + /// * The value must not already have a `ListArc` reference. |
| 220 | + /// * The tracking inside `T` must think that there is a `ListArc` reference. |
| 221 | + #[inline] |
| 222 | + pub unsafe fn from_raw(ptr: *const T) -> Self { |
| 223 | + // SAFETY: The pointer satisfies the safety requirements for `Arc::from_raw`. |
| 224 | + let arc = unsafe { Arc::from_raw(ptr) }; |
| 225 | + // SAFETY: The value doesn't already have a `ListArc` reference, but the tracking thinks it |
| 226 | + // does. |
| 227 | + unsafe { Self::transmute_from_arc(arc) } |
| 228 | + } |
| 229 | + |
| 230 | + /// Converts the `ListArc` into an [`Arc`]. |
| 231 | + #[inline] |
| 232 | + pub fn into_arc(self) -> Arc<T> { |
| 233 | + let arc = Self::transmute_to_arc(self); |
| 234 | + // SAFETY: There is no longer a `ListArc`, but the tracking thinks there is. |
| 235 | + unsafe { T::on_drop_list_arc(&arc) }; |
| 236 | + arc |
| 237 | + } |
| 238 | + |
| 239 | + /// Clone a `ListArc` into an [`Arc`]. |
| 240 | + #[inline] |
| 241 | + pub fn clone_arc(&self) -> Arc<T> { |
| 242 | + self.arc.clone() |
| 243 | + } |
| 244 | + |
| 245 | + /// Returns a reference to an [`Arc`] from the given [`ListArc`]. |
| 246 | + /// |
| 247 | + /// This is useful when the argument of a function call is an [`&Arc`] (e.g., in a method |
| 248 | + /// receiver), but we have a [`ListArc`] instead. |
| 249 | + /// |
| 250 | + /// [`&Arc`]: Arc |
| 251 | + #[inline] |
| 252 | + pub fn as_arc(&self) -> &Arc<T> { |
| 253 | + &self.arc |
| 254 | + } |
| 255 | + |
| 256 | + /// Returns an [`ArcBorrow`] from the given [`ListArc`]. |
| 257 | + /// |
| 258 | + /// This is useful when the argument of a function call is an [`ArcBorrow`] (e.g., in a method |
| 259 | + /// receiver), but we have an [`Arc`] instead. Getting an [`ArcBorrow`] is free when optimised. |
| 260 | + #[inline] |
| 261 | + pub fn as_arc_borrow(&self) -> ArcBorrow<'_, T> { |
| 262 | + self.arc.as_arc_borrow() |
| 263 | + } |
| 264 | + |
| 265 | + /// Compare whether two [`ListArc`] pointers reference the same underlying object. |
| 266 | + #[inline] |
| 267 | + pub fn ptr_eq(this: &Self, other: &Self) -> bool { |
| 268 | + Arc::ptr_eq(&this.arc, &other.arc) |
| 269 | + } |
| 270 | +} |
| 271 | + |
| 272 | +impl<T, const ID: u64> Deref for ListArc<T, ID> |
| 273 | +where |
| 274 | + T: ListArcSafe<ID> + ?Sized, |
| 275 | +{ |
| 276 | + type Target = T; |
| 277 | + |
| 278 | + #[inline] |
| 279 | + fn deref(&self) -> &Self::Target { |
| 280 | + self.arc.deref() |
| 281 | + } |
| 282 | +} |
| 283 | + |
| 284 | +impl<T, const ID: u64> Drop for ListArc<T, ID> |
| 285 | +where |
| 286 | + T: ListArcSafe<ID> + ?Sized, |
| 287 | +{ |
| 288 | + #[inline] |
| 289 | + fn drop(&mut self) { |
| 290 | + // SAFETY: There is no longer a `ListArc`, but the tracking thinks there is by the type |
| 291 | + // invariants on `Self`. |
| 292 | + unsafe { T::on_drop_list_arc(&self.arc) }; |
| 293 | + } |
| 294 | +} |
| 295 | + |
| 296 | +// This is to allow [`ListArc`] (and variants) to be used as the type of `self`. |
| 297 | +impl<T, const ID: u64> core::ops::Receiver for ListArc<T, ID> where T: ListArcSafe<ID> + ?Sized {} |
| 298 | + |
| 299 | +// This is to allow coercion from `ListArc<T>` to `ListArc<U>` if `T` can be converted to the |
| 300 | +// dynamically-sized type (DST) `U`. |
| 301 | +impl<T, U, const ID: u64> core::ops::CoerceUnsized<ListArc<U, ID>> for ListArc<T, ID> |
| 302 | +where |
| 303 | + T: ListArcSafe<ID> + Unsize<U> + ?Sized, |
| 304 | + U: ListArcSafe<ID> + ?Sized, |
| 305 | +{ |
| 306 | +} |
| 307 | + |
| 308 | +// This is to allow `ListArc<U>` to be dispatched on when `ListArc<T>` can be coerced into |
| 309 | +// `ListArc<U>`. |
| 310 | +impl<T, U, const ID: u64> core::ops::DispatchFromDyn<ListArc<U, ID>> for ListArc<T, ID> |
| 311 | +where |
| 312 | + T: ListArcSafe<ID> + Unsize<U> + ?Sized, |
| 313 | + U: ListArcSafe<ID> + ?Sized, |
| 314 | +{ |
| 315 | +} |
0 commit comments