zerocopy/pointer/
invariant.rs

1// Copyright 2024 The Fuchsia Authors
2//
3// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
4// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
5// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
6// This file may not be copied, modified, or distributed except according to
7// those terms.
8
9#![allow(missing_copy_implementations, missing_debug_implementations)]
10
11//! The parameterized invariants of a [`Ptr`][super::Ptr].
12//!
13//! Invariants are encoded as ([`Aliasing`], [`Alignment`], [`Validity`])
14//! triples implementing the [`Invariants`] trait.
15
16/// The invariants of a [`Ptr`][super::Ptr].
17pub trait Invariants: Sealed {
18    type Aliasing: Aliasing;
19    type Alignment: Alignment;
20    type Validity: Validity;
21}
22
23impl<A: Aliasing, AA: Alignment, V: Validity> Invariants for (A, AA, V) {
24    type Aliasing = A;
25    type Alignment = AA;
26    type Validity = V;
27}
28
29/// The aliasing invariant of a [`Ptr`][super::Ptr].
30///
31/// All aliasing invariants must permit reading from the bytes of a pointer's
32/// referent which are not covered by [`UnsafeCell`]s.
33///
34/// [`UnsafeCell`]: core::cell::UnsafeCell
35pub trait Aliasing: Sealed {
36    /// Is `Self` [`Exclusive`]?
37    #[doc(hidden)]
38    const IS_EXCLUSIVE: bool;
39}
40
41/// The alignment invariant of a [`Ptr`][super::Ptr].
42pub trait Alignment: Sealed {}
43
44/// The validity invariant of a [`Ptr`][super::Ptr].
45pub trait Validity: Sealed {}
46
47/// An [`Aliasing`] invariant which is either [`Shared`] or [`Exclusive`].
48///
49/// # Safety
50///
51/// Given `A: Reference`, callers may assume that either `A = Shared` or `A =
52/// Exclusive`.
53pub trait Reference: Aliasing + Sealed {}
54
55/// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`.
56///
57/// The referent of a shared-aliased `Ptr` may be concurrently referenced by any
58/// number of shared-aliased `Ptr` or `&T` references, and may not be
59/// concurrently referenced by any exclusively-aliased `Ptr`s or `&mut T`
60/// references. The referent must not be mutated, except via [`UnsafeCell`]s.
61///
62/// [`UnsafeCell`]: core::cell::UnsafeCell
63pub enum Shared {}
64impl Aliasing for Shared {
65    const IS_EXCLUSIVE: bool = false;
66}
67impl Reference for Shared {}
68
69/// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a mut T`.
70///
71/// The referent of an exclusively-aliased `Ptr` may not be concurrently
72/// referenced by any other `Ptr`s or references, and may not be accessed (read
73/// or written) other than via this `Ptr`.
74pub enum Exclusive {}
75impl Aliasing for Exclusive {
76    const IS_EXCLUSIVE: bool = true;
77}
78impl Reference for Exclusive {}
79
80/// It is unknown whether the pointer is aligned.
81pub enum Unaligned {}
82
83impl Alignment for Unaligned {}
84
85/// The referent is aligned: for `Ptr<T>`, the referent's address is a multiple
86/// of the `T`'s alignment.
87pub enum Aligned {}
88impl Alignment for Aligned {}
89
90/// Any bit pattern is allowed in the `Ptr`'s referent, including uninitialized
91/// bytes.
92pub enum Uninit {}
93impl Validity for Uninit {}
94
95/// The byte ranges initialized in `T` are also initialized in the referent.
96///
97/// Formally: uninitialized bytes may only be present in `Ptr<T>`'s referent
98/// where they are guaranteed to be present in `T`. This is a dynamic property:
99/// if, at a particular byte offset, a valid enum discriminant is set, the
100/// subsequent bytes may only have uninitialized bytes as specificed by the
101/// corresponding enum.
102///
103/// Formally, given `len = size_of_val_raw(ptr)`, at every byte offset, `b`, in
104/// the range `[0, len)`:
105/// - If, in any instance `t: T` of length `len`, the byte at offset `b` in `t`
106///   is initialized, then the byte at offset `b` within `*ptr` must be
107///   initialized.
108/// - Let `c` be the contents of the byte range `[0, b)` in `*ptr`. Let `S` be
109///   the subset of valid instances of `T` of length `len` which contain `c` in
110///   the offset range `[0, b)`. If, in any instance of `t: T` in `S`, the byte
111///   at offset `b` in `t` is initialized, then the byte at offset `b` in `*ptr`
112///   must be initialized.
113///
114///   Pragmatically, this means that if `*ptr` is guaranteed to contain an enum
115///   type at a particular offset, and the enum discriminant stored in `*ptr`
116///   corresponds to a valid variant of that enum type, then it is guaranteed
117///   that the appropriate bytes of `*ptr` are initialized as defined by that
118///   variant's bit validity (although note that the variant may contain another
119///   enum type, in which case the same rules apply depending on the state of
120///   its discriminant, and so on recursively).
121pub enum AsInitialized {}
122impl Validity for AsInitialized {}
123
124/// The byte ranges in the referent are fully initialized. In other words, if
125/// the referent is `N` bytes long, then it contains a bit-valid `[u8; N]`.
126pub enum Initialized {}
127impl Validity for Initialized {}
128
129/// The referent is bit-valid for `T`.
130pub enum Valid {}
131impl Validity for Valid {}
132
133/// # Safety
134///
135/// `DT: CastableFrom<ST, SV, DV>` is sound if `SV = DV = Uninit` or `SV = DV =
136/// Initialized`.
137pub unsafe trait CastableFrom<ST: ?Sized, SV, DV> {}
138
139// SAFETY: `SV = DV = Uninit`.
140unsafe impl<ST: ?Sized, DT: ?Sized> CastableFrom<ST, Uninit, Uninit> for DT {}
141// SAFETY: `SV = DV = Initialized`.
142unsafe impl<ST: ?Sized, DT: ?Sized> CastableFrom<ST, Initialized, Initialized> for DT {}
143
144/// [`Ptr`](crate::Ptr) referents that permit unsynchronized read operations.
145///
146/// `T: Read<A, R>` implies that a pointer to `T` with aliasing `A` permits
147/// unsynchronized read oeprations. This can be because `A` is [`Exclusive`] or
148/// because `T` does not permit interior mutation.
149///
150/// # Safety
151///
152/// `T: Read<A, R>` if either of the following conditions holds:
153/// - `A` is [`Exclusive`]
154/// - `T` implements [`Immutable`](crate::Immutable)
155///
156/// As a consequence, if `T: Read<A, R>`, then any `Ptr<T, (A, ...)>` is
157/// permitted to perform unsynchronized reads from its referent.
158pub trait Read<A: Aliasing, R: ReadReason> {}
159
160impl<A: Aliasing, T: ?Sized + crate::Immutable> Read<A, BecauseImmutable> for T {}
161impl<T: ?Sized> Read<Exclusive, BecauseExclusive> for T {}
162
163/// Used to disambiguate [`Read`] impls.
164pub trait ReadReason: Sealed {}
165
166/// Unsynchronized reads are permitted because only one live [`Ptr`](crate::Ptr)
167/// or reference may exist to the referent bytes at a time.
168#[derive(Copy, Clone, Debug)]
169#[doc(hidden)]
170pub enum BecauseExclusive {}
171impl ReadReason for BecauseExclusive {}
172
173/// Unsynchronized reads are permitted because no live [`Ptr`](crate::Ptr)s or
174/// references permit interior mutation.
175#[derive(Copy, Clone, Debug)]
176#[doc(hidden)]
177pub enum BecauseImmutable {}
178impl ReadReason for BecauseImmutable {}
179
180use sealed::Sealed;
181mod sealed {
182    use super::*;
183
184    pub trait Sealed {}
185
186    impl Sealed for Shared {}
187    impl Sealed for Exclusive {}
188
189    impl Sealed for Unaligned {}
190    impl Sealed for Aligned {}
191
192    impl Sealed for Uninit {}
193    impl Sealed for AsInitialized {}
194    impl Sealed for Initialized {}
195    impl Sealed for Valid {}
196
197    impl<A: Sealed, AA: Sealed, V: Sealed> Sealed for (A, AA, V) {}
198
199    impl Sealed for BecauseImmutable {}
200    impl Sealed for BecauseExclusive {}
201}