// SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2024 Google LLC. //! A field that is exclusively owned by a [`ListArc`]. //! //! This can be used to have reference counted struct where one of the reference counted pointers //! has exclusive access to a field of the struct. //! //! [`ListArc`]: crate::list::ListArc use core::cell::UnsafeCell; /// A field owned by a specific [`ListArc`]. /// /// [`ListArc`]: crate::list::ListArc pub struct ListArcField { value: UnsafeCell, } // SAFETY: If the inner type is thread-safe, then it's also okay for `ListArc` to be thread-safe. unsafe impl Send for ListArcField {} // SAFETY: If the inner type is thread-safe, then it's also okay for `ListArc` to be thread-safe. unsafe impl Sync for ListArcField {} impl ListArcField { /// Creates a new `ListArcField`. pub fn new(value: T) -> Self { Self { value: UnsafeCell::new(value), } } /// Access the value when we have exclusive access to the `ListArcField`. /// /// This allows access to the field using an `UniqueArc` instead of a `ListArc`. pub fn get_mut(&mut self) -> &mut T { self.value.get_mut() } /// Unsafely assert that you have shared access to the `ListArc` for this field. /// /// # Safety /// /// The caller must have shared access to the `ListArc` containing the struct with this /// field for the duration of the returned reference. pub unsafe fn assert_ref(&self) -> &T { // SAFETY: The caller has shared access to the `ListArc`, so they also have shared access // to this field. unsafe { &*self.value.get() } } /// Unsafely assert that you have mutable access to the `ListArc` for this field. /// /// # Safety /// /// The caller must have mutable access to the `ListArc` containing the struct with this /// field for the duration of the returned reference. #[allow(clippy::mut_from_ref)] pub unsafe fn assert_mut(&self) -> &mut T { // SAFETY: The caller has exclusive access to the `ListArc`, so they also have exclusive // access to this field. unsafe { &mut *self.value.get() } } } /// Defines getters for a [`ListArcField`]. #[macro_export] macro_rules! define_list_arc_field_getter { ($pub:vis fn $name:ident(&self $(<$id:tt>)?) -> &$typ:ty { $field:ident } $($rest:tt)* ) => { $pub fn $name<'a>(self: &'a $crate::list::ListArc) -> &'a $typ { let field = &(&**self).$field; // SAFETY: We have a shared reference to the `ListArc`. unsafe { $crate::list::ListArcField::<$typ $(, $id)?>::assert_ref(field) } } $crate::list::define_list_arc_field_getter!($($rest)*); }; ($pub:vis fn $name:ident(&mut self $(<$id:tt>)?) -> &mut $typ:ty { $field:ident } $($rest:tt)* ) => { $pub fn $name<'a>(self: &'a mut $crate::list::ListArc) -> &'a mut $typ { let field = &(&**self).$field; // SAFETY: We have a mutable reference to the `ListArc`. unsafe { $crate::list::ListArcField::<$typ $(, $id)?>::assert_mut(field) } } $crate::list::define_list_arc_field_getter!($($rest)*); }; () => {}; } pub use define_list_arc_field_getter;