From nobody Thu Sep 19 16:37:47 2024 Received: from mail-wm1-f73.google.com (mail-wm1-f73.google.com [209.85.128.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 79D2B13F42A for ; Wed, 14 Aug 2024 08:06:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723622767; cv=none; b=gtqRozsp3QRd0vZicmlGwvYxqzqJ17Ses8+cbFiLwX3Qf0EjdEp9rV9tUQ1k7+8YAxKXKU0WhGcaIXkFlHQxjpIBCG92Th2FWnUWK/bKk9KW99weX6nQ4JDXlt52tVomZqF0SjDZPdC08B8pcRkHBi38rXLXabXpOz56UHm4nAc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723622767; c=relaxed/simple; bh=RTOUzFCL9e4o7YmaN6V8KTg9ssYBxofhtcN5frBXE40=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=PQAT+utT86ob/pIGodor9hXlsh7VtPpQcuEg1qmBce0QCphI59rzViooAOA1+dVegR5qf/1rmhVS5zqxaGdc3pbxCKgAlUlNPlr1+dr6Xww2+Do94237Etc30Es33vMAY0opVC1Rdxmyh623Tryekg8gIYIlikBYcaQ7lZqF47Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=A+aHUVG/; arc=none smtp.client-ip=209.85.128.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="A+aHUVG/" Received: by mail-wm1-f73.google.com with SMTP id 5b1f17b1804b1-4281310bf7aso45011175e9.1 for ; Wed, 14 Aug 2024 01:06:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1723622762; x=1724227562; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=gbfgAGvA710CFpAKP9RmDT9+gw+olEYHRYVTDCVqe6I=; b=A+aHUVG/NTruAvgauVmN6ZHGe28YLAmbza9tXu/3NxG3RF9JqTk+y4dpEuCTpdO1DF FuiK001vmfZczZXKwkc/RLr+c2LQZHGGkITGudK5e6tKeENtFD63pzL05kqnF2gkA1ux 65vtdO/zZkr/ejn2ImGhskksUcVa1IJZXK3Ie7zoxprYQSA9lZLcPUgzs4JUzjKz73HJ B4/ibXRXQ+4rqDxRqTog8D/c0H4oV8cBh0a7cGndMWZxGXDrNuMdHGrY2cWfWjY01ugg aFpN5d/xLHt4MH/TKL7m4OGyYaJzOo6WZp6F3ui3uemcuYXKpr/5bcy2/7jweJ8OP6FI HceQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1723622762; x=1724227562; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=gbfgAGvA710CFpAKP9RmDT9+gw+olEYHRYVTDCVqe6I=; b=Zvj9xCvihigFQ7oahFn8EskrQ1f3roQFD99eIK9wwTWDMmKcVppCiiah35RcxT4VQP 2PMWu8HQl1WjjI++5a0OOk/9Nxfe6fBJtDu24u+c1y+dq+lXesVnTfJ8+StpIP6gcg+F GiZUyWMlKIiUJ1pBRg/TiwpYGdrJ7fBqrJA3o9HjW4I8nqVavjLylVNYYTy5dG4PMGCn PN3f/i6FA2Lpv3Tv7QPgBRZ+8Rt2+pIRXh5yBwr8pwwgiqXs6Y2kAKXQpFQXc06Fz76v GbYT0KD4N3VrLGeYDnYF8z5VPiqJ51PvjsSPmouTRTO5Qfcwy8i7/sJy112ID4l8Y1aB nEvQ== X-Forwarded-Encrypted: i=1; AJvYcCX+Wpv9b4o5jXzbKkTzjHXS8nla8mdZMS0TQzDZR/4YUy45UZ07VuBGWxKVmezPcsiqY5nacT3HxPNdE14=@vger.kernel.org X-Gm-Message-State: AOJu0YzrPDrOO5yda1kKtutMv8+DzfEFgnsqj9HCRBIY566sdlvrovAQ 6HbEjfS7e2fQjqBcZBnq0JuM5xNkY1907ww2ohz3ARfQyJctVfyZ81FyQsNCWwqDwYpESy1mlOG OTJoOtu2etKZNkg== X-Google-Smtp-Source: AGHT+IEWTShI9VkgfCcEDsu2Pz2mWkwmLZMKuvNQVXj4pKsWsDr8W5HESC9nvZ8zxU0dZhgFQr4+JSQpwh9EuyM= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:28:9cb1:c0a8:35bd]) (user=aliceryhl job=sendgmr) by 2002:a05:600c:714:b0:428:1718:957f with SMTP id 5b1f17b1804b1-429dd26a90fmr40035e9.5.1723622761709; Wed, 14 Aug 2024 01:06:01 -0700 (PDT) Date: Wed, 14 Aug 2024 08:05:21 +0000 In-Reply-To: <20240814-linked-list-v5-0-f5f5e8075da0@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20240814-linked-list-v5-0-f5f5e8075da0@google.com> X-Developer-Key: i=aliceryhl@google.com; a=openpgp; fpr=49F6C1FAA74960F43A5B86A1EE7A392FDE96209F X-Developer-Signature: v=1; a=openpgp-sha256; l=17972; i=aliceryhl@google.com; h=from:subject:message-id; bh=RTOUzFCL9e4o7YmaN6V8KTg9ssYBxofhtcN5frBXE40=; b=owEBbQKS/ZANAwAKAQRYvu5YxjlGAcsmYgBmvGVcuhQvrarQowP8V9X4cScychH87LppiBlhR x4W1YQvTN2JAjMEAAEKAB0WIQSDkqKUTWQHCvFIvbIEWL7uWMY5RgUCZrxlXAAKCRAEWL7uWMY5 RvO/EACsRWz1zTXUUktNOdo4A4mOnOYoqGH8vGKpPIDzkRz2b3Nn8Kw5AlRy4KPvoHkmCk2sgJb PRBqphz08feeSBVznG7wMY8ueZ8z/+Z0L0LLWUxykOI/UZ7PwY45Ug2xQBs9emxFPhLPrHUdmXK T3I+qJl651DyytlVjoCyTSiEVdZkopz3qjuOMkRUBLArfDujQSt1o58OUKYFuVD4pHtZvi8e1AY WJOZB6TIu0sRaVBKClKzNx3iRqlqg+t9w2/uI5jURATNuWKLtepmMhIAakWHWGWXZNYYg96GwUJ 6L6u2EyuV9fa0TWaHBNXQPNfEZJNp6U3nsetJ5Jwcsy/A9+jvXXqOhGCjAwgvt9YWAHFjr9O15i EWKRw9gpzEA8Oj6XwsbGqAGX1D+8ffWSQ6IngE+M9VScF59q0ASzL9zWkB+X8Qcmud0aFltDZZb I+J7BQhRJxbfv4Xs8yEUZIz5KNnBg4fLcNsl8ea2Eq2/fTCJH70T5RbTJCX3WSyGYzaa3Jjs2YE 3Guo2Q5PLOOrmmiRAFESaF8x9aJ7G1nnfXIR2FnfhRg23heHQh6IhZYZYw8IZw7CGqqS0KWY62A sXmpiuaKDSIqkgsVYzxI32iF8esz3PzPrk6DVAAUglhLo+xXTCNRrRd8G5/o3CmiPYHAKLNra7d ag8uJR4EUe6b8qg== X-Mailer: b4 0.13.0 Message-ID: <20240814-linked-list-v5-2-f5f5e8075da0@google.com> Subject: [PATCH v5 02/10] rust: list: add ListArc From: Alice Ryhl To: Miguel Ojeda , Andrew Morton Cc: Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Marco Elver , Coly Li , Paolo Abeni , Pierre Gondois , Ingo Molnar , Jakub Kicinski , Wei Yang , Matthew Wilcox , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, Alice Ryhl , Kees Cook Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable The `ListArc` type can be thought of as a special reference to a refcounted object that owns the permission to manipulate the `next`/`prev` pointers stored in the refcounted object. By ensuring that each object has only one `ListArc` reference, the owner of that reference is assured exclusive access to the `next`/`prev` pointers. When a `ListArc` is inserted into a `List`, the `List` takes ownership of the `ListArc` reference. There are various strategies for ensuring that a value has only one `ListArc` reference. The simplest is to convert a `UniqueArc` into a `ListArc`. However, the refcounted object could also keep track of whether a `ListArc` exists using a boolean, which could allow for the creation of new `ListArc` references from an `Arc` reference. Whatever strategy is used, the relevant tracking is referred to as "the tracking inside `T`", and the `ListArcSafe` trait (and its subtraits) are used to update the tracking when a `ListArc` is created or destroyed. Note that we allow the case where the tracking inside `T` thinks that a `ListArc` exists, but actually, there isn't a `ListArc`. However, we do not allow the opposite situation where a `ListArc` exists, but the tracking thinks it doesn't. This is because the former can at most result in us failing to create a `ListArc` when the operation could succeed, whereas the latter can result in the creation of two `ListArc` references. Only the latter situation can lead to memory safety issues. This patch introduces the `impl_list_arc_safe!` macro that allows you to implement `ListArcSafe` for types using the strategy where a `ListArc` can only be created from a `UniqueArc`. Other strategies are introduced in later patches. This is part of the linked list that Rust Binder will use for many different things. The strategy where a `ListArc` can only be created from a `UniqueArc` is actually sufficient for most of the objects that Rust Binder needs to insert into linked lists. Usually, these are todo items that are created and then immediately inserted into a queue. The const generic ID allows objects to have several prev/next pointer pairs so that the same object can be inserted into several different lists. You are able to have several `ListArc` references as long as they correspond to different pointer pairs. The ID itself is purely a compile-time concept and will not be present in the final binary. Both the `List` and the `ListArc` will need to agree on the ID for them to work together. Rust Binder uses this in a few places (e.g. death recipients) where the same object can be inserted into both generic todo lists and some other lists for tracking the status of the object. The ID is a const generic rather than a type parameter because the `pair_from_unique` method needs to be able to assert that the two ids are different. There's no easy way to assert that when using types instead of integers. Reviewed-by: Benno Lossin Signed-off-by: Alice Ryhl --- rust/kernel/lib.rs | 1 + rust/kernel/list.rs | 8 ++ rust/kernel/list/arc.rs | 352 ++++++++++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 361 insertions(+) diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 274bdc1b0a82..9baea9e9ee1a 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -38,6 +38,7 @@ pub mod ioctl; #[cfg(CONFIG_KUNIT)] pub mod kunit; +pub mod list; #[cfg(CONFIG_NET)] pub mod net; pub mod page; diff --git a/rust/kernel/list.rs b/rust/kernel/list.rs new file mode 100644 index 000000000000..fb16ea43b2ba --- /dev/null +++ b/rust/kernel/list.rs @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Google LLC. + +//! A linked list implementation. + +mod arc; +pub use self::arc::{impl_list_arc_safe, ListArc, ListArcSafe}; diff --git a/rust/kernel/list/arc.rs b/rust/kernel/list/arc.rs new file mode 100644 index 000000000000..966076da4a75 --- /dev/null +++ b/rust/kernel/list/arc.rs @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Google LLC. + +//! A wrapper around `Arc` for linked lists. + +use crate::alloc::{AllocError, Flags}; +use crate::prelude::*; +use crate::sync::{Arc, ArcBorrow, UniqueArc}; +use core::marker::Unsize; +use core::ops::Deref; +use core::pin::Pin; + +/// Declares that this type has some way to ensure that there is exactly o= ne `ListArc` instance for +/// this id. +/// +/// Types that implement this trait should include some kind of logic for = keeping track of whether +/// a [`ListArc`] exists or not. We refer to this logic as "the tracking i= nside `T`". +/// +/// We allow the case where the tracking inside `T` thinks that a [`ListAr= c`] exists, but actually, +/// there isn't a [`ListArc`]. However, we do not allow the opposite situa= tion where a [`ListArc`] +/// exists, but the tracking thinks it doesn't. This is because the former= can at most result in us +/// failing to create a [`ListArc`] when the operation could succeed, wher= eas the latter can result +/// in the creation of two [`ListArc`] references. Only the latter situati= on can lead to memory +/// safety issues. +/// +/// A consequence of the above is that you may implement the tracking insi= de `T` by not actually +/// keeping track of anything. To do this, you always claim that a [`ListA= rc`] exists, even if +/// there isn't one. This implementation is allowed by the above rule, but= it means that +/// [`ListArc`] references can only be created if you have ownership of *a= ll* references to the +/// refcounted object, as you otherwise have no way of knowing whether a [= `ListArc`] exists. +pub trait ListArcSafe { + /// Informs the tracking inside this type that it now has a [`ListArc`= ] reference. + /// + /// This method may be called even if the tracking inside this type th= inks that a `ListArc` + /// reference exists. (But only if that's not actually the case.) + /// + /// # Safety + /// + /// Must not be called if a [`ListArc`] already exist for this value. + unsafe fn on_create_list_arc_from_unique(self: Pin<&mut Self>); + + /// Informs the tracking inside this type that there is no [`ListArc`]= reference anymore. + /// + /// # Safety + /// + /// Must only be called if there is no [`ListArc`] reference, but the = tracking thinks there is. + unsafe fn on_drop_list_arc(&self); +} + +/// Declares that this type supports [`ListArc`]. +/// +/// When using this macro, it will only be possible to create a [`ListArc`= ] from a [`UniqueArc`]. +#[macro_export] +macro_rules! impl_list_arc_safe { + (impl$({$($generics:tt)*})? ListArcSafe<$num:tt> for $t:ty { untracked= ; } $($rest:tt)*) =3D> { + impl$(<$($generics)*>)? $crate::list::ListArcSafe<$num> for $t { + unsafe fn on_create_list_arc_from_unique(self: ::core::pin::Pi= n<&mut Self>) {} + unsafe fn on_drop_list_arc(&self) {} + } + $crate::list::impl_list_arc_safe! { $($rest)* } + }; + + () =3D> {}; +} +pub use impl_list_arc_safe; + +/// A wrapper around [`Arc`] that's guaranteed unique for the given id. +/// +/// The `ListArc` type can be thought of as a special reference to a refco= unted object that owns the +/// permission to manipulate the `next`/`prev` pointers stored in the refc= ounted object. By ensuring +/// that each object has only one `ListArc` reference, the owner of that r= eference is assured +/// exclusive access to the `next`/`prev` pointers. When a `ListArc` is in= serted into a `List`, the +/// `List` takes ownership of the `ListArc` reference. +/// +/// There are various strategies to ensuring that a value has only one `Li= stArc` reference. The +/// simplest is to convert a [`UniqueArc`] into a `ListArc`. However, the = refcounted object could +/// also keep track of whether a `ListArc` exists using a boolean, which c= ould allow for the +/// creation of new `ListArc` references from an [`Arc`] reference. Whatev= er strategy is used, the +/// relevant tracking is referred to as "the tracking inside `T`", and the= [`ListArcSafe`] trait +/// (and its subtraits) are used to update the tracking when a `ListArc` i= s created or destroyed. +/// +/// Note that we allow the case where the tracking inside `T` thinks that = a `ListArc` exists, but +/// actually, there isn't a `ListArc`. However, we do not allow the opposi= te situation where a +/// `ListArc` exists, but the tracking thinks it doesn't. This is because = the former can at most +/// result in us failing to create a `ListArc` when the operation could su= cceed, whereas the latter +/// can result in the creation of two `ListArc` references. +/// +/// While this `ListArc` is unique for the given id, there still might exi= st normal `Arc` +/// references to the object. +/// +/// # Invariants +/// +/// * Each reference counted object has at most one `ListArc` for each val= ue of `ID`. +/// * The tracking inside `T` is aware that a `ListArc` reference exists. +#[repr(transparent)] +pub struct ListArc +where + T: ListArcSafe + ?Sized, +{ + arc: Arc, +} + +impl, const ID: u64> ListArc { + /// Constructs a new reference counted instance of `T`. + #[inline] + pub fn new(contents: T, flags: Flags) -> Result { + Ok(Self::from(UniqueArc::new(contents, flags)?)) + } + + /// Use the given initializer to in-place initialize a `T`. + /// + /// If `T: !Unpin` it will not be able to move afterwards. + // We don't implement `InPlaceInit` because `ListArc` is implicitly pi= nned. This is similar to + // what we do for `Arc`. + #[inline] + pub fn pin_init(init: impl PinInit, flags: Flags) -> Result + where + E: From, + { + Ok(Self::from(UniqueArc::try_pin_init(init, flags)?)) + } + + /// Use the given initializer to in-place initialize a `T`. + /// + /// This is equivalent to [`ListArc::pin_init`], since a [`ListArc`= ] is always pinned. + #[inline] + pub fn init(init: impl Init, flags: Flags) -> Result + where + E: From, + { + Ok(Self::from(UniqueArc::try_init(init, flags)?)) + } +} + +impl From> for ListArc +where + T: ListArcSafe + ?Sized, +{ + /// Convert a [`UniqueArc`] into a [`ListArc`]. + #[inline] + fn from(unique: UniqueArc) -> Self { + Self::from(Pin::from(unique)) + } +} + +impl From>> for ListArc +where + T: ListArcSafe + ?Sized, +{ + /// Convert a pinned [`UniqueArc`] into a [`ListArc`]. + #[inline] + fn from(mut unique: Pin>) -> Self { + // SAFETY: We have a `UniqueArc`, so there is no `ListArc`. + unsafe { T::on_create_list_arc_from_unique(unique.as_mut()) }; + let arc =3D Arc::from(unique); + // SAFETY: We just called `on_create_list_arc_from_unique` on an a= rc without a `ListArc`, + // so we can create a `ListArc`. + unsafe { Self::transmute_from_arc(arc) } + } +} + +impl ListArc +where + T: ListArcSafe + ?Sized, +{ + /// Creates two `ListArc`s from a [`UniqueArc`]. + /// + /// The two ids must be different. + #[inline] + pub fn pair_from_unique(unique: UniqueArc) -> (Self= , ListArc) + where + T: ListArcSafe, + { + Self::pair_from_pin_unique(Pin::from(unique)) + } + + /// Creates two `ListArc`s from a pinned [`UniqueArc`]. + /// + /// The two ids must be different. + #[inline] + pub fn pair_from_pin_unique( + mut unique: Pin>, + ) -> (Self, ListArc) + where + T: ListArcSafe, + { + build_assert!(ID !=3D ID2); + + // SAFETY: We have a `UniqueArc`, so there is no `ListArc`. + unsafe { >::on_create_list_arc_from_unique(un= ique.as_mut()) }; + // SAFETY: We have a `UniqueArc`, so there is no `ListArc`. + unsafe { >::on_create_list_arc_from_unique(u= nique.as_mut()) }; + + let arc1 =3D Arc::from(unique); + let arc2 =3D Arc::clone(&arc1); + + // SAFETY: We just called `on_create_list_arc_from_unique` on an a= rc without a `ListArc` + // for both IDs (which are different), so we can create two `ListA= rc`s. + unsafe { + ( + Self::transmute_from_arc(arc1), + ListArc::transmute_from_arc(arc2), + ) + } + } + + /// Transmutes an [`Arc`] into a `ListArc` without updating the tracki= ng inside `T`. + /// + /// # Safety + /// + /// * The value must not already have a `ListArc` reference. + /// * The tracking inside `T` must think that there is a `ListArc` ref= erence. + #[inline] + unsafe fn transmute_from_arc(arc: Arc) -> Self { + // INVARIANT: By the safety requirements, the invariants on `ListA= rc` are satisfied. + Self { arc } + } + + /// Transmutes a `ListArc` into an [`Arc`] without updating the tracki= ng inside `T`. + /// + /// After this call, the tracking inside `T` will still think that the= re is a `ListArc` + /// reference. + #[inline] + fn transmute_to_arc(self) -> Arc { + // Use a transmute to skip destructor. + // + // SAFETY: ListArc is repr(transparent). + unsafe { core::mem::transmute(self) } + } + + /// Convert ownership of this `ListArc` into a raw pointer. + /// + /// The returned pointer is indistinguishable from pointers returned b= y [`Arc::into_raw`]. The + /// tracking inside `T` will still think that a `ListArc` exists after= this call. + #[inline] + pub fn into_raw(self) -> *const T { + Arc::into_raw(Self::transmute_to_arc(self)) + } + + /// Take ownership of the `ListArc` from a raw pointer. + /// + /// # Safety + /// + /// * `ptr` must satisfy the safety requirements of [`Arc::from_raw`]. + /// * The value must not already have a `ListArc` reference. + /// * The tracking inside `T` must think that there is a `ListArc` ref= erence. + #[inline] + pub unsafe fn from_raw(ptr: *const T) -> Self { + // SAFETY: The pointer satisfies the safety requirements for `Arc:= :from_raw`. + let arc =3D unsafe { Arc::from_raw(ptr) }; + // SAFETY: The value doesn't already have a `ListArc` reference, b= ut the tracking thinks it + // does. + unsafe { Self::transmute_from_arc(arc) } + } + + /// Converts the `ListArc` into an [`Arc`]. + #[inline] + pub fn into_arc(self) -> Arc { + let arc =3D Self::transmute_to_arc(self); + // SAFETY: There is no longer a `ListArc`, but the tracking thinks= there is. + unsafe { T::on_drop_list_arc(&arc) }; + arc + } + + /// Clone a `ListArc` into an [`Arc`]. + #[inline] + pub fn clone_arc(&self) -> Arc { + self.arc.clone() + } + + /// Returns a reference to an [`Arc`] from the given [`ListArc`]. + /// + /// This is useful when the argument of a function call is an [`&Arc`]= (e.g., in a method + /// receiver), but we have a [`ListArc`] instead. + /// + /// [`&Arc`]: Arc + #[inline] + pub fn as_arc(&self) -> &Arc { + &self.arc + } + + /// Returns an [`ArcBorrow`] from the given [`ListArc`]. + /// + /// This is useful when the argument of a function call is an [`ArcBor= row`] (e.g., in a method + /// receiver), but we have an [`Arc`] instead. Getting an [`ArcBorrow`= ] is free when optimised. + #[inline] + pub fn as_arc_borrow(&self) -> ArcBorrow<'_, T> { + self.arc.as_arc_borrow() + } + + /// Compare whether two [`ListArc`] pointers reference the same underl= ying object. + #[inline] + pub fn ptr_eq(this: &Self, other: &Self) -> bool { + Arc::ptr_eq(&this.arc, &other.arc) + } +} + +impl Deref for ListArc +where + T: ListArcSafe + ?Sized, +{ + type Target =3D T; + + #[inline] + fn deref(&self) -> &Self::Target { + self.arc.deref() + } +} + +impl Drop for ListArc +where + T: ListArcSafe + ?Sized, +{ + #[inline] + fn drop(&mut self) { + // SAFETY: There is no longer a `ListArc`, but the tracking thinks= there is by the type + // invariants on `Self`. + unsafe { T::on_drop_list_arc(&self.arc) }; + } +} + +impl AsRef> for ListArc +where + T: ListArcSafe + ?Sized, +{ + #[inline] + fn as_ref(&self) -> &Arc { + self.as_arc() + } +} + +// This is to allow [`ListArc`] (and variants) to be used as the type of `= self`. +impl core::ops::Receiver for ListArc where T: Lis= tArcSafe + ?Sized {} + +// This is to allow coercion from `ListArc` to `ListArc` if `T` can = be converted to the +// dynamically-sized type (DST) `U`. +impl core::ops::CoerceUnsized> for Lis= tArc +where + T: ListArcSafe + Unsize + ?Sized, + U: ListArcSafe + ?Sized, +{ +} + +// This is to allow `ListArc` to be dispatched on when `ListArc` can= be coerced into +// `ListArc`. +impl core::ops::DispatchFromDyn> for L= istArc +where + T: ListArcSafe + Unsize + ?Sized, + U: ListArcSafe + ?Sized, +{ +} --=20 2.46.0.76.ge559c4bf1a-goog