macro_rules! ctx {
(|$ctxt:pat_param| $true:expr, |$ctxf:pat_param| $false:expr $(, $($C:ty $(,)?)?)?) => {{
match $crate::__mac::cond::hold::<$($($C)?)?>() {
Ok($ctxt) => $true,
Err($ctxf) => $false,
}
}};
}
pub(crate) use ctx;
pub mod direct;
use core::mem::ManuallyDrop;
use crate::NatExpr;
#[allow(type_alias_bounds)]
pub type CondTy<Cond: NatExpr, True, False> = crate::internals::CondTy<Cond::Eval, True, False>;
#[repr(transparent)]
#[must_use]
pub struct CondResult<Cond: NatExpr, T, E> {
pub inner: CondTy<Cond, T, E>,
}
impl<C: NatExpr, T, E> CondResult<C, T, E> {
pub const fn into_inner(self) -> CondTy<C, T, E> {
unsafe {
crate::utils::union_transmute!(
CondResult::<C, T, E>, CondTy::<C, T, E>,
self,
)
}
}
pub const IS_OK: bool = !crate::is_zero::<C>();
pub const IS_ERR: bool = !Self::IS_OK;
pub const fn is_ok(&self) -> bool {
Self::IS_OK
}
pub const fn is_err(&self) -> bool {
Self::IS_ERR
}
pub const fn as_ref(&self) -> CondResult<C, &T, &E> {
CondResult {
inner: direct::as_ref::<C, _, _>(&self.inner),
}
}
pub const fn as_mut(&mut self) -> CondResult<C, &mut T, &mut E> {
CondResult {
inner: direct::as_mut::<C, _, _>(&mut self.inner),
}
}
#[expect(clippy::missing_errors_doc)]
pub const fn into_std(self) -> Result<T, E> {
ctx!(
|c| Ok(c.unwrap_ok(self)),
|c| Err(c.unwrap_err(self))
)
}
#[track_caller]
pub const fn new_ok(ok: T) -> Self {
ctx!(
|c| c.new_ok(ok),
|_| panic!("Call to `new_ok` on Err type")
)
}
pub const fn unwrap(self) -> T {
ctx!(
|c| c.unwrap_ok(self),
|_| panic!("Call to `unwrap` on Err type")
)
}
#[track_caller]
pub const fn new_err(err: E) -> Self {
ctx!(
|_| panic!("Call to `new_err` on Ok type"),
|c| c.new_err(err),
)
}
pub const fn unwrap_err(self) -> E {
ctx!(
|_| panic!("Call to `unwrap_err` on Ok type"),
|c| c.unwrap_err(self),
)
}
#[expect(clippy::missing_errors_doc)]
#[must_use = "The contents of this `Result` may need to be dropped, and it may be an `Err` variant, which needs to be handled."]
pub const fn into_manual_drop_std(self) -> Result<ManuallyDrop<T>, ManuallyDrop<E>> {
ctx!(
|c| Ok(ManuallyDrop::new(c.unwrap_ok(self))),
|c| Err(ManuallyDrop::new(c.unwrap_err(self))),
)
}
}
impl<C: NatExpr, T> CondResult<C, T, T> {
pub const fn new_trivial(inner: T) -> Self {
Self {
inner: direct::new_trivial::<C, _>(inner),
}
}
pub const fn unwrap_trivial(self) -> T {
direct::unwrap_trivial::<C, _>(self.into_inner())
}
}
#[repr(transparent)]
pub struct CondOption<Cond: NatExpr, T> {
pub inner: CondTy<Cond, T, ()>,
}
impl<C: NatExpr, T> CondOption<C, T> {
pub const fn into_inner(self) -> CondTy<C, T, ()> {
unsafe {
crate::utils::union_transmute!(
CondOption::<C, T>, CondTy::<C, T, ()>,
self,
)
}
}
pub const IS_SOME: bool = !crate::is_zero::<C>();
pub const IS_NONE: bool = !Self::IS_SOME;
pub const fn is_some(&self) -> bool {
Self::IS_SOME
}
pub const fn is_none(&self) -> bool {
Self::IS_NONE
}
pub const fn into_std(self) -> Option<T> {
ctx!(
|c| Some(c.unwrap_some(self)),
|c| {
c.drop_none(self);
None
},
)
}
pub const fn as_ref(&self) -> CondOption<C, &T> {
ctx!(
|c| c.new_some(c.unwrap_true(direct::as_ref::<C, _, _>(&self.inner))),
|c| c.new_none(),
)
}
pub const fn as_mut(&mut self) -> CondOption<C, &mut T> {
ctx!(
|c| c.new_some(c.unwrap_true(direct::as_mut::<C, _, _>(&mut self.inner))),
|c| c.new_none(),
)
}
pub const fn unwrap(self) -> T {
ctx!(
|c| c.unwrap_some(self),
|_| panic!("Call to `unwrap` on None instance"),
)
}
#[track_caller]
pub const fn assert_none(self) {
ctx!(
|_| panic!("Call to `assert_none` on Some instance"),
|c| c.drop_none(self),
)
}
}