#![allow(dead_code)]
use std::any::{Any, TypeId};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::mem::{ManuallyDrop, MaybeUninit};
use std::boxed::Box as Ptr;
use crate::bytes::*;
use crate::traits::*;
use crate::Elem;
#[derive(Debug)]
pub enum Error {
ValueTooLarge,
MismatchedTypes { expected: TypeId, actual: TypeId },
}
impl fmt::Display for Error {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::ValueTooLarge => {
write!(f, "Value could not fit into a single pointer sized word.\nTry constructing a BoxValue instead.")?;
}
Error::MismatchedTypes { expected, actual } => {
writeln!(f, "Trying to assign a value of one type (with TypeId {:?}) to a value of another (with TypeId {:?}).", actual, expected)?;
}
}
Ok(())
}
}
impl std::error::Error for Error {}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Meta<V> {
pub element_size: usize,
pub element_type_id: TypeId,
pub vtable: V,
}
impl<'a, B: GetBytesMut, V: Clone + HasDrop> From<&'a Value<B, V>> for Meta<Ptr<V>> {
#[inline]
fn from(val: &'a Value<B, V>) -> Meta<Ptr<V>> {
Meta {
element_size: val.bytes.get_bytes_ref().len(),
element_type_id: val.type_id,
vtable: Ptr::clone(&val.vtable),
}
}
}
impl<'a, V: HasDrop> From<ValueRef<'a, V>> for Meta<VTableRef<'a, V>> {
#[inline]
fn from(val: ValueRef<'a, V>) -> Meta<VTableRef<'a, V>> {
Meta {
element_size: val.bytes.len(),
element_type_id: val.type_id,
vtable: val.vtable,
}
}
}
impl<'a, V: HasDrop> From<ValueMut<'a, V>> for Meta<VTableRef<'a, V>> {
#[inline]
fn from(val: ValueMut<'a, V>) -> Meta<VTableRef<'a, V>> {
Meta {
element_size: val.bytes.len(),
element_type_id: val.type_id,
vtable: val.vtable,
}
}
}
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 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
}
}
};
}
impl<T: Any> HasDrop for (DropFn, T) {
#[inline]
fn drop_fn(&self) -> &DropFn {
&self.0
}
}
impl<V: HasClone> HasClone for (DropFn, V) {
#[inline]
fn clone_fn(&self) -> &CloneFn {
&self.1.clone_fn()
}
#[inline]
fn clone_from_fn(&self) -> &CloneFromFn {
&self.1.clone_from_fn()
}
#[inline]
fn clone_into_raw_fn(&self) -> &CloneIntoRawFn {
&self.1.clone_into_raw_fn()
}
}
impl<V: HasHash> HasHash for (DropFn, V) {
#[inline]
fn hash_fn(&self) -> &HashFn {
&self.1.hash_fn()
}
}
impl<V: HasPartialEq> HasPartialEq for (DropFn, V) {
#[inline]
fn eq_fn(&self) -> &EqFn {
&self.1.eq_fn()
}
}
impl<V: HasEq> HasEq for (DropFn, V) {}
impl<V: HasDebug> HasDebug for (DropFn, V) {
#[inline]
fn fmt_fn(&self) -> &FmtFn {
&self.1.fmt_fn()
}
}
pub trait GetBytesRef {
fn get_bytes_ref(&self) -> &[MaybeUninit<u8>];
}
pub trait GetBytesMut: GetBytesRef {
fn get_bytes_mut(&mut self) -> &mut [MaybeUninit<u8>];
}
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 GetBytesRef for MaybeUninit<usize> {
#[inline]
fn get_bytes_ref(&self) -> &[MaybeUninit<u8>] {
self.as_bytes()
}
}
impl GetBytesMut for MaybeUninit<usize> {
#[inline]
fn get_bytes_mut(&mut self) -> &mut [MaybeUninit<u8>] {
self.as_bytes_mut()
}
}
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
}
}
pub struct Value<B, V>
where
B: GetBytesMut,
V: ?Sized + HasDrop,
{
pub(crate) bytes: ManuallyDrop<B>,
pub(crate) type_id: TypeId,
pub(crate) vtable: ManuallyDrop<Ptr<V>>,
}
pub type SmallValue<V> = Value<MaybeUninit<usize>, V>;
pub type BoxValue<V> = Value<Box<[MaybeUninit<u8>]>, V>;
impl<V: HasDrop> SmallValue<V> {
#[inline]
pub fn try_new<T: Any + DropBytes>(value: T) -> Option<Value<MaybeUninit<usize>, V>>
where
V: VTable<T>,
{
let val = ManuallyDrop::new(value);
val.try_into_usize().map(|usized_value| Value {
bytes: ManuallyDrop::new(usized_value),
type_id: TypeId::of::<T>(),
vtable: ManuallyDrop::new(Ptr::new(V::build_vtable())),
})
}
#[inline]
pub fn new<T: Any + DropBytes>(value: T) -> Value<MaybeUninit<usize>, V>
where
V: VTable<T>,
{
Self::try_new(value).unwrap()
}
}
impl<V: ?Sized + HasDrop> SmallValue<V> {
#[inline]
pub(crate) unsafe fn from_raw_parts(
bytes: MaybeUninit<usize>,
type_id: TypeId,
vtable: Ptr<V>,
) -> Value<MaybeUninit<usize>, V> {
Value {
bytes: ManuallyDrop::new(bytes),
type_id,
vtable: ManuallyDrop::new(vtable),
}
}
#[inline]
pub fn upcast<U: HasDrop + From<V>>(self) -> SmallValue<U>
where
V: Clone,
{
let mut md = ManuallyDrop::new(self);
let output = Value {
bytes: md.bytes,
type_id: md.type_id,
vtable: ManuallyDrop::new(Ptr::new(U::from((**md.vtable).clone()))),
};
unsafe {
ManuallyDrop::drop(&mut md.vtable);
}
output
}
#[inline]
pub fn into_raw_parts(self) -> (MaybeUninit<usize>, TypeId, Ptr<V>) {
let mut md = ManuallyDrop::new(self);
let vtable = unsafe { ManuallyDrop::take(&mut md.vtable) };
let bytes = unsafe { ManuallyDrop::take(&mut md.bytes) };
(bytes, md.type_id, vtable)
}
}
impl<V: HasDrop> BoxValue<V> {
#[inline]
pub fn new<T: Any + DropBytes>(value: T) -> Value<Box<[MaybeUninit<u8>]>, V>
where
V: VTable<T>,
{
Value {
bytes: ManuallyDrop::new(Bytes::box_into_box_bytes(Box::new(value))),
type_id: TypeId::of::<T>(),
vtable: ManuallyDrop::new(Ptr::new(V::build_vtable())),
}
}
}
impl<V: ?Sized + HasDrop> BoxValue<V> {
#[inline]
pub(crate) unsafe fn from_raw_parts(
bytes: Box<[MaybeUninit<u8>]>,
type_id: TypeId,
vtable: Ptr<V>,
) -> Value<Box<[MaybeUninit<u8>]>, V> {
Value {
bytes: ManuallyDrop::new(bytes),
type_id,
vtable: ManuallyDrop::new(vtable),
}
}
#[inline]
pub fn upcast<U: HasDrop + From<V>>(self) -> BoxValue<U>
where
V: Clone,
{
let mut md = ManuallyDrop::new(self);
let output = Value {
bytes: ManuallyDrop::new(unsafe { ManuallyDrop::take(&mut md.bytes) }),
type_id: md.type_id,
vtable: ManuallyDrop::new(Ptr::new(U::from((**md.vtable).clone()))),
};
unsafe {
ManuallyDrop::drop(&mut md.vtable);
}
output
}
#[inline]
pub fn into_raw_parts(self) -> (Box<[MaybeUninit<u8>]>, TypeId, Ptr<V>) {
let mut md = ManuallyDrop::new(self);
let vtable = unsafe { ManuallyDrop::take(&mut md.vtable) };
let bytes = unsafe { ManuallyDrop::take(&mut md.bytes) };
(bytes, md.type_id, vtable)
}
}
impl<B: GetBytesMut, V: ?Sized + HasDrop> Value<B, V> {
#[inline]
pub fn as_ref(&self) -> ValueRef<V> {
ValueRef {
bytes: self.bytes.get_bytes_ref(),
type_id: self.type_id,
vtable: VTableRef::Ref(&self.vtable),
}
}
#[inline]
pub fn as_mut(&mut self) -> ValueMut<V> {
ValueMut {
bytes: self.bytes.get_bytes_mut(),
type_id: self.type_id,
vtable: VTableRef::Ref(&self.vtable),
}
}
}
unsafe impl<B: GetBytesMut, V: ?Sized + HasDrop + HasSend> Send for Value<B, V> {}
unsafe impl<B: GetBytesMut, V: ?Sized + HasDrop + HasSync> Sync for Value<B, V> {}
impl<B: GetBytesMut, V: ?Sized + HasDebug + HasDrop> fmt::Debug for Value<B, V> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
unsafe { self.vtable.fmt_fn()(self.bytes.get_bytes_ref(), f) }
}
}
impl<V: ?Sized + Clone + HasClone + HasDrop> Clone for Value<MaybeUninit<usize>, V> {
#[inline]
fn clone(&self) -> Value<MaybeUninit<usize>, V> {
self.as_ref().clone_small_value()
}
}
impl<V: ?Sized + Clone + HasClone + HasDrop> Clone for Value<Box<[MaybeUninit<u8>]>, V> {
#[inline]
fn clone(&self) -> Value<Box<[MaybeUninit<u8>]>, V> {
self.as_ref().clone_value()
}
}
impl<B: GetBytesMut, V: ?Sized + HasDrop> Drop for Value<B, V> {
#[inline]
fn drop(&mut self) {
unsafe {
self.vtable.drop_fn()(self.bytes.get_bytes_mut());
ManuallyDrop::drop(&mut self.bytes);
ManuallyDrop::drop(&mut self.vtable);
}
}
}
impl<B: GetBytesMut, V: ?Sized + HasDrop + HasPartialEq> PartialEq for Value<B, V> {
#[inline]
fn eq(&self, other: &Self) -> bool {
assert_eq!(
self.type_id, other.type_id,
"Comparing values of different types is forbidden"
);
unsafe { self.vtable.eq_fn()(self.bytes.get_bytes_ref(), other.bytes.get_bytes_ref()) }
}
}
impl<B: GetBytesMut, V: ?Sized + HasDrop + HasPartialEq> Eq for Value<B, V> {}
impl<B: GetBytesMut, V: ?Sized + HasDrop + HasHash> Hash for Value<B, V> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
unsafe {
self.vtable.hash_fn()(self.bytes.get_bytes_ref(), state);
}
}
}
pub trait VTable<T> {
fn build_vtable() -> Self;
}
impl<T: Copy> VTable<T> for () {
#[inline]
fn build_vtable() -> Self {}
}
impl<T: DropBytes, V: VTable<T>> VTable<T> for (DropFn, V) {
#[inline]
fn build_vtable() -> Self {
(T::drop_bytes, V::build_vtable())
}
}
impl<B: GetBytesMut, V: ?Sized + HasDrop> Value<B, V> {
impl_value_base!();
}
impl<V: ?Sized + HasDrop> Value<Box<[MaybeUninit<u8>]>, V> {
#[inline]
pub fn downcast<T: 'static>(self) -> Option<Box<T>> {
let mut s = ManuallyDrop::new(self);
let output = if s.is::<T>() {
Some(unsafe { Bytes::box_from_box_bytes(ManuallyDrop::take(&mut s.bytes)) })
} else {
None
};
unsafe {
ManuallyDrop::drop(&mut s.vtable);
}
output
}
}
impl<V: ?Sized + HasDrop> Value<MaybeUninit<usize>, V> {
#[inline]
pub fn downcast<T: 'static>(self) -> Option<T> {
let mut s = ManuallyDrop::new(self);
let output = if s.is::<T>() {
unsafe { Bytes::try_from_usize(ManuallyDrop::take(&mut s.bytes)) }
} else {
None
};
unsafe {
ManuallyDrop::drop(&mut s.vtable);
}
output
}
}
#[derive(Clone, Debug)]
pub enum VTableRef<'a, V>
where
V: ?Sized,
{
Ref(&'a V),
Box(Box<V>),
#[cfg(feature = "shared-vtables")]
Rc(Rc<V>),
}
impl<'a, V: Clone + ?Sized> VTableRef<'a, V> {
#[inline]
pub fn take(self) -> V {
match self {
VTableRef::Ref(v) => v.clone(),
VTableRef::Box(v) => *v,
#[cfg(feature = "shared-vtables")]
VTableRef::Rc(v) => Rc::try_unwrap(v).unwrap_or_else(|v| (*v).clone()),
}
}
#[inline]
pub fn into_owned(self) -> Ptr<V> {
match self {
VTableRef::Ref(v) => Ptr::new(v.clone()),
VTableRef::Box(v) => v,
#[cfg(feature = "shared-vtables")]
VTableRef::Rc(v) => Rc::clone(&v),
}
}
}
impl<'a, V: ?Sized> std::ops::Deref for VTableRef<'a, V> {
type Target = V;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}
impl<'a, V: ?Sized> From<&'a V> for VTableRef<'a, V> {
#[inline]
fn from(v: &'a V) -> VTableRef<'a, V> {
VTableRef::Ref(v)
}
}
impl<'a, V: ?Sized> From<Box<V>> for VTableRef<'a, V> {
#[inline]
fn from(v: Box<V>) -> VTableRef<'a, V> {
VTableRef::Box(v)
}
}
#[cfg(feature = "shared-vtables")]
impl<'a, V: ?Sized> From<Ptr<V>> for VTableRef<'a, V> {
#[inline]
fn from(v: Ptr<V>) -> VTableRef<'a, V> {
VTableRef::Rc(v)
}
}
impl<'a, V: ?Sized> AsRef<V> for VTableRef<'a, V> {
#[inline]
fn as_ref(&self) -> &V {
match self {
VTableRef::Ref(v) => v,
VTableRef::Box(v) => &*v,
#[cfg(feature = "shared-vtables")]
VTableRef::Rc(v) => &*v,
}
}
}
#[derive(Clone)]
pub struct ValueRef<'a, V>
where
V: ?Sized + HasDrop,
{
pub(crate) bytes: &'a [MaybeUninit<u8>],
pub(crate) type_id: TypeId,
pub(crate) vtable: VTableRef<'a, V>,
}
unsafe impl<'a, V: ?Sized + HasDrop + HasSend> Send for ValueRef<'a, V> {}
unsafe impl<'a, V: ?Sized + HasDrop + HasSync> Sync for ValueRef<'a, V> {}
impl<'a, V: ?Sized + HasHash + HasDrop> Hash for ValueRef<'a, V> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
unsafe {
self.vtable.as_ref().hash_fn()(self.bytes.get_bytes_ref(), state);
}
}
}
impl<'a, V: ?Sized + HasDebug + HasDrop> fmt::Debug for ValueRef<'a, V> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
unsafe { self.vtable.as_ref().fmt_fn()(self.bytes.get_bytes_ref(), f) }
}
}
impl<'a, V: ?Sized + HasPartialEq + HasDrop> PartialEq for ValueRef<'a, V> {
#[inline]
fn eq(&self, other: &Self) -> bool {
assert_eq!(
self.type_id, other.type_id,
"Comparing values of different types is forbidden"
);
unsafe {
self.vtable.as_ref().eq_fn()(self.bytes.get_bytes_ref(), other.bytes.get_bytes_ref())
}
}
}
impl<'a, V: ?Sized + HasEq + HasDrop> Eq for ValueRef<'a, V> {}
impl<'a, V: HasDrop> ValueRef<'a, V> {
#[inline]
pub fn new<T: Any + DropBytes>(typed: &'a T) -> ValueRef<'a, V>
where
V: VTable<T>,
{
ValueRef {
bytes: typed.as_bytes(),
type_id: TypeId::of::<T>(),
vtable: VTableRef::Box(Box::new(V::build_vtable())),
}
}
}
impl<'a, B: GetBytesMut, V> From<&'a Value<B, V>> for ValueRef<'a, V>
where
B: GetBytesRef,
V: ?Sized + Clone + HasDrop,
{
fn from(val: &'a Value<B, V>) -> Self {
ValueRef {
bytes: val.bytes.get_bytes_ref(),
type_id: val.type_id,
vtable: Ptr::clone(&val.vtable).into(),
}
}
}
impl<'a, V: ?Sized + HasDrop> ValueRef<'a, V> {
impl_value_base!();
#[inline]
pub(crate) unsafe fn from_raw_parts(
bytes: &'a [MaybeUninit<u8>],
type_id: TypeId,
vtable: impl Into<VTableRef<'a, V>>,
) -> ValueRef<'a, V> {
ValueRef {
bytes,
type_id,
vtable: vtable.into(),
}
}
#[inline]
pub fn clone_value(&self) -> Value<Box<[MaybeUninit<u8>]>, V>
where
V: HasClone + Clone,
{
Value {
bytes: ManuallyDrop::new(unsafe { self.vtable.as_ref().clone_fn()(&self.bytes) }),
type_id: self.type_id,
vtable: ManuallyDrop::new(Ptr::from(self.vtable.as_ref().clone())),
}
}
#[inline]
pub fn clone_small_value(&self) -> Value<MaybeUninit<usize>, V>
where
V: HasClone + Clone,
{
let mut bytes = MaybeUninit::uninit();
unsafe {
self.vtable.clone_into_raw_fn()(self.bytes.get_bytes_ref(), bytes.as_bytes_mut());
}
Value {
bytes: ManuallyDrop::new(bytes),
type_id: self.type_id,
vtable: ManuallyDrop::new(Ptr::from(self.vtable.as_ref().clone())),
}
}
#[inline]
pub fn downcast<T: 'static>(self) -> Option<&'a T> {
self.downcast_with::<T, _, _>(|b| unsafe { Bytes::from_bytes(b.bytes) })
}
#[inline]
pub fn upcast<U: ?Sized + HasDrop + From<V>>(self) -> ValueRef<'a, U>
where
V: Clone,
{
ValueRef {
bytes: self.bytes,
type_id: self.type_id,
vtable: VTableRef::Box(Box::new(U::from(self.vtable.take()))),
}
}
#[inline]
pub fn upcast_ref<U: ?Sized + HasDrop + From<V>>(&self) -> ValueRef<U>
where
V: Clone,
{
let vtable = self.vtable.as_ref();
ValueRef {
bytes: self.bytes,
type_id: self.type_id,
vtable: VTableRef::Box(Box::new(U::from((*vtable).clone()))),
}
}
#[inline]
pub fn reborrow(&self) -> ValueRef<V> {
ValueRef {
bytes: &*self.bytes,
type_id: self.type_id,
vtable: VTableRef::Ref(self.vtable.as_ref()),
}
}
}
pub struct ValueMut<'a, V>
where
V: ?Sized + HasDrop,
{
pub(crate) bytes: &'a mut [MaybeUninit<u8>],
pub(crate) type_id: TypeId,
pub(crate) vtable: VTableRef<'a, V>,
}
impl<'a, V: ?Sized + HasDebug + HasDrop> fmt::Debug for ValueMut<'a, V> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
unsafe { self.vtable.as_ref().fmt_fn()(self.bytes, f) }
}
}
impl<'a, V: ?Sized + HasPartialEq + HasDrop> PartialEq for ValueMut<'a, V> {
#[inline]
fn eq(&self, other: &Self) -> bool {
assert_eq!(
self.type_id, other.type_id,
"Comparing values of different types is forbidden"
);
unsafe {
self.vtable.as_ref().eq_fn()(self.bytes.get_bytes_ref(), other.bytes.get_bytes_ref())
}
}
}
impl<'a, V: ?Sized + HasEq + HasDrop> Eq for ValueMut<'a, V> {}
impl<'a, V: HasDrop> ValueMut<'a, V> {
#[inline]
pub fn new<T: Any>(typed: &'a mut T) -> ValueMut<'a, V>
where
V: VTable<T>,
{
ValueMut {
bytes: typed.as_bytes_mut(),
type_id: TypeId::of::<T>(),
vtable: VTableRef::Box(Box::new(V::build_vtable())),
}
}
}
impl<'a, V: ?Sized + HasDrop> ValueMut<'a, V> {
impl_value_base!();
#[inline]
pub fn swap<'b>(&mut self, other: &mut ValueMut<'b, V>) {
if self.value_type_id() == other.value_type_id() {
self.bytes.swap_with_slice(other.bytes);
}
}
pub fn assign<B: GetBytesMut>(&mut self, mut value: Value<B, V>) {
self.swap(&mut value.as_mut())
}
#[inline]
pub fn clone_from_other<'b>(&mut self, other: impl Into<ValueRef<'b, V>>) -> Result<(), Error>
where
V: HasClone + 'b,
{
let other = other.into();
if self.value_type_id() == other.value_type_id() {
unsafe {
self.vtable.as_ref().clone_from_fn()(&mut self.bytes, other.bytes);
}
Ok(())
} else {
Err(Error::MismatchedTypes {
expected: self.value_type_id(),
actual: other.value_type_id(),
})
}
}
#[inline]
pub fn clone_value(&self) -> Value<Box<[MaybeUninit<u8>]>, V>
where
V: HasClone + Clone,
{
Value {
bytes: ManuallyDrop::new(unsafe { self.vtable.as_ref().clone_fn()(&self.bytes) }),
type_id: self.type_id,
vtable: ManuallyDrop::new(Ptr::from(self.vtable.as_ref().clone())),
}
}
#[inline]
pub fn clone_small_value(&self) -> Value<MaybeUninit<usize>, V>
where
V: HasClone + Clone,
{
let mut bytes = MaybeUninit::uninit();
unsafe {
self.vtable.clone_into_raw_fn()(self.bytes.get_bytes_ref(), bytes.as_bytes_mut());
}
Value {
bytes: ManuallyDrop::new(bytes),
type_id: self.type_id,
vtable: ManuallyDrop::new(Ptr::from(self.vtable.as_ref().clone())),
}
}
#[inline]
pub(crate) unsafe fn from_raw_parts(
bytes: &'a mut [MaybeUninit<u8>],
type_id: TypeId,
vtable: impl Into<VTableRef<'a, V>>,
) -> ValueMut<'a, V> {
ValueMut {
bytes,
type_id,
vtable: vtable.into(),
}
}
#[inline]
pub fn downcast<T: 'static>(self) -> Option<&'a mut T> {
self.downcast_with::<T, _, _>(|b| unsafe { Bytes::from_bytes_mut(b.bytes) })
}
#[inline]
pub fn upcast<U: ?Sized + HasDrop + From<V>>(self) -> ValueMut<'a, U>
where
V: Clone,
{
ValueMut {
bytes: self.bytes,
type_id: self.type_id,
vtable: VTableRef::Box(Box::new(U::from(self.vtable.take()))),
}
}
#[inline]
pub fn upcast_mut<U: ?Sized + HasDrop + From<V>>(&mut self) -> ValueMut<U>
where
V: Clone,
{
ValueMut {
bytes: self.bytes,
type_id: self.type_id,
vtable: VTableRef::Box(Box::new(U::from((*self.vtable).clone()))),
}
}
#[inline]
pub fn reborrow(&self) -> ValueRef<V> {
ValueRef {
bytes: self.bytes,
type_id: self.type_id,
vtable: VTableRef::Ref(self.vtable.as_ref()),
}
}
#[inline]
pub fn reborrow_mut(&mut self) -> ValueMut<V> {
ValueMut {
bytes: self.bytes,
type_id: self.type_id,
vtable: VTableRef::Ref(self.vtable.as_ref()),
}
}
}
#[derive(Clone, Debug)]
pub struct CopyValueRef<'a, V = ()>
where
V: ?Sized,
{
pub(crate) bytes: &'a [MaybeUninit<u8>],
pub(crate) type_id: TypeId,
pub(crate) vtable: VTableRef<'a, V>,
}
impl<'a, V> CopyValueRef<'a, V> {
#[inline]
pub fn new<T: Elem>(typed: &'a T) -> CopyValueRef<'a, V>
where
V: VTable<T>,
{
CopyValueRef {
bytes: typed.as_bytes(),
type_id: TypeId::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,
vtable: impl Into<VTableRef<'a, V>>,
) -> CopyValueRef<'a, V> {
CopyValueRef {
bytes,
type_id,
vtable: vtable.into(),
}
}
#[inline]
pub fn downcast<T: Elem>(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,
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,
vtable: VTableRef::Box(Box::new(U::from((*vtable).clone()))),
}
}
}
#[derive(Debug)]
pub struct CopyValueMut<'a, V = ()>
where
V: ?Sized,
{
pub(crate) bytes: &'a mut [MaybeUninit<u8>],
pub(crate) type_id: TypeId,
pub(crate) vtable: VTableRef<'a, V>,
}
impl<'a, V> CopyValueMut<'a, V> {
#[inline]
pub fn new<T: Elem>(typed: &'a mut T) -> CopyValueMut<'a, V>
where
V: VTable<T>,
{
CopyValueMut {
bytes: typed.as_bytes_mut(),
type_id: TypeId::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,
vtable: impl Into<VTableRef<'a, V>>,
) -> CopyValueMut<'a, V> {
CopyValueMut {
bytes,
type_id,
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(&mut other.bytes);
std::mem::swap(&mut self.type_id, &mut other.type_id);
}
}
#[inline]
pub fn downcast<T: Elem>(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,
vtable: VTableRef::Box(Box::new(U::from(vtable.clone()))),
}
}
}
impl<'a, V: HasDrop> From<ValueMut<'a, V>> for ValueRef<'a, V> {
#[inline]
fn from(v: ValueMut<'a, V>) -> ValueRef<'a, V> {
ValueRef {
bytes: v.bytes,
type_id: v.type_id,
vtable: v.vtable,
}
}
}
impl<'a, V: HasDrop> 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,
vtable: v.vtable,
}
}
}
unsafe fn drop_copy(_: &mut [MaybeUninit<u8>]) {}
impl<'a, V: Any + Clone> From<CopyValueMut<'a, V>> for ValueMut<'a, (DropFn, V)> {
#[inline]
fn from(v: CopyValueMut<'a, V>) -> ValueMut<'a, (DropFn, V)> {
ValueMut {
bytes: v.bytes,
type_id: v.type_id,
vtable: VTableRef::Box(Box::new((drop_copy, v.vtable.take()))),
}
}
}
impl<'a, V: Any + Clone> From<CopyValueRef<'a, V>> for ValueRef<'a, (DropFn, V)> {
#[inline]
fn from(v: CopyValueRef<'a, V>) -> ValueRef<'a, (DropFn, V)> {
ValueRef {
bytes: v.bytes,
type_id: v.type_id,
vtable: VTableRef::Box(Box::new((drop_copy, v.vtable.take()))),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::dync_trait;
use std::rc::Rc;
#[dync_trait(dync_crate_name = "crate")]
pub trait Val: Clone + PartialEq + Eq + std::hash::Hash + std::fmt::Debug + 'static {}
impl<T> Val for T where T: Clone + PartialEq + Eq + std::hash::Hash + std::fmt::Debug + 'static {}
#[test]
#[should_panic]
fn forbidden_value_compare() {
let a = BoxValue::<ValVTable>::new(Rc::new("Hello"));
let b = BoxValue::<ValVTable>::new(Rc::new(String::from("Hello")));
assert_eq!(a, b);
}
#[test]
#[should_panic]
fn forbidden_value_ref_compare() {
let a = BoxValue::<ValVTable>::new(Rc::new("Hello"));
let b = BoxValue::<ValVTable>::new(Rc::new(String::from("Hello")));
assert_eq!(a.as_ref(), b.as_ref());
}
#[test]
#[should_panic]
fn forbidden_value_mut_compare() {
let mut a = BoxValue::<ValVTable>::new(Rc::new("Hello"));
let mut b = BoxValue::<ValVTable>::new(Rc::new(String::from("Hello")));
assert_eq!(a.as_mut(), b.as_mut());
}
#[test]
fn value_equality() {
let a = Rc::new(String::from("Hello"));
let b = Rc::new(String::from("Hello"));
assert_eq!(&a, &b);
let a = BoxValue::<ValVTable>::new(Rc::new(String::from("Hello")));
let b = BoxValue::<ValVTable>::new(Rc::new(String::from("Hello")));
let c = b.clone();
let c_rc = b.clone().downcast::<Rc<String>>().unwrap();
let d = BoxValue::<ValVTable>::new(Rc::clone(&*c_rc));
assert_eq!(&a, &b);
assert_eq!(&a, &c);
assert_eq!(&a, &d);
}
#[test]
fn clone_test() {
let val = BoxValue::<ValVTable>::new(Rc::new(1u8));
assert_eq!(&val, &val.clone());
}
#[test]
fn clone_small_test() {
let val = SmallValue::<ValVTable>::new(Rc::new(1u8));
assert_eq!(&val, &val.clone());
}
}