use core::borrow::{Borrow, BorrowMut};
use core::fmt;
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};
use core::ptr::NonNull;
use crate::mutability::{IsMutable, IsShared, Mutability, Mutable, Shared};
pub mod genref_methods;
mod impl_traits;
#[repr(transparent)]
pub struct GenRef<'s, M: Mutability, T: ?Sized> {
_lifetime: PhantomData<&'s mut T>,
_mutability: PhantomData<*const M>,
ptr: NonNull<T>,
}
macro_rules! docs_for {
(as_ptr) => {
"Casts the reference into a `NonNull` pointer.
# Safety
The `GenRef` must not be used while the pointer is active.
The exact semantics of this depend on the memory model adopted by Rust.
# Guarantees
The returned pointer is guaranteed to be valid for reads for `'s`, and also for writes if `M` is `Mutable`."
};
(gen_into_shared_downgrading) => {
"Converts a generic `GenRef<'_, M, T>` into `&T`, downgrading the reference if `M` is `Mutable`.
If `M` is `Shared` it behaves exactly the same way as `gen_into_shared` without requiring a proof for sharedness.
In this case, the difference between the two is purely semantic: if you have proof that `M` is `Shared`, you should use `gen_into_shared`."
};
(gen_into_mut) => {
"Converts a generic `GenRef<'_, M, T>` into `&mut T`.
This is available in a generic context.
Once the transformations are done, the result can be converted back into a `GenRef` using the `gen_from_mut` function.
The conversion requires that `M` is `Mutable`, this must be proven by passing an `IsMutable<M>` value.
That can be obtained by `match`ing on `M::mutability()`."
};
(gen_into_shared) => {
"Converts a generic `GenRef<'_, M, T>` into `&T`.
This is available in a generic context.
Once the transformations are done, the result can be converted back into a `GenRef` using the `gen_from_shared` function.
The conversion requires that `M` is `Shared`, this must be proven by passing an `IsShared<M>` value.
That can be obtained by `match`ing on `M::mutability()`.
If you want to force the conversion even if `M` is `Mutable`, you can use the `gen_into_shared_downgrading` function."
};
(reborrow) => {
"Generically reborrows a `GenRef`.
That is, it creates a shorter-lived owned `GenRef` from a `&mut GenRef`.
This is available in a generic context.
This requires the variable to be marked `mut`, even if `M` is `Shared` and thus no mutation takes place."
};
(map) => {
"Maps a generic `GenRef` into another one using either `f_mut` or `f_shared`.
This is available in a generic context.
Using this function is usually sufficient.
For mapping over field access, you can use the `field!` macro instead.
If you need more flexibility, you can use the `gen_mut!` macro or `match`ing over `M::mutability()`."
};
(map_deref) => {
"Generically dereferences the value contained in the `GenRef`.
This is available in a generic context."
};
}
pub(self) use docs_for;
impl<'s, M: Mutability, T: ?Sized> GenRef<'s, M, T> {
#[inline(always)]
pub unsafe fn from_ptr_unchecked(ptr: NonNull<T>) -> Self {
Self {
_lifetime: PhantomData,
_mutability: PhantomData,
ptr,
}
}
#[inline(always)]
#[doc = docs_for!(as_ptr)]
pub fn as_ptr(genref: &Self) -> NonNull<T> {
genref.ptr
}
#[inline(always)]
pub fn gen_from_mut_downgrading(reference: &'s mut T) -> Self {
let ptr = NonNull::from(reference);
unsafe { Self::from_ptr_unchecked(ptr) }
}
#[inline(always)]
#[doc = docs_for!(gen_into_shared_downgrading)]
pub fn gen_into_shared_downgrading(genref: Self) -> &'s T {
let ptr = GenRef::as_ptr(&genref);
unsafe { ptr.as_ref() }
}
#[inline(always)]
#[doc = docs_for!(gen_into_mut)]
pub fn gen_into_mut(genref: Self, _proof: IsMutable<M>) -> &'s mut T {
let mut ptr = GenRef::as_ptr(&genref);
unsafe { ptr.as_mut() }
}
#[inline(always)]
pub fn gen_from_mut(reference: &'s mut T, _proof: IsMutable<M>) -> Self {
GenRef::gen_from_mut_downgrading(reference)
}
#[inline(always)]
#[doc = docs_for!(gen_into_shared)]
pub fn gen_into_shared(genref: Self, _proof: IsShared<M>) -> &'s T {
GenRef::gen_into_shared_downgrading(genref)
}
#[inline(always)]
pub fn gen_from_shared(reference: &'s T, _proof: IsShared<M>) -> Self {
let ptr = NonNull::from(reference);
unsafe { Self::from_ptr_unchecked(ptr) }
}
#[inline(always)]
#[doc = docs_for!(reborrow)]
pub fn reborrow(genref: &mut Self) -> GenRef<'_, M, T> {
unsafe { GenRef::from_ptr_unchecked(GenRef::as_ptr(genref)) }
}
#[inline(always)]
#[doc = docs_for!(map)]
pub fn map<U: ?Sized>(
genref: Self,
f_shared: impl FnOnce(&T) -> &U,
f_mut: impl FnOnce(&mut T) -> &mut U,
) -> GenRef<'s, M, U> {
use crate::MutabilityEnum::*;
match M::mutability() {
Mutable(proof) => {
GenRef::gen_from_mut(f_mut(GenRef::gen_into_mut(genref, proof)), proof)
}
Shared(proof) => {
GenRef::gen_from_shared(f_shared(GenRef::gen_into_shared(genref, proof)), proof)
}
}
}
#[inline(always)]
#[doc = docs_for!(map_deref)]
pub fn map_deref(genref: Self) -> GenRef<'s, M, T::Target>
where
T: Deref + DerefMut,
{
GenRef::map(genref, Deref::deref, DerefMut::deref_mut)
}
}
impl<'s, T: ?Sized> GenRef<'s, Shared, T> {
#[inline(always)]
pub fn into_shared(genref: Self) -> &'s T {
Self::gen_into_shared(genref, Shared::mutability())
}
}
impl<'s, T: ?Sized> GenRef<'s, Mutable, T> {
#[inline(always)]
pub fn into_mut(genref: Self) -> &'s mut T {
Self::gen_into_mut(genref, Mutable::mutability())
}
}
impl<'s, T: ?Sized> From<&'s T> for GenRef<'s, Shared, T> {
#[inline(always)]
fn from(reference: &'s T) -> Self {
GenRef::gen_from_shared(reference, Shared::mutability())
}
}
impl<'s, T: ?Sized> From<&'s mut T> for GenRef<'s, Mutable, T> {
#[inline(always)]
fn from(reference: &'s mut T) -> Self {
GenRef::gen_from_mut(reference, Mutable::mutability())
}
}
impl<M: Mutability, T: ?Sized> Deref for GenRef<'_, M, T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
let ptr = GenRef::as_ptr(self);
unsafe { ptr.as_ref() }
}
}
impl<T: ?Sized> DerefMut for GenRef<'_, Mutable, T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
GenRef::into_mut(GenRef::reborrow(self))
}
}
impl<T: ?Sized> Clone for GenRef<'_, Shared, T> {
#[inline(always)]
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized> Copy for GenRef<'_, Shared, T> {}
impl<M: Mutability, T: ?Sized> Borrow<T> for GenRef<'_, M, T> {
#[inline(always)]
fn borrow(&self) -> &T {
self
}
}
impl<T: ?Sized> BorrowMut<T> for GenRef<'_, Mutable, T> {
#[inline(always)]
fn borrow_mut(&mut self) -> &mut T {
self
}
}
impl<M: Mutability, T: ?Sized> fmt::Pointer for GenRef<'_, M, T> {
#[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.ptr.fmt(f)
}
}
unsafe impl<M: Mutability, T: ?Sized> Send for GenRef<'_, M, T> where T: Send + Sync {}
unsafe impl<M: Mutability, T: ?Sized> Sync for GenRef<'_, M, T> where T: Sync {}