use std::{ops::{Deref, DerefMut}, fmt::Debug};
use crate::TinyPtr;
#[repr(transparent)]
pub struct TinyBox<T>(TinyPtr<T>);
macro_rules! impl_traits {
($derefable:ident) => {
impl<T: std::fmt::Display> std::fmt::Display for $derefable<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.deref().fmt(f)
}
}
impl<T: std::hash::Hash> std::hash::Hash for $derefable<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
std::hash::Hash::hash(self.deref(), state)
}
}
};
}
impl<T: Debug> std::fmt::Debug for TinyBox<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("TinyBox").field(self.deref()).finish()
}
}
impl<T: Clone> Clone for TinyBox<T> {
fn clone(&self) -> Self {
Self::new(self.deref().clone())
}
}
pub(crate) use impl_traits;
impl_traits!(TinyBox);
impl<T> TinyBox<T> {
pub fn new(value: T) -> Self {
Self(TinyPtr::new(value))
}
}
impl<T> Deref for TinyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.0.get() }
}
}
impl<T> DerefMut for TinyBox<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.0.get_mut() }
}
}
impl<T> std::ops::Drop for TinyBox<T> {
fn drop(&mut self) {
self.0.take();
}
}
#[cfg(test)]
mod tests {
use crate::tests::*;
use super::*;
#[test]
fn assert_optimization_test() {
assert_eq!(std::mem::size_of::<Option<TinyBox<u8>>>(), std::mem::size_of::<TinyBox<u8>>());
}
#[test]
fn single_box_test() {
make_drop_indicator!(__ind, b, 42i32);
let mut b = TinyBox::new(b);
**b += 5;
assert_eq!(*b, 47);
std::mem::drop(b);
assert_dropped!(__ind);
}
#[test]
fn multiple_box_test() {
for i in 0..100 {
make_drop_indicator!(__ind, b, i);
let mut b = TinyBox::new(b);
**b += i;
assert_eq!(*b, i * 2);
std::mem::drop(b);
assert_dropped!(__ind);
}
}
}