use std::any::TypeId;
use std::mem::MaybeUninit;
use crate::bytes::*;
use crate::elem::*;
use crate::vtable::*;
use crate::CopyElem;
macro_rules! impl_value_base {
() => {
#[inline]
pub fn size(&self) -> usize {
self.bytes.get_bytes_ref().len()
}
#[inline]
pub fn value_type_id(&self) -> TypeId {
self.type_id
}
#[inline]
pub fn value_alignment(&self) -> usize {
self.alignment
}
#[inline]
pub fn is<T: 'static>(&self) -> bool {
self.value_type_id() == TypeId::of::<T>()
}
#[inline]
fn downcast_with<T: 'static, U, F: FnOnce(Self) -> U>(self, f: F) -> Option<U> {
if self.is::<T>() {
Some(f(self))
} else {
None
}
}
};
}
pub trait GetBytesRef {
fn get_bytes_ref(&self) -> &[MaybeUninit<u8>];
}
pub trait GetBytesMut: GetBytesRef {
fn get_bytes_mut(&mut self) -> &mut [MaybeUninit<u8>];
}
pub trait DropAsAligned {
fn drop_as_aligned(&mut self, alignment: usize);
}
impl GetBytesRef for Box<[MaybeUninit<u8>]> {
#[inline]
fn get_bytes_ref(&self) -> &[MaybeUninit<u8>] {
&*self
}
}
impl GetBytesMut for Box<[MaybeUninit<u8>]> {
#[inline]
fn get_bytes_mut(&mut self) -> &mut [MaybeUninit<u8>] {
&mut *self
}
}
impl DropAsAligned for Box<[MaybeUninit<u8>]> {
#[inline]
fn drop_as_aligned(&mut self, alignment: usize) {
fn drop_bytes<T: 'static>(b: Box<[MaybeUninit<u8>]>) {
let size = b.len() / std::mem::align_of::<T>();
let ptr: *mut T = Box::into_raw(b) as *mut T;
unsafe {
let slice_t = std::slice::from_raw_parts_mut(ptr, size);
let _ = Box::from_raw(slice_t);
}
}
eval_align!(alignment; drop_bytes::<_>(std::mem::take(self)));
}
}
impl GetBytesRef for MaybeUninit<usize> {
#[inline]
fn get_bytes_ref(&self) -> &[MaybeUninit<u8>] {
Bytes::as_bytes(self)
}
}
impl GetBytesMut for MaybeUninit<usize> {
#[inline]
fn get_bytes_mut(&mut self) -> &mut [MaybeUninit<u8>] {
Bytes::as_bytes_mut(self)
}
}
impl DropAsAligned for MaybeUninit<usize> {
#[inline]
fn drop_as_aligned(&mut self, _: usize) {
}
}
impl GetBytesRef for [MaybeUninit<u8>] {
#[inline]
fn get_bytes_ref(&self) -> &[MaybeUninit<u8>] {
self
}
}
impl GetBytesMut for [MaybeUninit<u8>] {
#[inline]
fn get_bytes_mut(&mut self) -> &mut [MaybeUninit<u8>] {
self
}
}
#[derive(Clone)]
pub struct CopyValueRef<'a, V = ()>
where
V: ?Sized,
{
pub(crate) bytes: &'a [MaybeUninit<u8>],
pub(crate) type_id: TypeId,
pub(crate) alignment: usize,
pub(crate) vtable: VTableRef<'a, V>,
}
impl<'a, V> CopyValueRef<'a, V> {
#[inline]
pub fn new<T: CopyElem>(typed: &'a T) -> CopyValueRef<'a, V>
where
V: VTable<T>,
{
CopyValueRef {
bytes: typed.as_bytes(),
type_id: TypeId::of::<T>(),
alignment: std::mem::align_of::<T>(),
vtable: VTableRef::Box(Box::new(V::build_vtable())),
}
}
}
impl<'a, V: ?Sized> CopyValueRef<'a, V> {
impl_value_base!();
#[inline]
pub(crate) unsafe fn from_raw_parts(
bytes: &'a [MaybeUninit<u8>],
type_id: TypeId,
alignment: usize,
vtable: impl Into<VTableRef<'a, V>>,
) -> CopyValueRef<'a, V> {
CopyValueRef {
bytes,
type_id,
alignment,
vtable: vtable.into(),
}
}
#[inline]
pub fn downcast<T: CopyElem>(self) -> Option<&'a T> {
self.downcast_with::<T, _, _>(|b| unsafe { Bytes::from_bytes(b.bytes) })
}
#[inline]
pub fn upcast<U: ?Sized + From<V>>(self) -> CopyValueRef<'a, U>
where
V: Clone,
{
CopyValueRef {
bytes: self.bytes,
type_id: self.type_id,
alignment: self.alignment,
vtable: VTableRef::Box(Box::new(U::from(self.vtable.take()))),
}
}
#[inline]
pub fn upcast_ref<U: ?Sized + From<V>>(&self) -> CopyValueRef<U>
where
V: Clone,
{
let vtable = self.vtable.as_ref();
CopyValueRef {
bytes: self.bytes,
type_id: self.type_id,
alignment: self.alignment,
vtable: VTableRef::Box(Box::new(U::from((*vtable).clone()))),
}
}
}
pub struct CopyValueMut<'a, V = ()>
where
V: ?Sized,
{
pub(crate) bytes: &'a mut [MaybeUninit<u8>],
pub(crate) type_id: TypeId,
pub(crate) alignment: usize,
pub(crate) vtable: VTableRef<'a, V>,
}
impl<'a, V> CopyValueMut<'a, V> {
#[inline]
pub fn new<T: CopyElem>(typed: &'a mut T) -> CopyValueMut<'a, V>
where
V: VTable<T>,
{
CopyValueMut {
bytes: typed.as_bytes_mut(),
type_id: TypeId::of::<T>(),
alignment: std::mem::align_of::<T>(),
vtable: VTableRef::Box(Box::new(V::build_vtable())),
}
}
}
impl<'a, V: ?Sized> CopyValueMut<'a, V> {
impl_value_base!();
#[inline]
pub(crate) unsafe fn from_raw_parts(
bytes: &'a mut [MaybeUninit<u8>],
type_id: TypeId,
alignment: usize,
vtable: impl Into<VTableRef<'a, V>>,
) -> CopyValueMut<'a, V> {
CopyValueMut {
bytes,
type_id,
alignment,
vtable: vtable.into(),
}
}
#[inline]
pub fn copy(self, other: CopyValueRef<'a, V>) -> Option<Self> {
if self.value_type_id() == other.value_type_id() {
self.bytes.copy_from_slice(other.bytes);
Some(self)
} else {
None
}
}
#[inline]
pub fn swap(&mut self, other: &mut CopyValueMut<V>) {
if self.value_type_id() == other.value_type_id() {
self.bytes.swap_with_slice(other.bytes);
assert_eq!(self.alignment, other.alignment);
}
}
#[inline]
pub fn downcast<T: CopyElem>(self) -> Option<&'a mut T> {
self.downcast_with::<T, _, _>(|b| unsafe { Bytes::from_bytes_mut(b.bytes) })
}
#[inline]
pub fn upcast<U: From<V>>(&mut self) -> CopyValueMut<U>
where
V: Clone,
{
let vtable = self.vtable.as_ref();
CopyValueMut {
bytes: self.bytes,
type_id: self.type_id,
alignment: self.alignment,
vtable: VTableRef::Box(Box::new(U::from(vtable.clone()))),
}
}
}
impl<'a, V> From<CopyValueMut<'a, V>> for CopyValueRef<'a, V> {
#[inline]
fn from(v: CopyValueMut<'a, V>) -> CopyValueRef<'a, V> {
CopyValueRef {
bytes: v.bytes,
type_id: v.type_id,
alignment: v.alignment,
vtable: v.vtable,
}
}
}