generic_mutability/
genref.rs

1use core::borrow::{Borrow, BorrowMut};
2use core::fmt;
3use core::marker::PhantomData;
4use core::ops::{Deref, DerefMut};
5use core::ptr::NonNull;
6
7use crate::mutability::{IsMutable, IsShared, Mutability, Mutable, Shared};
8
9pub mod genref_methods;
10mod impl_traits;
11
12/// This is the main type of this crate.
13/// It is the generic-mutability equivalent of safe reference types (`&` and `&mut`).
14///
15/// # Usage for end users
16///
17/// *You need to interface with an API that is generic over mutability, but you do not use generic mutability to call it.*
18///
19/// You will need to create a `GenRef<'_, Mutable, T>` or `GenRef<'_, Shared, T>` via the `From<&mut T>` or `From<&T>` implementations, respectively.
20/// Then pass the `GenRef` to the function(s) you would like to call.
21/// At the end, you can use the resulting `GenRef` mostly the same way you would use a reference, but you can also unwrap it into a normal reference using the `into_mut` or `into_shared` functions.
22///
23/// For example:
24///
25/// ```
26/// # use core::ops::{Index, IndexMut};
27/// # use generic_mutability::{gen_mut, GenRef, Mutability, Shared};
28/// # fn gen_index<M: Mutability, I, C>(gen_collection: GenRef<'_, M, C>, index: I) -> GenRef<'_, M, C::Output>
29/// # where
30/// #     C: Index<I> + IndexMut<I>,
31/// # {
32/// #     gen_mut! {M => {
33/// #         into_gen!(switch_shared_mut![C::index, C::index_mut](from_gen!(gen_collection), index))
34/// #     }}
35/// # }
36/// let v = vec![1, 2, 3];
37///
38/// let gen_r: GenRef<'_, Shared, i32> = gen_index(GenRef::from(&v), 1);
39///
40/// let r: &i32 = GenRef::into_shared(gen_r);
41///
42/// assert_eq!(gen_r, &2);
43/// assert_eq!(r, &2);
44/// ```
45///
46/// # Usage for libraries
47///
48/// *You are implementing an API that is supposed to be generic over mutability.*
49///
50/// You should start by introducing a *mutability parameter*.
51/// It is a generic argument (usually named `M`) with a `M: Mutability` bound on it .
52///
53/// Then you can take a `GenRef` as an argument.
54///
55/// `GenRef` always provides immutable access to the pointed-to value through the `Deref` trait.
56///
57/// Then, to map the generic reference into one of another type, you can do one of these:
58///
59/// - If the API you are calling has generic mutability accessors, you can pass the `GenRef` directly to them.
60///     Unlike normal references, which are automatically reborrowed, you may need to use `GenRef::reborrow` to perform a reborrow manually.
61///     You can also call `map_deref` to perform a dereference.
62///
63/// - If the API you're calling *does not* have generic mutability, you can use one of the following ways to unwrap and reconstruct the `GenRef`:
64///     - `map`
65///     - `field!` macro for accessing fields
66///     - `gen_mut!` macro
67///     - branch to cases on `Mutability::mutability()` and use `gen_{into,from}_{mut,shared}` with the proof provided by the return value of `Mutability::mutability()`.
68///         See the Examples section on how to do this.
69///
70/// # Examples
71///
72/// When you need to map a generic `GenRef` through an API that doesn't support it, you can use the following pattern:
73///
74/// ```
75/// # use generic_mutability::{ GenRef, Mutability, MutabilityEnum::* };
76/// fn gen_index<M: Mutability, T>(gen_slice: GenRef<'_, M, [T]>, index: usize) -> GenRef<'_, M, T> {
77///     match M::mutability() {
78///         Mutable(proof) => {
79///             let mut_slice: &mut [T] = GenRef::gen_into_mut(gen_slice, proof);
80///             let mut_elem: &mut T = &mut mut_slice[index];
81///             GenRef::gen_from_mut(mut_elem, proof)
82///         },
83///         Shared(proof) => {
84///             let ref_slice: &[T] = GenRef::gen_into_shared(gen_slice, proof);
85///             let ref_elem: &T = &ref_slice[index];
86///             GenRef::gen_from_shared(ref_elem, proof)
87///         }
88///     }
89/// }
90/// ```
91///
92/// In most cases, the mutable and shared cases share most of the code. When that is the case, it is often possible to use the `gen_mut!` macro, which expands to the same as above:
93///
94/// ```
95/// # use generic_mutability::{ GenRef, Mutability, gen_mut };
96/// fn gen_index<M: Mutability, T>(gen_slice: GenRef<'_, M, [T]>, index: usize) -> GenRef<'_, M, T> {
97///     gen_mut!(M => {
98///         let ref_slice = from_gen!(gen_slice);
99///         into_gen!(&gen ref_slice[index])
100///     })
101/// }
102/// ```
103///
104/// When performing a one-to-one mapping with two separate functions (often when calling into an API), the `GenRef::map` can come handy:
105///
106/// ```
107/// # use generic_mutability::{ GenRef, Mutability };
108/// fn gen_index<M: Mutability, T>(gen_slice: GenRef<'_, M, [T]>, index: usize) -> GenRef<'_, M, T> {
109///     GenRef::map(gen_slice, |r| &r[index], |r| &mut r[index])
110/// }
111/// ```
112///
113/// Finally, when accessing fields or performing indexing, the `field!` macro can be helpful as well:
114///
115/// ```
116/// # use generic_mutability::{ GenRef, Mutability, field };
117/// fn gen_index<M: Mutability, T>(gen_slice: GenRef<'_, M, [T]>, index: usize) -> GenRef<'_, M, T> {
118///     field!(&gen gen_slice[index])
119/// }
120/// ```
121#[repr(transparent)]
122pub struct GenRef<'s, M: Mutability, T: ?Sized> {
123    // This could contain an `ErasedMutRef` instead of `_lifetime` and `ptr`,
124    // but that way it could not implement `Copy`
125    _lifetime: PhantomData<&'s mut T>,
126    _mutability: PhantomData<*const M>,
127    ptr: NonNull<T>,
128}
129
130macro_rules! docs_for {
131    (as_ptr) => {
132         "Casts the reference into a `NonNull` pointer.
133
134# Safety
135
136The `GenRef` must not be used while the pointer is active. 
137The exact semantics of this depend on the memory model adopted by Rust.
138
139# Guarantees
140
141The returned pointer is guaranteed to be valid for reads for `'s`, and also for writes if `M` is `Mutable`."
142    };
143    (gen_into_shared_downgrading) => {
144         "Converts a generic `GenRef<'_, M, T>` into `&T`, downgrading the reference if `M` is `Mutable`.
145
146If `M` is `Shared` it behaves exactly the same way as `gen_into_shared` without requiring a proof for sharedness.
147In this case, the difference between the two is purely semantic: if you have proof that `M` is `Shared`, you should use `gen_into_shared`."
148    };
149    (gen_into_mut) => {
150         "Converts a generic `GenRef<'_, M, T>` into `&mut T`. 
151This is available in a generic context.
152
153Once the transformations are done, the result can be converted back into a `GenRef` using the `gen_from_mut` function.
154
155The conversion requires that `M` is `Mutable`, this must be proven by passing an `IsMutable<M>` value.
156That can be obtained by `match`ing on `M::mutability()`."
157    };
158    (gen_into_shared) => {
159         "Converts a generic `GenRef<'_, M, T>` into `&T`. 
160This is available in a generic context.
161
162Once the transformations are done, the result can be converted back into a `GenRef` using the `gen_from_shared` function.
163
164The conversion requires that `M` is `Shared`, this must be proven by passing an `IsShared<M>` value.
165That can be obtained by `match`ing on `M::mutability()`.
166
167If you want to force the conversion even if `M` is `Mutable`, you can use the `gen_into_shared_downgrading` function."
168    };
169    (reborrow) => {
170         "Generically reborrows a `GenRef`. 
171That is, it creates a shorter-lived owned `GenRef` from a `&mut GenRef`.
172This is available in a generic context.
173
174This requires the variable to be marked `mut`, even if `M` is `Shared` and thus no mutation takes place."
175    };
176    (map) => {
177         "Maps a generic `GenRef` into another one using either `f_mut` or `f_shared`. 
178This is available in a generic context.
179
180Using this function is usually sufficient.
181For mapping over field access, you can use the `field!` macro instead.
182If you need more flexibility, you can use the `gen_mut!` macro or `match`ing over `M::mutability()`."
183    };
184    (map_deref) => {
185         "Generically dereferences the value contained in the `GenRef`.
186This is available in a generic context."
187    };
188}
189
190pub(self) use docs_for;
191
192impl<'s, M: Mutability, T: ?Sized> GenRef<'s, M, T> {
193    #[inline(always)]
194    /// Creates a `GenRef<'s, M, T>` from a pointer with the chosen mutability `M` and lifetime `'s`, without checking.
195    ///
196    /// To create a non-generic `GenRef` from a reference, use the `From` implementation.
197    ///
198    /// To convert a reference into a `GenRef` in a generic context, use the `gen_from_shared` and `gen_from_mut` methods with a proof or the `gen_from_mut_downgrading` method instead.
199    ///
200    /// # Safety
201    ///
202    /// `GenRef` is a safe reference type. Using this method is equivalent to dereferencing the pointer and creating a reference from it. As such:
203    ///
204    /// - The pointer must be properly aligned.
205    /// - The pointer must point to an initialized instance of `T`.
206    /// - The lifetime `'s` and mutability `M` are arbitrarily chosen and do not necessarily reflect the actual lifetime and mutability of the data.
207    ///     Extra care must be taken to ensure that the correct lifetime and mutability parameters are used.
208    /// - Furthermore:
209    ///     - If the mutability is `Immutable`:
210    ///         - The pointer must be valid for reads for lifetime `'s`.
211    ///         - The pointed-to value must not be written to by other pointers and no mutable references to it may exist during `'s`.
212    ///     - If the mutability is `Mutable`:
213    ///         - The pointer must be valid for reads and writes for lifetime `'s`.
214    ///         - The pointed-to value must not be accessed (read or written) by other pointers, and no other references to it may exist during `'s`.
215    pub unsafe fn from_ptr_unchecked(ptr: NonNull<T>) -> Self {
216        Self {
217            _lifetime: PhantomData,
218            _mutability: PhantomData,
219            ptr,
220        }
221    }
222
223    #[inline(always)]
224    #[doc = docs_for!(as_ptr)]
225    pub fn as_ptr(genref: &Self) -> NonNull<T> {
226        genref.ptr
227    }
228
229    #[inline(always)]
230    /// Converts a `&mut T` into a generic `GenRef<'_, M, T>`, downgrading the reference if `M` is `Shared`.
231    ///
232    /// If `M` is `Mutable` it behaves exactly the same way as `gen_from_mut` without requiring a proof for mutability.
233    /// In this case, the difference between the two is purely semantic: if you have proof that `M` is `Mutable`, you should use `gen_from_mut`.
234    pub fn gen_from_mut_downgrading(reference: &'s mut T) -> Self {
235        let ptr = NonNull::from(reference);
236
237        // SAFETY: `ptr` is derived from a mutable reference, so points to a valid `T` and is valid and unaliased for `'s`.
238        // The correct lifetime is enforced by the function signature.
239        unsafe { Self::from_ptr_unchecked(ptr) }
240    }
241
242    #[inline(always)]
243    #[doc = docs_for!(gen_into_shared_downgrading)]
244    pub fn gen_into_shared_downgrading(genref: Self) -> &'s T {
245        let ptr = GenRef::as_ptr(&genref);
246
247        // SAFETY: `GenRef::as_ptr` guarantees that `ptr` points to a valid `T` and is valid for reads for `'s`.
248        unsafe { ptr.as_ref() }
249    }
250
251    #[inline(always)]
252    #[doc = docs_for!(gen_into_mut)]
253    pub fn gen_into_mut(genref: Self, _proof: IsMutable<M>) -> &'s mut T {
254        let mut ptr = GenRef::as_ptr(&genref);
255
256        // SAFETY: For a value of `IsMutable<M>` to exist, `M` must be `Mutable`.
257        // `GenRef::as_ptr` guarantees that `ptr` points to a valid `T` and (given that `M` is `Mutable`) is valid for reads and writes for `'s`.
258        // This function takes ownership of `GenRef`, so `ptr` can not be aliased.
259        unsafe { ptr.as_mut() }
260    }
261    #[inline(always)]
262    /// Converts a `&mut T` into a generic `GenRef<'_, M, T>`.
263    /// This is available in a generic context.
264    ///
265    /// The conversion requires that `M` is `Mutable`, this must be proven by passing an `IsMutable<M>` value.
266    /// That can be obtained by `match`ing on `M::mutability()`.
267    ///
268    /// If you want to force the conversion even if `M` is `Shared`, you can use the `gen_from_mut_downgrading` function.
269    pub fn gen_from_mut(reference: &'s mut T, _proof: IsMutable<M>) -> Self {
270        // `gen_from_mut_downgrading` is semantically different, but when called with `M = Mutable` they perform the same operation.
271        GenRef::gen_from_mut_downgrading(reference)
272    }
273
274    #[inline(always)]
275    #[doc = docs_for!(gen_into_shared)]
276    pub fn gen_into_shared(genref: Self, _proof: IsShared<M>) -> &'s T {
277        // `gen_into_shared_downgrading` is semantically different, but when called with `M = Shared` they perform the same operation.
278        GenRef::gen_into_shared_downgrading(genref)
279    }
280
281    #[inline(always)]
282    /// Converts a `&T` into a generic `GenRef<'_, M, T>`.
283    /// This is available in a generic context.
284    ///
285    /// The conversion requires that `M` is `Shared`, this must be proven by passing an `IsShared<M>` value.
286    /// That can be obtained by `match`ing on `M::mutability()`.
287    pub fn gen_from_shared(reference: &'s T, _proof: IsShared<M>) -> Self {
288        let ptr = NonNull::from(reference);
289
290        // SAFETY: For a value of `IsShared<M>` to exist, `M` must be `Shared`. `ptr` is derived from a shared reference, so it is valid for reads for `'s`.
291        // The correct lifetime is enforced by the function signature.
292        unsafe { Self::from_ptr_unchecked(ptr) }
293    }
294
295    #[inline(always)]
296    #[doc = docs_for!(reborrow)]
297    pub fn reborrow(genref: &mut Self) -> GenRef<'_, M, T> {
298        // SAFETY: `GenRef::as_ptr` guarantees that `ptr` points to a valid `T` and is valid for reads for `'_`. If `M` is `Mutable`, it also guarantees validity for writes.
299        // The `GenRef` received as argument is not used after calling `as_ptr` for the lifetime `'_`, and the pointer returned by `as_ptr` can not be aliased, both guaranteed by the exclusive reference received as argument.
300        // The correct lifetime and mutability parameters are enforced by the function signature.
301        unsafe { GenRef::from_ptr_unchecked(GenRef::as_ptr(genref)) }
302    }
303
304    #[inline(always)]
305    #[doc = docs_for!(map)]
306    pub fn map<U: ?Sized>(
307        genref: Self,
308        f_shared: impl FnOnce(&T) -> &U,
309        f_mut: impl FnOnce(&mut T) -> &mut U,
310    ) -> GenRef<'s, M, U> {
311        use crate::MutabilityEnum::*;
312
313        match M::mutability() {
314            Mutable(proof) => {
315                GenRef::gen_from_mut(f_mut(GenRef::gen_into_mut(genref, proof)), proof)
316            }
317            Shared(proof) => {
318                GenRef::gen_from_shared(f_shared(GenRef::gen_into_shared(genref, proof)), proof)
319            }
320        }
321    }
322
323    #[inline(always)]
324    #[doc = docs_for!(map_deref)]
325    pub fn map_deref(genref: Self) -> GenRef<'s, M, T::Target>
326    where
327        T: Deref + DerefMut,
328    {
329        GenRef::map(genref, Deref::deref, DerefMut::deref_mut)
330    }
331}
332
333impl<'s, T: ?Sized> GenRef<'s, Shared, T> {
334    #[inline(always)]
335    /// Converts a `GenRef<'_, Shared, T>` into `&T` in a non-generic context.
336    ///
337    /// This is used to unwrap the reference in end-user code.
338    ///
339    /// To perform the same operation in a generic context, use `gen_into_shared` or `gen_into_shared_downgrading`.
340    pub fn into_shared(genref: Self) -> &'s T {
341        Self::gen_into_shared(genref, Shared::mutability())
342    }
343}
344impl<'s, T: ?Sized> GenRef<'s, Mutable, T> {
345    #[inline(always)]
346    /// Converts a `GenRef<'_, Mutable T>` into `&mut T` in a non-generic context.
347    ///
348    /// This is used to unwrap the reference in end-user code.
349    ///
350    /// To perform the same operation in a generic context, use `gen_into_mut`.
351    pub fn into_mut(genref: Self) -> &'s mut T {
352        Self::gen_into_mut(genref, Mutable::mutability())
353    }
354}
355
356/// Creates a non-generic `GenRef<'_, Shared, T>` from a `&T`.
357///
358/// This is used to create a `GenRef` in end-user code.
359///
360/// To create a generic `GenRef<'_, M, T>`, use `gen_from_shared`.
361impl<'s, T: ?Sized> From<&'s T> for GenRef<'s, Shared, T> {
362    #[inline(always)]
363    fn from(reference: &'s T) -> Self {
364        GenRef::gen_from_shared(reference, Shared::mutability())
365    }
366}
367/// Creates a non-generic `GenRef<'_, Mutable, T>` from a `&mut T`.
368///
369/// This is used to create a `GenRef` in end-user code.
370///
371/// To create a generic `GenRef<'_, M, T>`, use `gen_from_mut` or `gen_from_mut_downgrading`.
372impl<'s, T: ?Sized> From<&'s mut T> for GenRef<'s, Mutable, T> {
373    #[inline(always)]
374    fn from(reference: &'s mut T) -> Self {
375        GenRef::gen_from_mut(reference, Mutable::mutability())
376    }
377}
378
379/// This is available in a generic context.
380impl<M: Mutability, T: ?Sized> Deref for GenRef<'_, M, T> {
381    type Target = T;
382    #[inline(always)]
383    fn deref(&self) -> &Self::Target {
384        let ptr = GenRef::as_ptr(self);
385
386        // SAFETY: `GenRef::as_ptr` guarantees that `ptr` points to a valid `T` and is valid for reads for `'s`.
387        // The correct lifetime is enforced by the function signature.
388        unsafe { ptr.as_ref() }
389    }
390}
391
392/// This is only implemented for `GenRef<'_, Mutable, T>`, and is not available in a generic context.
393///
394/// To get mutable access to the value, call `reborrow` followed by `gen_into_mut` (this requires proving that `M` is mutable).
395impl<T: ?Sized> DerefMut for GenRef<'_, Mutable, T> {
396    #[inline(always)]
397    fn deref_mut(&mut self) -> &mut Self::Target {
398        GenRef::into_mut(GenRef::reborrow(self))
399    }
400}
401
402/// This is only implemented for `GenRef<'_, Shared, T>`, and is not available in a generic context.
403impl<T: ?Sized> Clone for GenRef<'_, Shared, T> {
404    /// Copies the reference. This does not call `clone` on the pointed-to value.
405    #[inline(always)]
406    fn clone(&self) -> Self {
407        *self
408    }
409}
410/// This is only implemented for `GenRef<'_, Shared, T>`, and is not available in a generic context.
411impl<T: ?Sized> Copy for GenRef<'_, Shared, T> {}
412
413impl<M: Mutability, T: ?Sized> Borrow<T> for GenRef<'_, M, T> {
414    #[inline(always)]
415    fn borrow(&self) -> &T {
416        self
417    }
418}
419/// This is only implemented for `GenRef<'_, Mutable, T>`, and is not available in a generic context.
420impl<T: ?Sized> BorrowMut<T> for GenRef<'_, Mutable, T> {
421    #[inline(always)]
422    fn borrow_mut(&mut self) -> &mut T {
423        self
424    }
425}
426
427impl<M: Mutability, T: ?Sized> fmt::Pointer for GenRef<'_, M, T> {
428    #[inline(always)]
429    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
430        self.ptr.fmt(f)
431    }
432}
433
434/// This implementation requires `T: Sync` even when `M` is `Mutable`.
435/// With specialisation, this requirement could be lifted.
436// SAFETY: `GenRef` behaves like a reference, and both `&T` and `&mut T` implement `Send` if `T` is `Send` and `Sync`
437unsafe impl<M: Mutability, T: ?Sized> Send for GenRef<'_, M, T> where T: Send + Sync {}
438// SAFETY: `GenRef` behaves like a reference, and both `&T` and `&mut T` implement `Sync` if `T` is `Sync`
439unsafe impl<M: Mutability, T: ?Sized> Sync for GenRef<'_, M, T> where T: Sync {}