@@ -399,6 +399,130 @@ We might also imagine a variant of the above example where `alignment_pow`, like
399399carry a safety invariant. Ultimately, whether or not it makes sense for a field to be ` unsafe ` is a
400400function of programmer preference and API requirements.
401401
402+ ## Complete Example
403+
404+ The below example demonstrates how field safety support can be applied to build a practical
405+ abstraction with small safety boundaries
406+ ([ playground] ( https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=e8aa2af933f5bf4892d1be951062538d ) ):
407+
408+ ``` rust
409+ #![deny(
410+ unfulfilled_lint_expectations,
411+ clippy:: missing_safety_doc,
412+ clippy:: undocumented_unsafe_blocks,
413+ )]
414+
415+ use std :: {
416+ cell :: UnsafeCell ,
417+ ops :: {Deref , DerefMut },
418+ sync :: Arc ,
419+ };
420+
421+ /// An `Arc` that provides exclusive access to its referent.
422+ ///
423+ /// A `UniqueArc` may have any number of `KeepAlive` handles which ensure that
424+ /// the inner value is not dropped. These handles only control dropping, and do
425+ /// not provide read or write access to the value.
426+ pub struct UniqueArc <T : 'static > {
427+ /// # Safety
428+ ///
429+ /// So long as `T` is owned by `UniqueArc`, `T` may not be accessed (read or
430+ /// written) other than via this `UniqueArc`.
431+ unsafe arc : Arc <UnsafeCell <T >>,
432+ }
433+
434+ /// Keeps the parent [`UniqueArc`] alive without providing read or write access
435+ /// to its value.
436+ pub struct KeepAlive <T > {
437+ /// # Safety
438+ ///
439+ /// `T` may not be accessed (read or written) via this `Arc`.
440+ #[expect(unused)]
441+ unsafe arc : Arc <UnsafeCell <T >>,
442+ }
443+
444+ impl <T > UniqueArc <T > {
445+ /// Constructs a new `UniqueArc` from a value.
446+ pub fn new (val : T ) -> Self {
447+ let arc = Arc :: new (UnsafeCell :: new (val ));
448+ // SAFETY: Since we have just created `arc` and have neither cloned it
449+ // nor leaked a reference to it, we can be sure `T` cannot be read or
450+ // accessed other than via this particular `arc`.
451+ unsafe { Self { arc } }
452+ }
453+
454+ /// Releases ownership of the enclosed value.
455+ ///
456+ /// Returns `None` if any `KeepAlive`s were created but not destroyed.
457+ pub fn into_inner (self ) -> Option <T > {
458+ // SAFETY: Moving `arc` out of `Self` releases it from its safety
459+ // invariant.
460+ let arc = unsafe { self . arc };
461+ Arc :: into_inner (arc ). map (UnsafeCell :: into_inner )
462+ }
463+
464+ /// Produces a `KeepAlive` handle, which defers the destruction
465+ /// of the enclosed value.
466+ pub fn keep_alive (& self ) -> KeepAlive <T > {
467+ // SAFETY: By invariant on `KeepAlive::arc`, this clone will never be
468+ // used for accessing `T`, as required by `UniqueArc::arc`. The one
469+ // exception is that, if a `KeepAlive` is the last reference to be
470+ // dropped, then it will drop the inner `T`. However, if this happens,
471+ // it means that the `UniqueArc` has already been dropped, and so its
472+ // invariant will not be violated.
473+ unsafe {
474+ KeepAlive {
475+ arc : self . arc. clone (),
476+ }
477+ }
478+ }
479+ }
480+
481+ impl <T > Deref for UniqueArc <T > {
482+ type Target = T ;
483+
484+ fn deref (& self ) -> & T {
485+ // SAFETY: We do not create any other owning references to `arc` - we
486+ // only dereference it below, but do not clone it.
487+ let arc = unsafe { & self . arc };
488+ let ptr = UnsafeCell :: get (arc );
489+ // SAFETY: We satisfy all requirements for pointer-to-reference
490+ // conversions [1]:
491+ // - By invariant on `&UnsafeCell<T>`, `ptr` is well-aligned, non-null,
492+ // dereferenceable, and points to a valid `T`.
493+ // - By invariant on `Self::arc`, no other `Arc` references exist to
494+ // this value which will be used for reading or writing. Thus, we
495+ // satisfy the aliasing invariant of `&` references.
496+ //
497+ // [1] https://doc.rust-lang.org/1.85.0/std/ptr/index.html#pointer-to-reference-conversion
498+ unsafe { & * ptr }
499+ }
500+ }
501+
502+ impl <T > DerefMut for UniqueArc <T > {
503+ fn deref_mut (& mut self ) -> & mut T {
504+ // SAFETY: We do not create any other owning references to `arc` - we
505+ // only dereference it below, but do not clone it.
506+ let arc = unsafe { & mut self . arc };
507+ let val = UnsafeCell :: get (arc );
508+ // SAFETY: We satisfy all requirements for pointer-to-reference
509+ // conversions [1]:
510+ // - By invariant on `&mut UnsafeCell<T>`, `ptr` is well-aligned,
511+ // non-null, dereferenceable, and points to a valid `T`.
512+ // - By invariant on `Self::arc`, no other `Arc` references exist to
513+ // this value which will be used for reading or writing. Thus, we
514+ // satisfy the aliasing invariant of `&mut` references.
515+ //
516+ // [1] https://doc.rust-lang.org/1.85.0/std/ptr/index.html#pointer-to-reference-conversion
517+ unsafe { & mut * val }
518+ }
519+ }
520+
521+ // SAFETY: `UniqueArc<T>` has the same aliasing and synchronization properties
522+ // as `&mut T`, and so it is `Sync` if `&mut T` is `Sync`.
523+ unsafe impl <T > Sync for UniqueArc <T > where & 'static mut T : Sync {}
524+ ```
525+
402526# Reference-level explanation
403527
404528## Syntax
0 commit comments