generic_mutability/mutability.rs
1use core::marker::PhantomData;
2
3mod seal {
4 use crate::{Mutable, Shared};
5
6 pub trait Sealed {}
7 impl Sealed for Mutable {}
8 impl Sealed for Shared {}
9}
10
11/// This trait is used as a bound on generic mutability parameters.
12///
13/// This trait is implemented by two types, `Shared` and `Mutable`, and it is sealed so no other types may implement it.
14///
15/// Not to be confused with `MutabilityEnum<M>`, which represents a proof about a generic mutability parameter.
16///
17/// Note that while mutability parameters are implemented as type parameters, they represent an entirely different kind of generic parameter.
18/// For this reason, the `M: Mutability` bound should be applied even in struct definitions where bounds are generally discouraged.
19#[allow(clippy::missing_safety_doc)]
20// SAFETY: this trait must only be implemented for `Shared` and `Mutable`. `Shared::mutability()` must return `MutabilityEnum::Shared(IsShared<Shared>)` and `Mutable::mutability()` must return `MutabilityEnum::Mutable(IsMutable<Mutable>)`.
21pub unsafe trait Mutability: Copy + Sized + seal::Sealed {
22 /// The result of this method lets you match over the mutability values to obtain a proof, which can be used to access features that are only available for one mutability.
23 ///
24 /// Most notably, the `GenRef::gen_{into,from}_{mut,shared}` methods require a proof of this form.
25 fn mutability() -> MutabilityEnum<Self>;
26}
27
28/// Represents the mutability of a shared reference, `&T`.
29///
30/// Along with `Mutable`, this is one of the two types that can be used as a generic mutability parameter.
31/// It is an empty type because it is always used as a generic parameter and never as a value.
32///
33/// Just as with `&T`, interior mutability types may change while behind a reference of `Shared` mutability.
34#[derive(Clone, Copy)]
35pub enum Shared {}
36
37// SAFETY: `mutability()` does return `MutabilityEnum::Shared(IsShared<Shared>)`
38unsafe impl Mutability for Shared {
39 #[inline(always)]
40 fn mutability() -> MutabilityEnum<Self> {
41 // This is not a recursive call, but a call to the inherent method.
42 #[deny(unconditional_recursion)]
43 let proof = Shared::mutability();
44
45 MutabilityEnum::Shared(proof)
46 }
47}
48impl Shared {
49 #[inline(always)]
50 /// This method returns a proof for the shared-ness of `Shared`.
51 /// Note: this method shadows `<Shared as Mutability>::mutability()`, which returns the same proof wrapped in `MutabilityEnum::Shared`.
52 /// If you have access to this method (i.e. in non-generic contexts), you should not need `<Shared as Mutability>::mutability()`.
53 pub fn mutability() -> IsShared<Shared> {
54 // SAFETY: `M` is `Shared`
55 unsafe { IsShared::new() }
56 }
57}
58
59/// Represents the mutability of a mutable (unique) reference, `&mut T`.
60///
61/// Along with `Shared`, this is one of the two types that can be used as a generic mutability parameter.
62/// It is an empty type because it is always used as a generic parameter and never as a value.
63#[derive(Clone, Copy)]
64pub enum Mutable {}
65
66// SAFETY: `mutability()` does return `MutabilityEnum::Mutable(IsMutable<Mutable>)`
67unsafe impl Mutability for Mutable {
68 #[inline(always)]
69 fn mutability() -> MutabilityEnum<Self> {
70 // This is not a recursive call, but a call to the inherent method.
71 #[deny(unconditional_recursion)]
72 let proof = Mutable::mutability();
73
74 MutabilityEnum::Mutable(proof)
75 }
76}
77impl Mutable {
78 #[inline(always)]
79 /// This method returns a proof for the mutable-ness of `Mutable`.
80 /// Note: this method shadows `<Mutable as Mutability>::mutability()`, which returns the same proof wrapped in `MutabilityEnum::Mutable`.
81 /// If you have access to this method (i.e. in non-generic contexts), you should not need `<Mutable as Mutability>::mutability()`.
82 pub fn mutability() -> IsMutable<Mutable> {
83 // SAFETY: `M` is `Mutable`
84 unsafe { IsMutable::new() }
85 }
86}
87
88/// The existence of a value of this type guarantees that a specific mutability parameter `M` is `Mutable`.
89/// Unsafe code may rely on this guarantee.
90/// You can obtain this value by matching over `M::mutability()`.
91///
92/// The most notable API that requires this is `GenRef::gen_{into,from}_mut`.
93#[derive(Clone, Copy)]
94pub struct IsMutable<M: Mutability>(PhantomData<M>);
95
96impl<M: Mutability> IsMutable<M> {
97 #[inline(always)]
98 // SAFETY: `M` must be `Mutable`
99 pub(crate) unsafe fn new() -> Self {
100 IsMutable(PhantomData)
101 }
102}
103
104/// The existence of a value of this type guarantees that a specific mutability parameter `M` is `Shared`.
105/// Unsafe code may rely on this guarantee.
106/// You can obtain this value by matching over `M::mutability()`.
107///
108/// The most notable API that requires this is `GenRef::gen_{into,from}_shared`.
109#[derive(Clone, Copy)]
110pub struct IsShared<M: Mutability>(PhantomData<M>);
111
112impl<M: Mutability> IsShared<M> {
113 #[inline(always)]
114 // SAFETY: `M` must be `Shared`
115 pub(crate) unsafe fn new() -> Self {
116 IsShared(PhantomData)
117 }
118}
119
120/// This enum makes it possible to `match` over a mutability parameter.
121/// Not to be confused with the `Mutability` trait, which is used as a bound for mutability parameters; and `Shared` and `Mutable`, which are values of the mutability parameters.
122///
123/// A value of this type can be obtained from the `Mutability::mutability()` method.
124///
125/// Each variant contains a proof about the value of mutability parameter `M`.
126///
127/// Note that the only valid value of type `MutabilityEnum<Shared>` is `MutabilityEnum::Shared(IsShared)`, and the only value of type `MutabilityEnum<Mutable>` is `MutabilityEnum::Mutable(IsMutable)`
128#[derive(Clone, Copy)]
129pub enum MutabilityEnum<M: Mutability> {
130 /// Contains a proof that `M` is `Mutable`. `MutabilityEnum::Mutable` (this enum variant) is not to be confused with `Mutable` (type implementing `Mutability`).
131 Mutable(IsMutable<M>),
132 /// Contains a proof that `M` is `Shared`. `MutabilityEnum::Shared` (this enum variant) is not to be confused with `Shared` (type implementing `Mutability`).
133 Shared(IsShared<M>),
134}