peckr 0.6.1

Rust pointer type that allows packing additional data along with the underlying memory offset.
Documentation
// inspired by: https://github.com/antirez/rax

#![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) {
            // left
            false => unsafe { ManuallyDrop::drop(&mut self.inner.as_mut().left) },
            // right
            true => unsafe { ManuallyDrop::drop(&mut self.inner.as_mut().right) },
        }
    }
}