// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. #![allow(missing_copy_implementations, missing_debug_implementations)] //! The parameterized invariants of a [`Ptr`][super::Ptr]. //! //! Invariants are encoded as ([`Aliasing`], [`Alignment`], [`Validity`]) //! triples implementing the [`Invariants`] trait. /// The invariants of a [`Ptr`][super::Ptr]. pub trait Invariants: Sealed { type Aliasing: Aliasing; type Alignment: Alignment; type Validity: Validity; } impl Invariants for (A, AA, V) { type Aliasing = A; type Alignment = AA; type Validity = V; } /// The aliasing invariant of a [`Ptr`][super::Ptr]. /// /// All aliasing invariants must permit reading from the bytes of a pointer's /// referent which are not covered by [`UnsafeCell`]s. /// /// [`UnsafeCell`]: core::cell::UnsafeCell pub trait Aliasing: Sealed { /// Is `Self` [`Exclusive`]? #[doc(hidden)] const IS_EXCLUSIVE: bool; } /// The alignment invariant of a [`Ptr`][super::Ptr]. pub trait Alignment: Sealed {} /// The validity invariant of a [`Ptr`][super::Ptr]. pub trait Validity: Sealed {} /// An [`Aliasing`] invariant which is either [`Shared`] or [`Exclusive`]. /// /// # Safety /// /// Given `A: Reference`, callers may assume that either `A = Shared` or `A = /// Exclusive`. pub trait Reference: Aliasing + Sealed {} /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`. /// /// The referent of a shared-aliased `Ptr` may be concurrently referenced by any /// number of shared-aliased `Ptr` or `&T` references, and may not be /// concurrently referenced by any exclusively-aliased `Ptr`s or `&mut T` /// references. The referent must not be mutated, except via [`UnsafeCell`]s. /// /// [`UnsafeCell`]: core::cell::UnsafeCell pub enum Shared {} impl Aliasing for Shared { const IS_EXCLUSIVE: bool = false; } impl Reference for Shared {} /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a mut T`. /// /// The referent of an exclusively-aliased `Ptr` may not be concurrently /// referenced by any other `Ptr`s or references, and may not be accessed (read /// or written) other than via this `Ptr`. pub enum Exclusive {} impl Aliasing for Exclusive { const IS_EXCLUSIVE: bool = true; } impl Reference for Exclusive {} /// It is unknown whether the pointer is aligned. pub enum Unaligned {} impl Alignment for Unaligned {} /// The referent is aligned: for `Ptr`, the referent's address is a multiple /// of the `T`'s alignment. pub enum Aligned {} impl Alignment for Aligned {} /// Any bit pattern is allowed in the `Ptr`'s referent, including uninitialized /// bytes. pub enum Uninit {} impl Validity for Uninit {} /// The byte ranges initialized in `T` are also initialized in the referent. /// /// Formally: uninitialized bytes may only be present in `Ptr`'s referent /// where they are guaranteed to be present in `T`. This is a dynamic property: /// if, at a particular byte offset, a valid enum discriminant is set, the /// subsequent bytes may only have uninitialized bytes as specificed by the /// corresponding enum. /// /// Formally, given `len = size_of_val_raw(ptr)`, at every byte offset, `b`, in /// the range `[0, len)`: /// - If, in any instance `t: T` of length `len`, the byte at offset `b` in `t` /// is initialized, then the byte at offset `b` within `*ptr` must be /// initialized. /// - Let `c` be the contents of the byte range `[0, b)` in `*ptr`. Let `S` be /// the subset of valid instances of `T` of length `len` which contain `c` in /// the offset range `[0, b)`. If, in any instance of `t: T` in `S`, the byte /// at offset `b` in `t` is initialized, then the byte at offset `b` in `*ptr` /// must be initialized. /// /// Pragmatically, this means that if `*ptr` is guaranteed to contain an enum /// type at a particular offset, and the enum discriminant stored in `*ptr` /// corresponds to a valid variant of that enum type, then it is guaranteed /// that the appropriate bytes of `*ptr` are initialized as defined by that /// variant's bit validity (although note that the variant may contain another /// enum type, in which case the same rules apply depending on the state of /// its discriminant, and so on recursively). pub enum AsInitialized {} impl Validity for AsInitialized {} /// The byte ranges in the referent are fully initialized. In other words, if /// the referent is `N` bytes long, then it contains a bit-valid `[u8; N]`. pub enum Initialized {} impl Validity for Initialized {} /// The referent is bit-valid for `T`. pub enum Valid {} impl Validity for Valid {} /// # Safety /// /// `DT: CastableFrom` is sound if `SV = DV = Uninit` or `SV = DV = /// Initialized`. pub unsafe trait CastableFrom {} // SAFETY: `SV = DV = Uninit`. unsafe impl CastableFrom for DT {} // SAFETY: `SV = DV = Initialized`. unsafe impl CastableFrom for DT {} /// [`Ptr`](crate::Ptr) referents that permit unsynchronized read operations. /// /// `T: Read` implies that a pointer to `T` with aliasing `A` permits /// unsynchronized read oeprations. This can be because `A` is [`Exclusive`] or /// because `T` does not permit interior mutation. /// /// # Safety /// /// `T: Read` if either of the following conditions holds: /// - `A` is [`Exclusive`] /// - `T` implements [`Immutable`](crate::Immutable) /// /// As a consequence, if `T: Read`, then any `Ptr` is /// permitted to perform unsynchronized reads from its referent. pub trait Read {} impl Read for T {} impl Read for T {} /// Unsynchronized reads are permitted because only one live [`Ptr`](crate::Ptr) /// or reference may exist to the referent bytes at a time. #[derive(Copy, Clone, Debug)] #[doc(hidden)] pub enum BecauseExclusive {} /// Unsynchronized reads are permitted because no live [`Ptr`](crate::Ptr)s or /// references permit interior mutation. #[derive(Copy, Clone, Debug)] #[doc(hidden)] pub enum BecauseImmutable {} use sealed::Sealed; mod sealed { use super::*; pub trait Sealed {} impl Sealed for Shared {} impl Sealed for Exclusive {} impl Sealed for Unaligned {} impl Sealed for Aligned {} impl Sealed for Uninit {} impl Sealed for AsInitialized {} impl Sealed for Initialized {} impl Sealed for Valid {} impl Sealed for (A, AA, V) {} impl Sealed for BecauseImmutable {} impl Sealed for BecauseExclusive {} }