Skip to main content

hermes_simd_core/cow/
rkyv.rs

1//! Zero-copy serialization support for Clone-on-Write SIMD containers using `rkyv`.
2
3use super::SimdCow;
4use crate::align::Alignment;
5use crate::arch::SimdArch;
6use crate::vec::AlignedVec;
7use crate::view::SimdView;
8use rkyv::munge::munge;
9use rkyv::rancor::Fallible;
10use rkyv::ser::{Allocator, Writer};
11use rkyv::{Place, Portable};
12
13/// Archived representation of a `SimdCow` used by `rkyv` zero-copy serialization.
14///
15/// `Portable` and `CheckBytes` are derived rather than asserted: the wrapper is
16/// transparent over `ArchivedVec`, so both properties reduce to the element
17/// type's, and the derive is what enforces that rather than a hand-written
18/// claim.
19#[derive(Portable, rkyv::bytecheck::CheckBytes)]
20#[bytecheck(crate = rkyv::bytecheck)]
21#[repr(transparent)]
22pub struct ArchivedSimdCow<T> {
23    pub(crate) elements: rkyv::vec::ArchivedVec<T>,
24}
25
26/// Resolver type for `SimdCow` serialization.
27pub struct SimdCowResolver {
28    pub(crate) elements_resolver: rkyv::vec::VecResolver,
29}
30
31impl<'a, T, Arch, Align> rkyv::Archive for SimdCow<'a, T, Arch, Align>
32where
33    T: rkyv::Archive,
34    Arch: SimdArch,
35    Align: Alignment,
36{
37    type Archived = ArchivedSimdCow<T::Archived>;
38    type Resolver = SimdCowResolver;
39
40    #[inline]
41    fn resolve(&self, resolver: Self::Resolver, out: Place<Self::Archived>) {
42        // 0.8 projects the field through `Place`, so the offset the 0.7
43        // implementation computed by hand cannot drift from the layout.
44        munge!(let ArchivedSimdCow { elements } = out);
45        rkyv::vec::ArchivedVec::resolve_from_slice(&self[..], resolver.elements_resolver, elements);
46    }
47}
48
49impl<'a, T, Arch, Align, S> rkyv::Serialize<S> for SimdCow<'a, T, Arch, Align>
50where
51    T: rkyv::Serialize<S> + rkyv::Archive,
52    Arch: SimdArch,
53    Align: Alignment,
54    S: Fallible + Allocator + Writer + ?Sized,
55{
56    #[inline]
57    fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
58        let elements_resolver =
59            rkyv::vec::ArchivedVec::serialize_from_slice(&self[..], serializer)?;
60        Ok(SimdCowResolver { elements_resolver })
61    }
62}
63
64// See `ArchivedAlignedVec`: the archived and native element types are distinct
65// in 0.8, so the deserialization target is its own parameter.
66impl<T, U, Arch, Align, D> rkyv::Deserialize<SimdCow<'static, U, Arch, Align>, D>
67    for ArchivedSimdCow<T>
68where
69    T: rkyv::Deserialize<U, D>,
70    Arch: SimdArch,
71    Align: Alignment,
72    D: Fallible + ?Sized,
73{
74    #[inline]
75    fn deserialize(
76        &self,
77        deserializer: &mut D,
78    ) -> Result<SimdCow<'static, U, Arch, Align>, D::Error> {
79        let slice = self.elements.as_slice();
80        let mut v = AlignedVec::with_capacity(slice.len());
81        for x in slice {
82            v.push(x.deserialize(deserializer)?);
83        }
84        Ok(SimdCow::Owned(v))
85    }
86}
87
88impl<T> ArchivedSimdCow<T> {
89    /// Returns the length of the archived vector.
90    #[inline]
91    pub fn len(&self) -> usize {
92        self.elements.len()
93    }
94
95    /// Returns `true` if the archived vector is empty.
96    #[inline]
97    pub fn is_empty(&self) -> bool {
98        self.elements.is_empty()
99    }
100
101    /// Access the archived elements as a slice.
102    #[inline]
103    pub fn as_slice(&self) -> &[T] {
104        self.elements.as_slice()
105    }
106
107    /// Zero-copy conversion of the archived SimdCow to a borrowed SimdCow.
108    ///
109    /// # Safety
110    /// The alignment of the underlying archived memory must satisfy `Align`.
111    #[inline]
112    pub unsafe fn as_borrowed<'a, Arch, Align>(&'a self) -> Option<SimdCow<'a, T, Arch, Align>>
113    where
114        Arch: SimdArch,
115        Align: Alignment,
116    {
117        let slice = self.elements.as_slice();
118        let view = SimdView::new(slice)?;
119        Some(SimdCow::Borrowed(view))
120    }
121}
122
123impl<T> core::ops::Deref for ArchivedSimdCow<T> {
124    type Target = [T];
125
126    #[inline]
127    fn deref(&self) -> &Self::Target {
128        self.elements.as_slice()
129    }
130}