use core::mem::ManuallyDrop;
use crate::{public_traits::*, Here, There};
#[repr(C)]
pub union Union<A, B> {
pub(crate) head: ManuallyDrop<A>,
pub(crate) tail: ManuallyDrop<B>,
}
#[derive(Copy, Clone, Debug)]
pub enum EmptyUnion {}
#[macro_export]
macro_rules! MkUnion {
($t: ty) => ($crate::Union<$t, $crate::EmptyUnion>);
($h:ty, $($t:ty),+) => ($crate::Union<$h, $crate::MkUnion!($($t),+)>);
}
impl<A: Copy, B: Copy> Clone for Union<A, B> {
fn clone(&self) -> Self {
*self
}
}
impl<A: Copy, B: Copy> Copy for Union<A, B> {}
pub trait IndexedClone {
unsafe fn iclone(&self, i: u32) -> Self;
}
impl<H: Clone, T: IndexedClone> IndexedClone for Union<H, T> {
unsafe fn iclone(&self, i: u32) -> Self {
if i == 0 {
Union {
head: self.head.clone(),
}
} else {
Union {
tail: ManuallyDrop::new(self.tail.iclone(i - 1)),
}
}
}
}
impl IndexedClone for EmptyUnion {
#[inline]
unsafe fn iclone(&self, _: u32) -> Self {
match *self {}
}
}
pub trait IndexedDebug {
unsafe fn ifmt(&self, f: &mut core::fmt::Formatter<'_>, i: u32) -> core::fmt::Result;
}
impl<H: core::fmt::Debug, T: IndexedDebug> IndexedDebug for Union<H, T> {
unsafe fn ifmt(&self, f: &mut core::fmt::Formatter<'_>, i: u32) -> core::fmt::Result {
if i == 0 {
self.head.fmt(f)
} else {
self.tail.ifmt(f, i - 1)
}
}
}
impl IndexedDebug for EmptyUnion {
#[inline]
unsafe fn ifmt(&self, _: &mut core::fmt::Formatter<'_>, _: u32) -> core::fmt::Result {
match *self {}
}
}
impl<H, T: IndexedDrop> IndexedDrop for Union<H, T> {
unsafe fn idrop(&mut self, i: u32) {
if i == 0 {
ManuallyDrop::drop(&mut self.head)
} else {
self.tail.idrop(i - 1)
}
}
}
impl IndexedDrop for EmptyUnion {
#[inline]
unsafe fn idrop(&mut self, _: u32) {
match *self {}
}
}
pub trait IndexedEq {
unsafe fn ieq(&self, other: &Self, i: u32) -> bool;
}
impl<H: PartialEq, T: IndexedEq> IndexedEq for Union<H, T> {
unsafe fn ieq(&self, other: &Self, i: u32) -> bool {
if i == 0 {
self.head == other.head
} else {
self.tail.ieq(&other.tail, i - 1)
}
}
}
impl IndexedEq for EmptyUnion {
#[inline]
unsafe fn ieq(&self, _: &Self, _: u32) -> bool {
match *self {}
}
}
impl<X, Rest> UnionAt<Here, X> for Union<X, Rest> {
fn inject(x: X) -> Self {
Union {
head: ManuallyDrop::new(x),
}
}
unsafe fn take(self) -> X {
ManuallyDrop::into_inner(self.head)
}
type Pruned = Rest;
}
impl<I, X, H, T> UnionAt<There<I>, X> for Union<H, T>
where
T: UnionAt<I, X>,
{
fn inject(x: X) -> Self {
Union {
tail: ManuallyDrop::new(T::inject(x)),
}
}
unsafe fn take(self) -> X {
ManuallyDrop::into_inner(self.tail).take()
}
type Pruned = Union<H, T::Pruned>;
}
pub unsafe fn union_transmute<X, Y>(x: X) -> Y {
#[repr(C)]
union Transmuter<A, B> {
before: ManuallyDrop<A>,
after: ManuallyDrop<B>,
}
ManuallyDrop::into_inner(
Transmuter {
before: ManuallyDrop::new(x),
}
.after,
)
}