#![allow(dead_code)]
use std::mem::ManuallyDrop;
use std::ops::Drop;
use peckr::alloc::boxed::PackedBox;
union EitherUnion<L, R> {
left: ManuallyDrop<L>,
right: ManuallyDrop<R>,
}
#[derive(Debug)]
enum Either<L, R> {
Left(L),
Right(R),
}
struct EitherBox<L, R> {
inner: PackedBox<1, EitherUnion<L, R>>,
}
fn main() {
let mut either: EitherBox<i32, String> =
EitherBox::right("ganda cena mano de broa velho".into());
println!("init value: {:#?}", either.get_ref());
let old_val = either.set(Either::Left(1234));
println!("old value: {old_val:#?}");
println!("new value: {:#?}", either.get_ref());
println!("pointer: {:p}", either.inner.as_ref());
}
impl<L, R> EitherBox<L, R> {
fn left(value: L) -> Self {
let inner = PackedBox::new(EitherUnion {
left: ManuallyDrop::new(value),
})
.unwrap();
Self { inner }
}
fn right(value: R) -> Self {
let mut inner = PackedBox::new(EitherUnion {
right: ManuallyDrop::new(value),
})
.unwrap();
inner.set_bit_high(0);
Self { inner }
}
fn set(&mut self, value: Either<L, R>) -> Either<L, R> {
let old_value = match self.inner.get_bit(0) {
false => Either::Left(unsafe { ManuallyDrop::take(&mut self.inner.as_mut().left) }),
true => Either::Right(unsafe { ManuallyDrop::take(&mut self.inner.as_mut().right) }),
};
match value {
Either::Left(value) => {
self.inner.set_bit_low(0);
unsafe {
*self.inner.as_mut().left = value;
}
}
Either::Right(value) => {
self.inner.set_bit_high(0);
unsafe {
*self.inner.as_mut().right = value;
}
}
}
old_value
}
fn get_ref(&self) -> Either<&L, &R> {
match self.inner.get_bit(0) {
false => Either::Left(unsafe { &self.inner.as_ref().left }),
true => Either::Right(unsafe { &self.inner.as_ref().right }),
}
}
fn get_mut(&mut self) -> Either<&mut L, &mut R> {
match self.inner.get_bit(0) {
false => Either::Left(unsafe { &mut self.inner.as_mut().left }),
true => Either::Right(unsafe { &mut self.inner.as_mut().right }),
}
}
}
impl<L, R> Drop for EitherBox<L, R> {
fn drop(&mut self) {
match self.inner.get_bit(0) {
false => unsafe { ManuallyDrop::drop(&mut self.inner.as_mut().left) },
true => unsafe { ManuallyDrop::drop(&mut self.inner.as_mut().right) },
}
}
}