crossmist/
unsized_builtins.rs

1use crate::{relocation::RelocatablePtr, Deserializer, NonTrivialObject, Object, Serializer};
2use std::io::Result;
3
4#[repr(C)]
5struct DynFatPtr {
6    data: *const (),
7    vtable: *const (),
8}
9
10#[derive(PartialEq)]
11enum TypeClass {
12    Sized,
13    Dyn,
14}
15impl TypeClass {
16    const fn of<T: ?Sized>() -> Self {
17        if std::mem::size_of::<&T>() == std::mem::size_of::<usize>() {
18            Self::Sized
19        } else if std::mem::size_of::<&T>() == std::mem::size_of::<DynFatPtr>() {
20            Self::Dyn
21        } else {
22            panic!(
23                "Unexpected pointer size. You are probably trying to serialize Box<&dyn TraitA + \
24                 TraitB>, which crossmist does not support, because this feature was not present \
25                 in rustc when this crate was published.",
26            );
27        }
28    }
29}
30
31unsafe impl<T: Object + ?Sized> NonTrivialObject for Box<T> {
32    fn serialize_self_non_trivial(&self, s: &mut Serializer) {
33        // Object is only implemented for types that implement NonTrivialObject, which inherits
34        // Sized, and `dyn Trait` where `Trait: Object`. Therefore, the only possible Ts here are
35        // sized types and `dyn Trait`. Slices are handled in another impl block, custom DSTs are
36        // not supported at all.
37
38        if TypeClass::of::<T>() == TypeClass::Dyn {
39            let fat_ptr = unsafe { std::mem::transmute_copy::<&T, DynFatPtr>(&self.as_ref()) };
40            s.serialize(&RelocatablePtr(fat_ptr.vtable));
41        }
42
43        #[cfg(not(feature = "nightly"))]
44        s.serialize(&RelocatablePtr(
45            self.as_ref().deserialize_on_heap_get() as *const ()
46        ));
47
48        self.as_ref().serialize_self(s);
49    }
50
51    unsafe fn deserialize_self_non_trivial(d: &mut Deserializer) -> Result<Self> {
52        let mut pointer: *mut T = match TypeClass::of::<T>() {
53            TypeClass::Sized => std::mem::transmute_copy::<usize, *mut T>(&0usize),
54            TypeClass::Dyn => std::mem::transmute_copy::<DynFatPtr, *mut T>(&DynFatPtr {
55                data: std::ptr::null(),
56                vtable: d.deserialize::<RelocatablePtr<()>>()?.0,
57            }),
58        };
59
60        #[cfg(feature = "nightly")]
61        let pointer_thin_part = pointer.deserialize_on_heap_ptr(d)?;
62        #[cfg(not(feature = "nightly"))]
63        let pointer_thin_part = std::mem::transmute::<
64            RelocatablePtr<()>,
65            unsafe fn(&mut Deserializer) -> Result<*mut ()>,
66        >(d.deserialize::<RelocatablePtr<()>>()?)(d)?;
67
68        (&mut pointer as *mut *mut T as *mut *mut ()).write(pointer_thin_part);
69
70        Ok(Box::from_raw(pointer))
71    }
72}
73
74unsafe impl<T: Object> NonTrivialObject for Box<[T]> {
75    fn serialize_self_non_trivial(&self, s: &mut Serializer) {
76        s.serialize(&self.len());
77        s.serialize_slice(self.as_ref());
78    }
79    unsafe fn deserialize_self_non_trivial(d: &mut Deserializer) -> Result<Self> {
80        Ok(d.deserialize::<Vec<T>>()?.into_boxed_slice())
81    }
82}