use core::fmt;
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};
use crate::token::InvariantLifetime;
macro_rules! branded_guard {
(
$(#[$shared_doc:meta])*
shared: $shared:ident;
$(#[$shared_into_doc:meta])*
shared_into: $shared_into:ident $([ $shared_const:tt ])?;
shared_map: { $(#[$shared_map_doc:meta])* }
shared_split: { $(#[$shared_split_doc:meta])* }
$(#[$excl_doc:meta])*
exclusive: $excl:ident;
$(#[$excl_into_doc:meta])*
exclusive_into: $excl_into:ident $([ $excl_const:tt ])?;
excl_map: { $(#[$excl_map_doc:meta])* }
excl_split: { $(#[$excl_split_doc:meta])* }
) => {
branded_guard! {
@one
[ $(#[$shared_doc])* ]
[ $shared ]
[ & 'a ]
[ $(#[$shared_into_doc])* ]
[ $shared_into ]
[ $($shared_const)? ]
[ $(#[$shared_map_doc])* ]
[ $(#[$shared_split_doc])* ]
[ no ]
}
branded_guard! {
@one
[ $(#[$excl_doc])* ]
[ $excl ]
[ & 'a mut ]
[ $(#[$excl_into_doc])* ]
[ $excl_into ]
[ $($excl_const)? ]
[ $(#[$excl_map_doc])* ]
[ $(#[$excl_split_doc])* ]
[ yes ]
}
};
(
@one
[ $(#[$doc:meta])* ]
[ $name:ident ]
[ $($refer:tt)* ]
[ $(#[$into_doc:meta])* ]
[ $into:ident ]
[ $($into_const:tt)? ]
[ $(#[$map_doc:meta])* ]
[ $(#[$split_doc:meta])* ]
[ $deref_mut:tt ]
) => {
$(#[$doc])*
#[repr(transparent)]
pub struct $name<'a, 'brand, T: ?Sized> {
value: $($refer)* T,
_brand: InvariantLifetime<'brand>,
}
impl<'a, 'brand, T: ?Sized> $name<'a, 'brand, T> {
#[inline]
pub(crate) fn new(value: $($refer)* T) -> Self {
Self {
value,
_brand: PhantomData,
}
}
$(#[$into_doc])*
#[inline]
#[must_use]
pub $($into_const)? fn $into(self) -> $($refer)* T {
self.value
}
$(#[$map_doc])*
#[inline]
pub fn map<U: ?Sized, F>(orig: Self, f: F) -> $name<'a, 'brand, U>
where
F: FnOnce($($refer)* T) -> $($refer)* U,
{
$name::new(f(orig.value))
}
$(#[$split_doc])*
#[inline]
pub fn map_split<U: ?Sized, V: ?Sized, F>(
orig: Self,
f: F,
) -> ($name<'a, 'brand, U>, $name<'a, 'brand, V>)
where
F: FnOnce($($refer)* T) -> ($($refer)* U, $($refer)* V),
{
let (a, b) = f(orig.value);
($name::new(a), $name::new(b))
}
}
impl<'a, 'brand, T: ?Sized> Deref for $name<'a, 'brand, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.value
}
}
branded_guard!(@deref_mut $deref_mut, $name);
impl<'a, 'brand, T: ?Sized + fmt::Debug> fmt::Debug for $name<'a, 'brand, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.value, f)
}
}
};
(@deref_mut no, $name:ident) => {};
(@deref_mut yes, $name:ident) => {
impl<'a, 'brand, T: ?Sized> DerefMut for $name<'a, 'brand, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
self.value
}
}
};
}
branded_guard! {
shared: MelinoeRef;
shared_into: into_ref [const];
shared_map: {
}
shared_split: {
}
exclusive: MelinoeMut;
exclusive_into: into_mut;
excl_map: {
}
excl_split: {
}
}