use core::cell::UnsafeCell; use core::marker::PhantomData; use core::mem; use core::ptr::{drop_in_place, read, NonNull}; use core::sync::atomic::{AtomicBool, Ordering};
externcrate alloc;
use alloc::alloc::{dealloc, Layout};
// Self referential structs are currently not supported with safe vanilla Rust. // The only reasonable safe alternative is to expect the user to juggle 2 separate // data structures which is a mess. The library solution rental is both no longer // maintained and really heavy to compile. So begrudgingly I rolled my own version. // These are some of the core invariants we require for this to be safe to use. // // 1. owner is initialized when UnsafeSelfCell is constructed. // 2. owner is NEVER changed again. // 3. The pointer to owner and dependent never changes, even when moved. // 4. The only access to owner and dependent is as immutable reference. // 5. owner lives longer than dependent.
// Library controlled struct that marks all accesses as unsafe. // Because the macro generated struct impl can be extended, could be unsafe. #[doc(hidden)] pubstruct UnsafeSelfCell<ContainedIn, Owner, DependentStatic: 'static> {
joined_void_ptr: NonNull<u8>,
// ContainedIn is necessary for type safety since we don't fully // prohibit access to the UnsafeSelfCell; swapping between different // structs can be unsafe otherwise, see Issue #17.
contained_in_marker: PhantomData<ContainedIn>,
owner_marker: PhantomData<Owner>, // DependentStatic is only used to correctly derive Send and Sync.
dependent_marker: PhantomData<DependentStatic>,
}
// This function used to return `&'a mut JoinedCell<Owner, Dependent>`. // It now creates two references to the fields instead to avoid claiming mutable access // to the whole `JoinedCell` (including the owner!) here.
(
&(*joined_ptr.as_ptr()).owner,
&mut (*joined_ptr.as_ptr()).dependent,
)
}
// Any subsequent use of this struct other than dropping it is UB. pubunsafefn drop_joined<Dependent>(&mutself) { let joined_ptr = self.joined_void_ptr.cast::<JoinedCell<Owner, Dependent>>();
// Also used in case drop_in_place(...dependent) fails let _guard = OwnerAndCellDropGuard { joined_ptr };
// IMPORTANT dependent must be dropped before owner. // We don't want to rely on an implicit order of struct fields. // So we drop the struct, field by field manually.
drop_in_place(&mut (*joined_ptr.as_ptr()).dependent);
// Dropping owner // and deallocating // due to _guard at end of scope.
}
pubunsafefn into_owner<Dependent>(self) -> Owner { let joined_ptr = self.joined_void_ptr.cast::<JoinedCell<Owner, Dependent>>();
// In case drop_in_place(...dependent) fails let drop_guard = OwnerAndCellDropGuard::new(joined_ptr);
// Drop dependent
drop_in_place(&mut (*joined_ptr.as_ptr()).dependent);
mem::forget(drop_guard);
let owner_ptr: *const Owner = &(*joined_ptr.as_ptr()).owner;
// Move owner out so it can be returned. // Must not read before dropping dependent!! (Which happened above.) let owner = read(owner_ptr);
// Deallocate JoinedCell let layout = Layout::new::<JoinedCell<Owner, Dependent>>();
dealloc(self.joined_void_ptr.as_ptr(), layout);
owner
}
}
unsafeimpl<ContainedIn, Owner, DependentStatic> Send for UnsafeSelfCell<ContainedIn, Owner, DependentStatic> where // Only derive Send if Owner and DependentStatic is also Send
Owner: Send,
DependentStatic: Send,
{
}
unsafeimpl<ContainedIn, Owner, DependentStatic> Sync for UnsafeSelfCell<ContainedIn, Owner, DependentStatic> where // Only derive Sync if Owner and DependentStatic is also Sync
Owner: Sync,
DependentStatic: Sync,
{
}
// This struct is used to safely deallocate only the owner if dependent // construction fails. // // mem::forget it once it's no longer needed or dtor will be UB. #[doc(hidden)] pubstruct OwnerAndCellDropGuard<Owner, Dependent> {
joined_ptr: NonNull<JoinedCell<Owner, Dependent>>,
}
impl<Owner, Dependent> Drop for OwnerAndCellDropGuard<Owner, Dependent> { fn drop(&mutself) { struct DeallocGuard {
ptr: *mut u8,
layout: Layout,
} impl Drop for DeallocGuard { fn drop(&mutself) { unsafe { dealloc(self.ptr, self.layout) }
}
}
// Deallocate even when the drop_in_place(...owner) panics let _guard = DeallocGuard {
ptr: self.joined_ptr.as_ptr() as *mut u8,
layout: Layout::new::<JoinedCell<Owner, Dependent>>(),
};
unsafe { // We must only drop owner and the struct itself, // The whole point of this drop guard is to clean up the partially // initialized struct should building the dependent fail.
drop_in_place(&mut (*self.joined_ptr.as_ptr()).owner);
}
// Deallocation happens at end of scope
}
}
// Older versions of rust do not support addr_of_mut!. What we want to do here // is to emulate the behavior of that macro by going (incorrectly) via a // reference cast. Technically this is UB, but testing does not show the older // compiler versions (ab)using this. For discussions about this behavior see // https://github.com/Voultapher/self_cell/pull/31 and // https://github.com/Voultapher/self_cell/issues/30 and // https://github.com/Voultapher/self_cell/pull/33 // // Because of 'procedural macros cannot expand to macro definitions' // we have wrap this in functions. impl<Owner, Dependent> JoinedCell<Owner, Dependent> { #[doc(hidden)] #[cfg(not(feature = "old_rust"))] pubunsafefn _field_pointers(this: *mutSelf) -> (*mut Owner, *mut Dependent) { let owner_ptr = core::ptr::addr_of_mut!((*this).owner); let dependent_ptr = core::ptr::addr_of_mut!((*this).dependent);
#[doc(hidden)] #[cfg(feature = "old_rust")] #[rustversion::before(1.51)] pubunsafefn _field_pointers(this: *mutSelf) -> (*mut Owner, *mut Dependent) { // See comment above, technically this is UB. let owner_ptr = &mut (*this).owner as *mut Owner; let dependent_ptr = &mut (*this).dependent as *mut Dependent;
(owner_ptr, dependent_ptr)
}
}
/// Wrapper type that allows creating a self-referential type that hold a mutable borrow `&mut T`. /// /// Example usage: /// /// ``` /// use self_cell::{self_cell, MutBorrow}; /// /// type MutStringRef<'a> = &'a mut String; /// /// self_cell!( /// struct MutStringCell { /// owner: MutBorrow<String>, /// /// #[covariant] /// dependent: MutStringRef, /// } /// ); /// /// let mut cell = MutStringCell::new(MutBorrow::new("abc".into()), |owner| owner.borrow_mut()); /// cell.with_dependent_mut(|_owner, dependent| { /// assert_eq!(dependent, &"abc"); /// dependent.pop(); /// assert_eq!(dependent, &"ab"); /// }); /// /// let recovered_owner: String = cell.into_owner().into_inner(); /// assert_eq!(recovered_owner, "ab"); /// ``` pubstruct MutBorrow<T> { // Private on purpose.
is_locked: AtomicBool,
value: UnsafeCell<T>,
}
impl<T> MutBorrow<T> { /// Constructs a new `MutBorrow`. pubfn new(value: T) -> Self { // Use the Rust type system to model an affine type that can only go from unlocked -> locked // but never the other way around. Self {
is_locked: AtomicBool::new(false),
value: UnsafeCell::new(value),
}
}
/// Obtains a mutable reference to the underlying data. /// /// This function can only sensibly be used in the builder function. Afterwards, it's impossible /// to access the inner value, with the exception of [`MutBorrow::into_inner`]. /// /// # Panics /// /// Will panic if called anywhere but in the dependent constructor. Will also panic if called /// more than once. #[allow(clippy::mut_from_ref)] pubfn borrow_mut(&self) -> &mut T { // Ensure this function can only be called once. // Relaxed should be fine, because only one thread could ever read `false` anyway, // so further synchronization is pointless. let was_locked = self.is_locked.swap(true, Ordering::Relaxed);
if was_locked {
panic!("Tried to access locked MutBorrow")
} else { // SAFETY: `self.is_locked` starts out as locked and can never be unlocked again, which // guarantees that this function can only be called once. And the `self.value` being // private ensures that there are no other references to it. unsafe { &mut *self.value.get() }
}
}
/// Consumes `self` and returns the wrapped value. pubfn into_inner(self) -> T { self.value.into_inner()
}
}
// SAFETY: The reasoning why it is safe to share `MutBorrow` across threads is as follows: The // `AtomicBool` `is_locked` ensures that only ever exactly one thread can get access to the inner // value. In that sense it works like a critical section, that begins when `borrow_mut()` is called // and that ends when the outer `MutBorrow` is dropped. Once one thread acquired the unique // reference through `borrow_mut()` no other interaction with the inner value MUST ever be possible // while the outer `MutBorrow` is alive. unsafeimpl<T: Send> Sync for MutBorrow<T> {}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.23 Sekunden
(vorverarbeitet am 2026-08-27)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.