use core::{
any::Any,
fmt::{Debug, Display},
hash::Hash,
marker::PhantomData,
mem::ManuallyDrop,
panic::{RefUnwindSafe, UnwindSafe},
};
use crate::Sealed;
#[expect(private_bounds, reason = "There are limited possible implementations.")]
pub unsafe trait Bool:
Sealed
+ Default
+ Clone
+ Copy
+ PartialEq
+ PartialOrd
+ Eq
+ Ord
+ Hash
+ Debug
+ Display
+ Send
+ Sync
+ Unpin
+ UnwindSafe
+ RefUnwindSafe
+ Any
+ 'static
{
const VALUE: bool;
type Not: Bool;
type And<T: Bool>: Bool;
type Or<T: Bool>: Bool;
type XOr<T: Bool>: Bool;
type Either<T, F>;
}
pub type Switch<B: Bool, T, F> = B::Either<T, F>;
#[inline(always)]
pub const fn bool_of<T: Bool>() -> bool {
T::VALUE
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Cond<const COND: bool>;
impl<const COND: bool> Display for Cond<COND> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
Display::fmt(&COND, f)
}
}
impl<const COND: bool> Sealed for Cond<COND> {}
pub type True = Cond<true>;
pub type False = Cond<false>;
unsafe impl Bool for True {
const VALUE: bool = true;
type Not = False;
type And<T: Bool> = T;
type Or<T: Bool> = True;
type XOr<T: Bool> = T::Not;
type Either<T, F> = T;
}
unsafe impl Bool for False {
const VALUE: bool = false;
type Not = True;
type And<T: Bool> = False;
type Or<T: Bool> = T;
type XOr<T: Bool> = T;
type Either<T, F> = F;
}
pub type And<P: Bool, Q: Bool> = P::And<Q>;
pub type Or<P: Bool, Q: Bool> = P::Or<Q>;
pub type XOr<P: Bool, Q: Bool> = P::XOr<Q>;
pub type Not<P: Bool> = P::Not;
#[macro_export]
macro_rules! all {
() => {
$crate::True
};
($B:ty $(,)?) => {
$B
};
($B1:ty, $($B:ty),+ $(,)?) => {
<$B1 as $crate::Bool>::And< $crate::all!( $($B),+ ) >
};
}
#[macro_export]
macro_rules! any {
() => {
$crate::False
};
($B:ty $(,)?) => {
$B
};
($B1:ty, $($B:ty),+ $(,)?) => {
<$B1 as $crate::Bool>::Or< $crate::any!( $($B),+ ) >
};
}
#[cfg(test)]
mod bool_logic_is_correct {
use crate::*;
use static_assertions::*;
assert_type_eq_all!(True, Or<True, True>, Or<False, True>, Or<True, False>, And<True, True>, XOr<False, True>, XOr<True, False>, all!(True, True), all!(True), all!(), any!(False, True), Not<False>, Not<Not<True>>);
assert_type_eq_all!(False, Or<False, False>, And<False, True>, And<True, False>, Or<False, False>, XOr<False, False>, XOr<True, True>, all!(False, True), all!(False), any!(), Not<True>, Not<Not<False>>);
}
pub unsafe trait SwitchStorage: Sized {
type OnTrue;
type OnFalse;
type Condition: Bool;
#[inline(always)]
fn new(value: Switch<Self::Condition, Self::OnTrue, Self::OnFalse>) -> Self {
unsafe { bool_macro_help::transmute_unchecked(value) }
}
#[inline(always)]
fn into_inner(self) -> Switch<Self::Condition, Self::OnTrue, Self::OnFalse> {
unsafe { bool_macro_help::transmute_unchecked(self) }
}
}
unsafe impl<'a, S: SwitchStorage> SwitchStorage for &'a S {
type OnTrue = &'a S::OnTrue;
type OnFalse = &'a S::OnFalse;
type Condition = S::Condition;
}
unsafe impl<'a, S: SwitchStorage> SwitchStorage for &'a mut S {
type OnTrue = &'a mut S::OnTrue;
type OnFalse = &'a mut S::OnFalse;
type Condition = S::Condition;
}
#[repr(transparent)]
pub struct SwitchCell<B: Bool, T, F = ()>(pub Switch<B, T, F>);
unsafe impl<B: Bool, T, F> SwitchStorage for SwitchCell<B, T, F> {
type OnTrue = T;
type OnFalse = F;
type Condition = B;
}
#[repr(C)]
#[derive(Clone, Copy)]
pub union SwitchUnion<B: Bool, T: Copy, F: Copy = ()> {
marker: PhantomData<B>,
on_true: T,
on_false: F,
}
unsafe impl<B: Bool, T: Copy, F: Copy> SwitchStorage for SwitchUnion<B, T, F> {
type OnTrue = T;
type OnFalse = F;
type Condition = B;
}
#[doc(hidden)]
pub mod bool_macro_help {
use super::*;
#[inline(always)]
pub(crate) const unsafe fn transmute_unchecked<Src, Dst>(src: Src) -> Dst {
#[repr(C)]
union Transmuter<Src, Dst> {
src: ManuallyDrop<Src>,
dst: ManuallyDrop<Dst>,
}
unsafe {
let x = Transmuter {
src: ManuallyDrop::new(src),
};
ManuallyDrop::into_inner(x.dst)
}
}
#[inline(always)]
pub fn condition_marker_value<T: Bool>(_condition: PhantomData<T>) -> bool {
T::VALUE
}
#[inline(always)]
pub fn switch_storage_condition_marker<T: SwitchStorage>(
_storage: &T,
) -> PhantomData<T::Condition> {
PhantomData
}
#[inline(always)]
pub unsafe fn into_true<T: SwitchStorage>(storage: T) -> T::OnTrue {
#[cfg(miri)]
{
assert!(T::Condition::VALUE);
}
unsafe { transmute_unchecked(storage) }
}
#[inline(always)]
pub unsafe fn from_true<T: SwitchStorage>(value: T::OnTrue) -> T {
#[cfg(miri)]
{
assert!(T::Condition::VALUE);
}
unsafe { transmute_unchecked(value) }
}
#[inline(always)]
pub unsafe fn into_false<T: SwitchStorage>(storage: T) -> T::OnFalse {
#[cfg(miri)]
{
assert!(!T::Condition::VALUE);
}
unsafe { transmute_unchecked(storage) }
}
#[inline(always)]
pub unsafe fn from_false<T: SwitchStorage>(value: T::OnFalse) -> T {
#[cfg(miri)]
{
assert!(!T::Condition::VALUE);
}
unsafe { transmute_unchecked(value) }
}
}
#[macro_export]
macro_rules! switch_match {
(match ( $first_i:ident $(= $first_e:expr)? $(, $i:ident $(= $e:expr)? )* $(,)? ) {true => $on_true:expr ; false => $on_false:expr $(;)? }) => {
{
$(let $first_i = $first_e;)?
#[allow(unused_assignments)]
#[allow(unused_mut)]
let mut condition = $crate::bool_macro_help::switch_storage_condition_marker(&$first_i);
$(
$(let $i = $e;)?
#[allow(unused_assignments)]
{ condition = $crate::bool_macro_help::switch_storage_condition_marker(&$i); }
)*
let condition = $crate::bool_macro_help::condition_marker_value(condition);
if condition {
let $first_i = unsafe {$crate::bool_macro_help::into_true($first_i)};
$(
let $i = unsafe {$crate::bool_macro_help::into_true($i)};
)*
$on_true
} else {
let $first_i = unsafe {$crate::bool_macro_help::into_false($first_i)};
$(
let $i = unsafe {$crate::bool_macro_help::into_false($i)};
)*
$on_false
}
}
};
(match ( $first_i:ident $(= $first_e:expr)? $(, $i:ident $(= $e:expr)? $(,)? )* ) { _ => $on_either:expr $(;)?}) => {
$crate::switch_match!(match ($first_i $(= $first_e)? $(, $i $(= $e)? )* ) { true => $on_either ; false => $on_either })
};
}
#[macro_export]
macro_rules! switch_map {
(match ( $first_i:ident $(= $first_e:expr)? $(, $i:ident $(= $e:expr)? )* $(,)? ) -> ( $($o:ident : $t:ty),+ $(,)? ) {true => $on_true:expr ; false => $on_false:expr $(;)? }) => {
{
$(let $first_i = $first_e;)?
#[allow(unused_assignments)]
let mut condition = $crate::bool_macro_help::switch_storage_condition_marker(&$first_i);
#[allow(unused_parens)]
$(
$(let $i = $e;)?
#[allow(unused_assignments)]
{ condition = $crate::bool_macro_help::switch_storage_condition_marker(&$i); }
)*
$(
#[allow(unused_assignments)]
{ condition = ::core::marker::PhantomData::<<$t as $crate::SwitchStorage>::Condition>; }
)+
let condition = $crate::bool_macro_help::condition_marker_value(condition);
#[allow(clippy::diverging_sub_expression)]
if condition {
let $first_i = unsafe {$crate::bool_macro_help::into_true($first_i)};
$(
let $i = unsafe {$crate::bool_macro_help::into_true($i)};
)*
#[allow(unused_parens)]
let ($($o),+) = $on_true;
#[allow(unreachable_code)]
($(
unsafe { $crate::bool_macro_help::from_true::<$t>($o) }
),+)
} else {
let $first_i = unsafe {$crate::bool_macro_help::into_false($first_i)};
$(
let $i = unsafe {$crate::bool_macro_help::into_false($i)};
)*
#[allow(unused_parens)]
let ($($o),+) = $on_false;
#[allow(unreachable_code)]
($(
unsafe { $crate::bool_macro_help::from_false::<$t>($o) }
),+)
}
}
};
(match ( $first_i:ident $(= $first_e:expr)? $(, $i:ident $(= $e:expr)? $(,)? )* ) -> ( $($o:ident : $t:ty),+ $(,)? ) { _ => $on_either:expr $(;)?}) => {
$crate::switch_map!(match ($first_i $(= $first_e)? $(, $i $(= $e)? )* ) -> ( $( $o:$t ),+ ) { true => $on_either ; false => $on_either })
};
}
#[macro_export]
macro_rules! switch_new {
(match -> ( $first_i:ident : $first_t:ty $(, $i:ident : $t:ty )* $(,)? ) {true => $on_true:expr ; false => $on_false:expr $(;)? }) => {
{
#[allow(unused_mut)]
#[allow(unused_assignments)]
let mut condition = ::core::marker::PhantomData::<<$first_t as $crate::SwitchStorage>::Condition>;
$(
#[allow(unused_assignments)]
{ condition = ::core::marker::PhantomData::<<$t as $crate::SwitchStorage>::Condition>; }
)*
let condition = $crate::bool_macro_help::condition_marker_value(condition);
#[allow(clippy::diverging_sub_expression)]
if condition {
#[allow(unused_parens)]
let ($first_i $(, $i)*) = $on_true;
#[allow(unreachable_code)]
(
unsafe { $crate::bool_macro_help::from_true::<$first_t>($first_i) }
$(
, unsafe { $crate::bool_macro_help::from_true::<$t>($i) }
)*
)
} else {
#[allow(unused_parens)]
let ($first_i $(, $i)*) = $on_false;
#[allow(unreachable_code)]
(
unsafe { $crate::bool_macro_help::from_false::<$first_t>($first_i) }
$(
, unsafe { $crate::bool_macro_help::from_false::<$t>($i) }
)*
)
}
}
};
(match -> ( $first_i:ident : $first_t:ty $(, $i:ident : $t:ty )* $(,)? ) { _ => $on_either:expr $(;)?}) => {
$crate::switch_new!(match -> ( $first_i:$first_t $(, $i:$t )* ) { true => $on_either ; false => $on_either })
};
}
impl<B: Bool, T: Debug, F: Debug> Debug for SwitchCell<B, T, F> {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
switch_match!(match (this = self) {
_ => Debug::fmt(this, f);
})
}
}
impl<B: Bool, T: Display, F: Display> Display for SwitchCell<B, T, F> {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
switch_match!(match (this = self) {
_ => Display::fmt(this, f);
})
}
}
impl<B: Bool, T: PartialEq, F: PartialEq> PartialEq for SwitchCell<B, T, F> {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
switch_match!(match (this = self, other) {
_ => PartialEq::eq(this, other);
})
}
}
impl<B: Bool, T: Eq, F: Eq> Eq for SwitchCell<B, T, F> {}
impl<B: Bool, T: PartialOrd, F: PartialOrd> PartialOrd for SwitchCell<B, T, F> {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
switch_match!(match (this = self, other) {
_ => PartialOrd::partial_cmp(this, other);
})
}
}
impl<B: Bool, T: Ord, F: Ord> Ord for SwitchCell<B, T, F> {
#[inline(always)]
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
switch_match!(match (this = self, other) {
_ => Ord::cmp(this, other);
})
}
}
impl<B: Bool, T: Hash, F: Hash> Hash for SwitchCell<B, T, F> {
#[inline(always)]
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
switch_match!(match (this = self) {
_ => Hash::hash(this, state);
});
}
}
unsafe impl<B: Bool, T: Send, F: Send> Send for SwitchCell<B, T, F> {}
unsafe impl<B: Bool, T: Sync, F: Sync> Sync for SwitchCell<B, T, F> {}
impl<B: Bool, T: Unpin, F: Unpin> Unpin for SwitchCell<B, T, F> {}
impl<B: Bool, T: UnwindSafe, F: UnwindSafe> UnwindSafe for SwitchCell<B, T, F> {}
impl<B: Bool, T: RefUnwindSafe, F: RefUnwindSafe> RefUnwindSafe for SwitchCell<B, T, F> {}
impl<B: Bool, T: Copy, F: Copy> Copy for SwitchCell<B, T, F> where Switch<B, T, F>: Copy {}
impl<B: Bool, T: Clone, F: Clone> Clone for SwitchCell<B, T, F> {
#[inline(always)]
fn clone(&self) -> Self {
switch_map!(match (this = self) -> (output: Self) {
_ => this.clone()
})
}
}
impl<B: Bool, T: Default, F: Default> Default for SwitchCell<B, T, F> {
#[inline(always)]
fn default() -> Self {
switch_new!(match -> (output: Self) {
_ => Default::default();
})
}
}
impl<B: Bool, T: Debug + Copy, F: Debug + Copy> Debug for SwitchUnion<B, T, F> {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
switch_match!(match (this = self) {
_ => Debug::fmt(this, f);
})
}
}
impl<B: Bool, T: Display + Copy, F: Display + Copy> Display for SwitchUnion<B, T, F> {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
switch_match!(match (this = self) {
_ => Display::fmt(this, f);
})
}
}
impl<B: Bool, T: PartialEq + Copy, F: PartialEq + Copy> PartialEq for SwitchUnion<B, T, F> {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
switch_match!(match (this = self, other) {
_ => PartialEq::eq(this, other);
})
}
}
impl<B: Bool, T: Eq + Copy, F: Eq + Copy> Eq for SwitchUnion<B, T, F> {}
impl<B: Bool, T: PartialOrd + Copy, F: PartialOrd + Copy> PartialOrd for SwitchUnion<B, T, F> {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
switch_match!(match (this = self, other) {
_ => PartialOrd::partial_cmp(this, other);
})
}
}
impl<B: Bool, T: Ord + Copy, F: Ord + Copy> Ord for SwitchUnion<B, T, F> {
#[inline(always)]
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
switch_match!(match (this = self, other) {
_ => Ord::cmp(this, other);
})
}
}
impl<B: Bool, T: Hash + Copy, F: Hash + Copy> Hash for SwitchUnion<B, T, F> {
#[inline(always)]
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
switch_match!(match (this = self) {
_ => Hash::hash(this, state);
});
}
}
impl<B: Bool, T: Default + Copy, F: Default + Copy> Default for SwitchUnion<B, T, F> {
#[inline(always)]
fn default() -> Self {
switch_new!(match -> (output: Self) {
_ => Default::default();
})
}
}
impl<B: Bool, T, F> SwitchCell<B, T, F> {
#[inline(always)]
pub fn as_ref(&self) -> SwitchCell<B, &T, &F> {
switch_map!(match (this = self) -> (out: SwitchCell<B, &T, &F>) {
_ => this;
})
}
#[inline(always)]
pub fn as_mut(&mut self) -> SwitchCell<B, &mut T, &mut F> {
switch_map!(match (this = self) -> (out: SwitchCell<B, &mut T, &mut F>) {
_ => this;
})
}
#[inline(always)]
pub fn merge<M: SwitchStorage<Condition = B>>(
self,
other: M,
) -> SwitchCell<B, (T, M::OnTrue), (F, M::OnFalse)> {
switch_map!(match (this = self, other) -> (out: SwitchCell<B, (T, M::OnTrue), (F, M::OnFalse)>) {
_ => (this, other);
})
}
#[inline(always)]
pub fn switch_match<O>(self, on_true: impl FnOnce(T) -> O, on_false: impl FnOnce(F) -> O) -> O {
switch_match!(match (this = self) {
true => on_true(this);
false => on_false(this);
})
}
#[inline(always)]
pub fn switch_map<T2, F2>(
self,
on_true: impl FnOnce(T) -> T2,
on_false: impl FnOnce(F) -> F2,
) -> SwitchCell<B, T2, F2> {
switch_map!(match (this = self) -> (out: SwitchCell<B, T2, F2>) {
true => on_true(this);
false => on_false(this);
})
}
#[inline(always)]
pub fn switch_new(on_true: impl FnOnce() -> T, on_false: impl FnOnce() -> F) -> Self {
switch_new!(match -> (out: Self) {
true => on_true();
false => on_false();
})
}
#[inline(always)]
pub fn switch_map_option<T2, F2>(
self,
on_true: impl FnOnce(T) -> Option<T2>,
on_false: impl FnOnce(F) -> Option<F2>,
) -> Option<SwitchCell<B, T2, F2>> {
Some(
switch_map!(match (this = self) -> (out: SwitchCell<B, T2, F2>) {
true => on_true(this)?;
false => on_false(this)?;
}),
)
}
#[inline(always)]
pub fn switch_new_option(
on_true: impl FnOnce() -> Option<T>,
on_false: impl FnOnce() -> Option<F>,
) -> Option<Self> {
Some(switch_new!(match -> (out: Self) {
true => on_true()?;
false => on_false()?;
}))
}
#[inline(always)]
pub fn switch_map_result<T2, F2, E>(
self,
on_true: impl FnOnce(T) -> Result<T2, E>,
on_false: impl FnOnce(F) -> Result<F2, E>,
) -> Result<SwitchCell<B, T2, F2>, E> {
Ok(
switch_map!(match (this = self) -> (out: SwitchCell<B, T2, F2>) {
true => on_true(this)?;
false => on_false(this)?;
}),
)
}
#[inline(always)]
pub fn switch_new_result<E>(
on_true: impl FnOnce() -> Result<T, E>,
on_false: impl FnOnce() -> Result<F, E>,
) -> Result<Self, E> {
Ok(switch_new!(match -> (out: Self) {
true => on_true()?;
false => on_false()?;
}))
}
}
impl<B: Bool, T: Copy, F: Copy> SwitchUnion<B, T, F> {
#[inline(always)]
pub fn as_ref(&self) -> SwitchUnion<B, &T, &F> {
switch_map!(match (this = self) -> (out: SwitchUnion<B, &T, &F>) {
_ => this;
})
}
#[inline(always)]
pub fn merge<M: SwitchStorage<Condition = B, OnFalse: Copy, OnTrue: Copy>>(
self,
other: M,
) -> SwitchUnion<B, (T, M::OnTrue), (F, M::OnFalse)> {
switch_map!(match (this = self, other) -> (out: SwitchUnion<B, (T, M::OnTrue), (F, M::OnFalse)>) {
_ => (this, other);
})
}
#[inline(always)]
pub fn switch_match<O>(self, on_true: impl FnOnce(T) -> O, on_false: impl FnOnce(F) -> O) -> O {
switch_match!(match (this = self) {
true => on_true(this);
false => on_false(this);
})
}
#[inline(always)]
pub fn switch_map<T2: Copy, F2: Copy>(
self,
on_true: impl FnOnce(T) -> T2,
on_false: impl FnOnce(F) -> F2,
) -> SwitchUnion<B, T2, F2> {
switch_map!(match (this = self) -> (out: SwitchUnion<B, T2, F2>) {
true => on_true(this);
false => on_false(this);
})
}
#[inline(always)]
pub fn switch_new(on_true: impl FnOnce() -> T, on_false: impl FnOnce() -> F) -> Self {
switch_new!(match -> (out: Self) {
true => on_true();
false => on_false();
})
}
#[inline(always)]
pub fn switch_map_option<T2: Copy, F2: Copy>(
self,
on_true: impl FnOnce(T) -> Option<T2>,
on_false: impl FnOnce(F) -> Option<F2>,
) -> Option<SwitchUnion<B, T2, F2>> {
Some(
switch_map!(match (this = self) -> (out: SwitchUnion<B, T2, F2>) {
true => on_true(this)?;
false => on_false(this)?;
}),
)
}
#[inline(always)]
pub fn switch_new_option(
on_true: impl FnOnce() -> Option<T>,
on_false: impl FnOnce() -> Option<F>,
) -> Option<Self> {
Some(switch_new!(match -> (out: Self) {
true => on_true()?;
false => on_false()?;
}))
}
#[inline(always)]
pub fn switch_map_result<T2: Copy, F2: Copy, E>(
self,
on_true: impl FnOnce(T) -> Result<T2, E>,
on_false: impl FnOnce(F) -> Result<F2, E>,
) -> Result<SwitchUnion<B, T2, F2>, E> {
Ok(
switch_map!(match (this = self) -> (out: SwitchUnion<B, T2, F2>) {
true => on_true(this)?;
false => on_false(this)?;
}),
)
}
#[inline(always)]
pub fn switch_new_result<E>(
on_true: impl FnOnce() -> Result<T, E>,
on_false: impl FnOnce() -> Result<F, E>,
) -> Result<Self, E> {
Ok(switch_new!(match -> (out: Self) {
true => on_true()?;
false => on_false()?;
}))
}
}
#[cfg(test)]
mod tests {
use core::num::{NonZeroI16, NonZeroU32};
use crate::*;
fn lifecycle_union<B: Bool>() {
let (a, mut b) = switch_new!(match -> (a: SwitchUnion<B, NonZeroU32, i16>, b: SwitchUnion<B, NonZeroU32, i16>) {
true => (NonZeroU32::new(5).unwrap(), NonZeroU32::new(3).unwrap());
false => (-2, 7);
});
let (x, y) = switch_map!(match (a, b = &mut b) -> (x: SwitchUnion<B, u32, NonZeroI16>, y: SwitchUnion<B, u32, NonZeroI16>) {
true => {
*b = b.saturating_add(1);
(a.get() * b.get(), a.get() + b.get())
};
false => {
*b = b.saturating_add(1);
(NonZeroI16::new(a * *b).unwrap(), NonZeroI16::new(a + *b).unwrap())
};
});
let truth = switch_match!(match (x, y, b) {
true => {
assert_eq!(x, 20);
assert_eq!(y, 9);
assert_eq!(b.get(), 4);
true
};
false => {
assert_eq!(x.get(), -16);
assert_eq!(y.get(), 6);
assert_eq!(b, 8);
false
}
});
assert_eq!(truth, B::VALUE);
}
fn lifecycle_cell<B: Bool>() {
let (a, mut b) = switch_new!(match -> (a: SwitchCell<B, NonZeroU32, i16>, b: SwitchCell<B, NonZeroU32, i16>) {
true => (NonZeroU32::new(5).unwrap(), NonZeroU32::new(3).unwrap());
false => (-2, 7);
});
let (x, y) = switch_map!(match (a, b = &mut b) -> (x: SwitchCell<B, u32, NonZeroI16>, y: SwitchCell<B, u32, NonZeroI16>) {
true => {
*b = b.saturating_add(1);
(a.get() * b.get(), a.get() + b.get())
};
false => {
*b = b.saturating_add(1);
(NonZeroI16::new(a * *b).unwrap(), NonZeroI16::new(a + *b).unwrap())
};
});
let truth = switch_match!(match (x, y, b) {
true => {
assert_eq!(x, 20);
assert_eq!(y, 9);
assert_eq!(b.get(), 4);
true
};
false => {
assert_eq!(x.get(), -16);
assert_eq!(y.get(), 6);
assert_eq!(b, 8);
false
}
});
assert_eq!(truth, B::VALUE);
}
#[test]
fn lifecycle_union_true() {
lifecycle_union::<True>();
}
#[test]
fn lifecycle_union_false() {
lifecycle_union::<False>();
}
#[test]
fn lifecycle_cell_true() {
lifecycle_cell::<True>();
}
#[test]
fn lifecycle_cell_false() {
lifecycle_cell::<False>();
}
}