vector_buffers/variants/disk_v2/
backed_archive.rs

1use std::marker::PhantomData;
2#[cfg(test)]
3use std::pin::Pin;
4
5use bytecheck::CheckBytes;
6use rkyv::{
7    archived_root, check_archived_root,
8    ser::{serializers::AllocSerializer, Serializer},
9    validation::validators::DefaultValidator,
10    Archive, Serialize,
11};
12
13use super::ser::{DeserializeError, SerializeError};
14
15/// A batteries-included serializer implementation.
16///
17/// Callers do not need to know or care about this, but it must be public as it is part of the
18/// `BackedArchive` API.
19pub type DefaultSerializer = AllocSerializer<4096>;
20
21/// Backed wrapper for any type that implements [`Archive`][archive].
22///
23/// For any backing store that can provide references to an underlying byte slice of suitable size,
24/// we can deserialize and serialize a type that is archivable. `BackedArchive` provides specific
25/// entrypoints to either deserialize the given type from the backing store, or to serialize a
26/// provided value to the backing store.
27///
28/// Once wrapped, the archived type can be accessed either immutably or mutably.  This provides a
29/// simple mechanism to use a variety of backing stores, such as `Vec<u8>` or a memory-mapped
30/// region.  This can in turn be used to avoid serializing to intermediate buffers when possible.
31///
32/// ## Archived types
33///
34/// Traditionally, (de)serialization frameworks focus on taking some type `T`, and translating it to
35/// and from another format: structured text like JSON, or maybe binary data for efficient
36/// on-the-wire representation, like Protocol Buffers.  `rkyv` works slightly differently, as a
37/// zero-copy (de)serialization framework, by providing a projected type, or "archive", over the
38/// underlying byte representation of `T`.
39///
40/// In general, what this means is that when you derive the correct traits for some type `T`, `rkyv`
41/// generates an `ArchivedT` type that can correctly represent `T` when serialized to disk,
42/// regardless of whether `T` contains primitive types or types holding underlying allocations, like
43/// `Vec<T>`.
44///
45/// Crucially, the archive type -- `ArchivedT` -- can be pointer casted against the underlying bytes
46/// to provide a reference of `ArchivedT`, or even a mutable reference.  This means that we can
47/// access an object that is like our `T`, in a native and ergonomic way, without copying any bytes,
48/// thus zero-copy deserialization.  Building off the ability to get a mutable reference, we can
49/// also expose way to trivially update the underlying bytes through a safe interface, which can
50/// avoid constantly serializing the entire type after changing a single field.
51///
52/// [archive]: rkyv::Archive
53#[derive(Debug)]
54pub struct BackedArchive<B, T> {
55    backing: B,
56    _archive: PhantomData<T>,
57}
58
59impl<B, T> BackedArchive<B, T>
60where
61    B: AsRef<[u8]>,
62    T: Archive,
63{
64    /// Deserializes the archived value from the backing store and wraps it.
65    ///
66    /// # Errors
67    ///
68    /// If the data in the backing store is not valid for `T`, an error variant will be returned.
69    pub fn from_backing(backing: B) -> Result<BackedArchive<B, T>, DeserializeError>
70    where
71        for<'a> T::Archived: CheckBytes<DefaultValidator<'a>>,
72    {
73        // Validate that the input is, well, valid.
74        _ = check_archived_root::<T>(backing.as_ref())?;
75
76        // Now that we know the buffer fits T, we're good to go!
77        Ok(Self {
78            backing,
79            _archive: PhantomData,
80        })
81    }
82
83    /// Gets a reference to the backing store.
84    pub fn get_backing_ref(&self) -> &B {
85        &self.backing
86    }
87
88    /// Gets a reference to the archived value.
89    pub fn get_archive_ref(&self) -> &T::Archived {
90        unsafe { archived_root::<T>(self.backing.as_ref()) }
91    }
92}
93
94impl<B, T> BackedArchive<B, T>
95where
96    B: AsMut<[u8]>,
97    T: Archive,
98{
99    /// Serializes the provided value to the backing store and wraps it.
100    ///
101    /// # Errors
102    ///
103    /// If there is an error during serializing of the value, an error variant will be returned that
104    /// describes the error.  If the backing store is too small to hold the serialized version of
105    /// the value, an error variant will be returned defining the minimum size the backing store
106    /// must be, as well containing the value that failed to get serialized.
107    pub fn from_value(mut backing: B, value: T) -> Result<BackedArchive<B, T>, SerializeError<T>>
108    where
109        T: Serialize<DefaultSerializer>,
110    {
111        // Serialize our value so we can shove it into the backing.
112        let mut serializer = DefaultSerializer::default();
113        _ = serializer
114            .serialize_value(&value)
115            .map_err(|e| SerializeError::FailedToSerialize(e.to_string()))?;
116
117        let src_buf = serializer.into_serializer().into_inner();
118
119        // Now we have to write the serialized version to the backing store.  For obvious reasons,
120        // the backing store needs to be able to hold the entire serialized representation, so we
121        // check for that.  As well, instead of using `archived_root_mut`, we use
122        // `archived_value_mut`, because this lets us relax need the backing store to be sized
123        // _identically_ to the serialized size.
124        let dst_buf = backing.as_mut();
125        if dst_buf.len() < src_buf.len() {
126            return Err(SerializeError::BackingStoreTooSmall(value, src_buf.len()));
127        }
128
129        dst_buf[..src_buf.len()].copy_from_slice(&src_buf);
130
131        Ok(Self {
132            backing,
133            _archive: PhantomData,
134        })
135    }
136
137    /// Gets a reference to the archived value.
138    #[cfg(test)]
139    pub fn get_archive_mut(&mut self) -> Pin<&mut T::Archived> {
140        use rkyv::archived_root_mut;
141
142        let pinned = Pin::new(self.backing.as_mut());
143        unsafe { archived_root_mut::<T>(pinned) }
144    }
145}