use crate::{
array::{Array, helper::*},
condty::CondResult,
};
macro_rules! cast_by_raw {
($name:ident, $param:expr) => {
$name!(from_raw, $name!(into_raw, $param).cast())
};
}
macro_rules! decl_ptr {
(
$name:ident,
modifiers! $modifiers:tt,
$($input:tt)*
) => {
decl_ptr! {
@[$]
$name,
modifiers! $modifiers,
modifiers! $modifiers,
$($input)*
}
};
(
@[$DOLLAR_SIGN:tt]
$name:ident,
modifiers! $modifiers:tt,
modifiers! { $($mods:tt)* },
typ! { $tparam:ident => $($typ:tt)* },
doc = ($docname_lhs:expr, $docname_rhs:expr),
$(into_raw = |$into_raw_par:pat_param| $into_raw:expr,)?
$(from_raw = |$from_raw_par:pat_param| $from_raw:expr,)?
cast = |$cast_par:pat_param| $cast:expr,
fns {
$($fn:ident: $impl:tt),* $(,)?
}
$(,)?
) => {
macro_rules! $name {
(typ, $DOLLAR_SIGN$tparam:ty) => { $($typ)* };
(docname, $inner_name:expr) => { core::concat!($docname_lhs, $inner_name, $docname_rhs) };
$( (into_raw, $ptr:expr) => {{ let $into_raw_par = $ptr; $into_raw }}; )?
$( (from_raw, $ptr:expr) => {{ let $from_raw_par = $ptr; $from_raw }}; )?
(cast, $src:expr) => {{ let $cast_par = $src; $cast }};
$( (fn $fn, $cb:ident) => { $cb! { $name $modifiers $impl } }; )*
(fn $unknown:ident, $cb:ident) => {};
}
};
}
decl_ptr![
Ref,
modifiers! { pub const },
typ! { inner => &$inner },
doc = ("`&", "`"),
into_raw = |r| core::ptr::from_ref(r).cast_mut(),
from_raw = |r| &*r,
cast = |r| cast_by_raw!(Ref, r),
fns {
retype: (retype_ref, try_retype_ref),
unsize: unsize_ref,
try_from_slice: (try_from_ref_slice, FromSliceOption),
},
];
decl_ptr![
RefMut,
modifiers! { pub const },
typ! { inner => &mut $inner },
doc = ("`&mut ", "`"),
into_raw = |r| core::ptr::from_mut(r),
from_raw = |r| &mut *r,
cast = |r| cast_by_raw!(RefMut, r),
fns {
retype: (retype_mut, try_retype_mut),
unsize: unsize_mut,
try_from_slice: (try_from_mut_slice, FromSliceOption),
},
];
decl_ptr![
Owned,
modifiers! { pub const },
typ! { inner => $inner },
doc = ("`", "`"),
cast = |r| crate::utils::_union_transmute(r),
fns {
retype: (retype, try_retype),
},
];
decl_ptr![
Box,
modifiers! {
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub
},
typ! { inner => alloc::boxed::Box<$inner> },
doc = ("[`Box<", ">`](std::boxed::Box)"),
into_raw = |r| alloc::boxed::Box::into_raw(r),
from_raw = |r| alloc::boxed::Box::from_raw(r),
cast = |r| cast_by_raw!(Box, r),
fns {
retype: (retype_box, try_retype_box),
unsize: unsize_box,
try_from_slice: (try_from_boxed_slice, FromSliceResult),
},
];
decl_ptr![
Rc,
modifiers! {
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub
},
typ! { inner => alloc::rc::Rc<$inner> },
doc = ("[`Rc<", ">`](std::boxed::Box)"),
into_raw = |r| alloc::rc::Rc::into_raw(r).cast_mut(),
from_raw = |r| alloc::rc::Rc::from_raw(r),
cast = |r| cast_by_raw!(Rc, r),
fns {
retype: (retype_rc, try_retype_rc),
unsize: unsize_rc,
try_from_slice: (try_from_rc_slice, FromSliceResult),
},
];
decl_ptr![
Arc,
modifiers! {
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub
},
typ! { inner => alloc::sync::Arc<$inner> },
doc = ("[`Rc<", ">`](std::boxed::Box)"),
into_raw = |r| alloc::sync::Arc::into_raw(r).cast_mut(),
from_raw = |r| alloc::sync::Arc::from_raw(r),
cast = |r| cast_by_raw!(Arc, r),
fns {
retype: (retype_arc, try_retype_arc),
unsize: unsize_arc,
try_from_slice: (try_from_arc_slice, FromSliceResult),
},
];
macro_rules! for_each_ptr {
($fn:ident, $cb:ident) => {
Ref! { fn $fn, $cb }
RefMut! { fn $fn, $cb }
Box! { fn $fn, $cb }
Rc! { fn $fn, $cb }
Arc! { fn $fn, $cb }
Owned! { fn $fn, $cb }
};
}
macro_rules! decl_retype {
($ty:ident { $($mods:tt)* } ($retype:ident, $try_retype:ident)) => {
#[doc = core::concat!(
"Converts between ",
$ty!(docname, "impl Array"),
".",
)]
$($mods)* fn $retype<Src, Dst>(src: $ty!(typ, Src)) -> $ty!(typ, Dst)
where
Src: Array,
Dst: Array<Item = Src::Item, Length = Src::Length>,
{
arr_impl_ubcheck::<Src>();
arr_impl_ubcheck::<Dst>();
unsafe { $ty!(cast, src) }
}
#[doc = core::concat!(
"Converts between ",
$ty!(docname, "impl Array"),
".",
)]
$($mods)* fn $try_retype<Src, Dst>(src: $ty!(typ, Src)) -> CondResult<
crate::expr::Eq<Src::Length, Dst::Length>,
$ty!(typ, Dst),
$ty!(typ, Src),
>
where
Src: Array,
Dst: Array<Item = Src::Item>,
{
arr_impl_ubcheck::<Src>();
arr_impl_ubcheck::<Dst>();
crate::condty::ctx!(
|c| c.new_ok(
unsafe { $ty!(cast, src) },
),
|c| c.new_err(src),
)
}
};
}
for_each_ptr!(retype, decl_retype);
macro_rules! decl_unsize {
($ty:ident { $($mods:tt)* } $name:ident) => {
#[doc = core::concat!(
"Converts ",
$ty!(docname, "impl Array<Item = T>"),
" to ",
$ty!(docname, "[T]"),
".",
)]
#[track_caller]
$($mods)* fn $name<A: Array>(arr: $ty!(typ, A)) -> $ty!(typ, [A::Item]) {
arr_impl_ubcheck::<A>();
unsafe { $ty!(from_raw, crate::array::helper::unsize_raw_mut($ty!(into_raw, arr))) }
}
};
}
for_each_ptr!(unsize, decl_unsize);
#[cfg(feature = "alloc")]
macro_rules! FromSliceResult {
(type, $T:ty, $E:ty) => { Result<$T, $E> };
(Ok, $expr:expr) => { Ok($expr) };
(Err, $expr:expr) => { Err($expr) };
}
macro_rules! FromSliceOption {
(type, $T:ty, $E:ty) => { Option<$T> };
(Ok, $expr:expr) => { Some($expr) };
(Err, $expr:expr) => { None };
}
macro_rules! decl_from_slice {
($ty:ident { $($mods:tt)* } ($name:ident, $Res:ident)) => {
#[doc = core::concat!(
"Converts ",
$ty!(docname, "[T]"),
" to ",
$ty!(docname, "impl Array<Item = T>"),
".",
)]
$($mods)* fn $name<A: Array>(slice: $ty!(typ, [A::Item])) -> $Res!(type, $ty!(typ, A), $ty!(typ, [A::Item])) {
arr_impl_ubcheck::<A>();
match crate::to_usize::<A::Length>() {
Some(arr_len) if arr_len == slice.len() => {
let slice: $ty!(typ, A) = unsafe { $ty!(from_raw, $ty!(into_raw, slice).cast()) };
$Res!(Ok, slice)
},
_ => $Res!(Err, slice),
}
}
};
}
for_each_ptr!(try_from_slice, decl_from_slice);