use std::{mem, ptr};
use crate::into;
use crate::limits::{self, NWORDS};
use crate::Trident;
#[cfg(not(any(target_pointer_width = "64", target_pointer_width = "32")))]
compile_error!("Not a 32- or 64-bit machine");
#[cfg_attr(target_pointer_width = "64", repr(C, align(8)))]
#[cfg_attr(target_pointer_width = "32", repr(C, align(4)))]
pub struct Erased {
words: [usize; NWORDS],
}
impl Erased {
pub fn new<T>(t: T) -> Self {
if limits::should_inline::<T>() {
let mut ret = Self { words: [0; NWORDS] };
unsafe {
ptr::copy_nonoverlapping(&t, ret.as_mut_ref(), 1);
}
mem::forget(t);
ret
} else {
let alloc = Box::new(t);
Self {
words: [Box::into_raw(alloc) as usize, 0, 0],
}
}
}
pub unsafe fn as_ptr<T>(&self) -> *const T {
if limits::should_inline::<T>() {
&self.words as *const _ as usize as *const T
} else {
self.words[0] as *const T
}
}
pub unsafe fn as_ref<T>(&self) -> &T {
&*self.as_ptr()
}
pub unsafe fn as_mut_ptr<T>(&mut self) -> *mut T {
if limits::should_inline::<T>() {
&mut self.words as *mut _ as usize as *mut T
} else {
self.words[0] as *mut T
}
}
pub unsafe fn as_mut_ref<T>(&mut self) -> &mut T {
&mut *self.as_mut_ptr()
}
pub unsafe fn get<T: Copy>(&self) -> T {
*self.as_ref()
}
pub unsafe fn into_inner<T>(mut self) -> T {
into::into_inner(self.as_mut_ptr(), self)
}
pub unsafe fn into_trident<T>(self) -> Trident<T> {
Trident::from_erased(self)
}
}