use std::any::{TypeId, Any};
pub struct Anon {
inner: Vec<u8>,
typeid: TypeId,
}
impl Anon {
pub fn new<T>(val: T) -> Self
where
T: Any + 'static,
{
let mut inner: Vec<u8> = (0..std::mem::size_of::<T>()).map(|_| 0).collect();
let ptr = inner.as_mut_ptr() as *mut T;
unsafe { *(ptr) = val; }
Self {
inner, typeid: TypeId::of::<T>(),
}
}
pub fn from_ptr(ptr: *const u8, size: usize, typeid: TypeId) -> Self {
Self {
inner: Vec::from_iter((0..size).map(|i| unsafe { *(ptr.add(i)) })),
typeid,
}
}
pub fn uninit() -> Self {
Self {
inner: Vec::new(),
typeid: TypeId::of::<i32>(),
}
}
pub fn init<T>(&mut self, val: T)
where
T: Any + 'static,
{
self.inner.extend((0..std::mem::size_of::<T>()).map(|_| 0));
let ptr = self.inner.as_mut_ptr() as *mut T;
unsafe { *(ptr) = val; }
self.typeid = TypeId::of::<T>();
}
pub fn inner(self) -> Vec<u8> {
self.inner
}
pub fn size(&self) -> usize {
self.inner.len()
}
pub fn typeid(&self) -> TypeId {
self.typeid
}
pub fn as_slice(&self) -> &[u8] {
self.inner.as_slice()
}
pub fn as_mut_slice(&mut self) -> &mut [u8] {
self.inner.as_mut_slice()
}
pub fn is_uninit(&self) -> bool {
self.inner.is_empty()
}
pub fn cast_ref<T>(&self) -> &T
where
T: Any + 'static,
{
unsafe { &*(self.inner.as_ptr() as *const T) }
}
pub fn cast_mut<T>(&mut self) -> &mut T
where
T: Any + 'static,
{
unsafe { &mut *(self.inner.as_mut_ptr() as *mut T) }
}
pub fn consume<T>(self) -> T
where
T: Any + Clone + 'static,
{
let out = unsafe { &*(self.inner.as_ptr() as *const T) };
out.clone()
}
}
#[cfg(test)]
mod tests {
use crate::anon::Anon;
#[repr(C)]
#[derive(PartialEq, Debug, Clone)]
struct Thing {
pub a: i32,
pub b: i32,
pub c: i32,
}
impl Thing {
fn new(a: i32, b: i32, c: i32) -> Self {
Self { a, b, c }
}
fn sum(&self) -> i32 {
self.a + self.b + self.c
}
}
#[test]
fn new() {
let t = Thing::new(1, 2, 3);
let anon = Anon::new(t);
let thing = anon.cast_ref::<Thing>();
assert_eq!(6, thing.sum());
}
#[test]
fn uninit_init() {
let mut anon = Anon::uninit();
{
let t = Thing::new(1, 2, 3);
anon.init::<Thing>(t);
}
let thing = anon.cast_ref::<Thing>();
assert_eq!(6, thing.sum());
}
#[test]
fn vec() {
let mut anon = Anon::uninit();
{
let t =
vec![
Thing::new(1, 2, 3),
Thing::new(1, 2, 3),
Thing::new(1, 2, 3),
];
anon.init::<Vec<Thing>>(t);
}
let things = anon.cast_ref::<Vec<Thing>>();
let v = things[0].sum() + things[1].sum() + things[2].sum();
assert_eq!(v, 18);
}
#[test]
fn consume() {
let mut anon = Anon::uninit();
{
let t =
vec![
Thing::new(1, 2, 3),
Thing::new(1, 2, 3),
Thing::new(1, 2, 3),
];
anon.init::<Vec<Thing>>(t);
}
let things = anon.consume::<Vec<Thing>>();
let v = things[0].sum() + things[1].sum() + things[2].sum();
assert_eq!(v, 18);
}
}