dync/
vtable.rs

1// At the time of this writing, there is no evidence that there is a significant benefit in sharing
2// vtables via Rc or Arc, but to make potential future refactoring easier we use the Ptr alias.
3use std::boxed::Box as Ptr;
4
5/// `VTable` defines a type that represents a virtual function table for some type `T`.
6///
7/// `T` is different than a type that can be turned into a trait object like `Box<dyn Any>`
8/// because a `VTable` effectively decouples the type's behaviour from the data it contains.
9///
10/// This mechanism allows the virtual function table to be attached to a homogeneous container, to
11/// prevent storing duplicates of these tables for each type instance stored in the container.
12///
13/// This is precisely how it is used to build `VecDyn<V>`, which is generic over the virtual table
14/// rather than the type itself.
15pub trait VTable<T> {
16    fn build_vtable() -> Self;
17}
18
19impl<T: Copy> VTable<T> for () {
20    #[inline]
21    fn build_vtable() -> Self {}
22}
23
24#[cfg(feature = "traits")]
25impl<T: crate::traits::DropBytes, V: VTable<T>> VTable<T> for (crate::traits::DropFn, V) {
26    #[inline]
27    fn build_vtable() -> Self {
28        (T::drop_bytes, V::build_vtable())
29    }
30}
31
32/// A VTable reference type.
33///
34/// Note we always need Drop because it's possible to clone ValueRef's contents, which need to know
35/// how to drop themselves.
36#[derive(Clone, Debug, PartialEq)]
37pub enum VTableRef<'a, V>
38where
39    V: ?Sized,
40{
41    Ref(&'a V),
42    Box(Box<V>),
43    //Rc(Rc<V>),
44}
45
46impl<'a, V: Clone + ?Sized> VTableRef<'a, V> {
47    #[inline]
48    pub fn take(self) -> V {
49        match self {
50            VTableRef::Ref(v) => v.clone(),
51            VTableRef::Box(v) => *v,
52            //VTableRef::Rc(v) => Rc::try_unwrap(v).unwrap_or_else(|v| (*v).clone()),
53        }
54    }
55
56    #[inline]
57    pub fn into_owned(self) -> Ptr<V> {
58        match self {
59            VTableRef::Ref(v) => Ptr::new(v.clone()),
60            VTableRef::Box(v) => v,
61            //VTableRef::Rc(v) => Rc::clone(&v),
62        }
63    }
64}
65
66impl<'a, V: ?Sized> std::ops::Deref for VTableRef<'a, V> {
67    type Target = V;
68    #[inline]
69    fn deref(&self) -> &Self::Target {
70        self.as_ref()
71    }
72}
73
74impl<'a, V: ?Sized> From<&'a V> for VTableRef<'a, V> {
75    #[inline]
76    fn from(v: &'a V) -> VTableRef<'a, V> {
77        VTableRef::Ref(v)
78    }
79}
80
81impl<'a, V: ?Sized> From<Box<V>> for VTableRef<'a, V> {
82    #[inline]
83    fn from(v: Box<V>) -> VTableRef<'a, V> {
84        VTableRef::Box(v)
85    }
86}
87
88// impl<'a, V: ?Sized> From<Ptr<V>> for VTableRef<'a, V> {
89//     #[inline]
90//     fn from(v: Ptr<V>) -> VTableRef<'a, V> {
91//         VTableRef::Rc(v)
92//     }
93// }
94
95impl<'a, V: ?Sized> AsRef<V> for VTableRef<'a, V> {
96    #[inline]
97    fn as_ref(&self) -> &V {
98        match self {
99            VTableRef::Ref(v) => v,
100            VTableRef::Box(v) => &*v,
101            // VTableRef::Rc(v) => &*v,
102        }
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109
110    #[test]
111    fn box_vtable() {
112        let v = Box::new(());
113        let from_box = VTableRef::from(v.clone());
114        let box_vtable = VTableRef::Box(v);
115        assert_eq!(&from_box, &box_vtable);
116
117        assert_eq!(from_box.into_owned(), Box::new(()));
118        assert_eq!(box_vtable.take(), ());
119    }
120}