rkyv/api/mod.rs
1//! APIs for producing and using archived data.
2//!
3//! # Accessing byte slices
4//!
5//! The safety requirements for accessing a byte slice will often state that a
6//! byte slice must "represent a valid archived type". The specific validity
7//! requirements may vary widely depending on the types being accessed, and so
8//! in general the only way to guarantee that this call is safe is to have
9//! previously validated the byte slice.
10//!
11//! Using techniques such as cryptographic signing can provide a more performant
12//! way to verify data integrity from trusted sources.
13//!
14//! It is generally safe to assume that unchanged and properly-aligned
15//! serialized bytes are always safe to access without validation. By contrast,
16//! bytes from a potentially-malicious source should always be validated prior
17//! to access.
18
19#[cfg(feature = "bytecheck")]
20mod checked;
21#[cfg(feature = "alloc")]
22pub mod high;
23pub mod low;
24#[cfg(test)]
25pub mod test;
26
27use core::mem::size_of;
28
29use rancor::Strategy;
30
31#[cfg(feature = "bytecheck")]
32pub use self::checked::*;
33use crate::{seal::Seal, ser::Writer, Deserialize, Portable, SerializeUnsized};
34
35#[cfg(debug_assertions)]
36fn sanity_check_buffer<T: Portable>(ptr: *const u8, pos: usize, size: usize) {
37 use core::mem::{align_of, size_of};
38
39 let root_size = size_of::<T>();
40 let min_size = pos + root_size;
41 debug_assert!(
42 min_size <= size,
43 concat!(
44 "buffer too small, expected at least {} bytes but found {} bytes\n",
45 "help: the root type at offset {} requires at least {} bytes",
46 ),
47 min_size,
48 size,
49 pos,
50 root_size,
51 );
52 let expect_align = align_of::<T>();
53 let actual_align = (ptr as usize).wrapping_add(pos) & (expect_align - 1);
54 debug_assert_eq!(
55 actual_align,
56 0,
57 concat!(
58 "unaligned buffer, expected alignment {} but found alignment {}\n",
59 "help: rkyv requires byte buffers to be aligned to access the \
60 data inside.\n",
61 " Using an AlignedVec or manually aligning your data with \
62 `#[align(...)]` may resolve this issue.\n",
63 " Alternatively, you may enable the `unaligned` feature to \
64 relax the alignment requirements for your archived data.\n",
65 " `unaligned` is a format control feature, and enabling it \
66 may change the format of your serialized data)",
67 ),
68 expect_align,
69 1 << actual_align.trailing_zeros()
70 );
71}
72
73/// Return the position of the root within a buffer of `length` bytes.
74///
75/// Most accessing functions have a variant which automatically calculates this
76/// value for you. For example, prefer to call [`access_unchecked`] over
77/// [`access_pos_unchecked`].
78///
79/// The root position of a buffer is calculated by subtracing the size of the
80/// root object from the end of the buffer. If the buffer size is too small to
81/// accomodate a root of the given type, then this function will return zero.
82///
83/// # Example
84///
85/// ```
86/// use rkyv::{api::root_position, Archive};
87///
88/// #[derive(Archive)]
89/// pub struct MyData {
90/// inner: u32,
91/// }
92///
93/// assert_eq!(size_of::<ArchivedMyData>(), 4);
94///
95/// // This is too small, and so returns 0
96/// assert_eq!(root_position::<ArchivedMyData>(3), 0);
97/// assert_eq!(root_position::<ArchivedMyData>(4), 0);
98/// assert_eq!(root_position::<ArchivedMyData>(5), 1);
99/// ```
100pub fn root_position<T: Portable>(size: usize) -> usize {
101 size.saturating_sub(size_of::<T>())
102}
103
104/// Access a byte slice with a given root position.
105///
106/// Most of the time, the root position should be calculated using the root type
107/// and size of the buffer. Prefer [`access_unchecked`] whenever possible.
108///
109/// While the root of the archived data is located at the given position, the
110/// reachable data may be located throughout the byte slice.
111///
112/// This function does not check that the bytes are valid to access. Use
113/// [`access_pos`](high::access_pos) to safely access the buffer using
114/// validation.
115///
116/// # Safety
117///
118/// The byte slice must represent a valid archived type when accessed with the
119/// given root position. See the [module docs](crate::api) for more information.
120///
121/// # Example
122///
123/// ```
124/// use rkyv::{
125/// api::{access_pos_unchecked, root_position},
126/// rancor::Error,
127/// to_bytes, Archive, Deserialize, Serialize,
128/// };
129///
130/// #[derive(Archive, Serialize, Deserialize)]
131/// struct Example {
132/// name: String,
133/// value: i32,
134/// }
135///
136/// let value = Example {
137/// name: "pi".to_string(),
138/// value: 31415926,
139/// };
140///
141/// let bytes = to_bytes::<Error>(&value).unwrap();
142///
143/// let archived = unsafe {
144/// access_pos_unchecked::<ArchivedExample>(
145/// &*bytes,
146/// root_position::<ArchivedExample>(bytes.len()),
147/// )
148/// };
149/// assert_eq!(archived.name, "pi");
150/// assert_eq!(archived.value, 31415926);
151/// ```
152pub unsafe fn access_pos_unchecked<T: Portable>(
153 bytes: &[u8],
154 pos: usize,
155) -> &T {
156 #[cfg(debug_assertions)]
157 sanity_check_buffer::<T>(bytes.as_ptr(), pos, bytes.len());
158
159 // SAFETY: The caller has guaranteed that a valid `T` is located at `pos` in
160 // the byte slice.
161 unsafe { &*bytes.as_ptr().add(pos).cast() }
162}
163
164/// Mutably access a byte slice with a given root position.
165///
166/// Most of the time, the root position should be calculated using the root type
167/// and size of the buffer. Prefer [`access_unchecked_mut`] whenever possible.
168///
169/// While the root of the archived data is located at the given position, the
170/// reachable data may be located throughout the byte slice.
171///
172/// This function does not check that the bytes are valid to access. Use
173/// [`access_pos_mut`](high::access_pos_mut) to safely access the buffer using
174/// validation.
175///
176/// The returned `Seal` restricts the mutating operations that may be safely
177/// performed on the returned reference. See [`Seal`] for more information.
178///
179/// # Safety
180///
181/// The byte slice must represent a valid archived type when accessed with the
182/// given root position. See the [module docs](crate::api) for more information.
183///
184/// # Example
185///
186/// ```
187/// use rkyv::{
188/// to_bytes, api::{root_position, access_pos_unchecked_mut}, util::Align,
189/// Archive, Serialize, Deserialize, munge::munge, rancor::Error,
190/// };
191///
192/// #[derive(Archive, Serialize, Deserialize)]
193/// struct Example {
194/// name: String,
195/// value: i32,
196/// }
197///
198/// let value = Example {
199/// name: "pi".to_string(),
200/// value: 31415926,
201/// };
202///
203/// let mut bytes = to_bytes::<Error>(&value).unwrap();
204/// let root_pos = root_position::<ArchivedExample>(bytes.len());
205///
206/// let mut archived = unsafe {
207/// access_pos_unchecked_mut::<ArchivedExample>(&mut *bytes, root_pos)
208/// };
209/// assert_eq!(archived.name, "pi");
210/// assert_eq!(archived.value, 31415926);
211///
212/// // Because the access is mutable, we can mutate the archived data
213/// munge!(let ArchivedExample { mut value, .. } = archived);
214/// assert_eq!(*value, 31415926);
215/// *value = 12345.into();
216/// assert_eq!(*value, 12345);
217/// ```
218pub unsafe fn access_pos_unchecked_mut<T: Portable>(
219 bytes: &mut [u8],
220 pos: usize,
221) -> Seal<'_, T> {
222 #[cfg(debug_assertions)]
223 sanity_check_buffer::<T>(bytes.as_ptr(), pos, bytes.len());
224
225 // SAFETY: The caller has guaranteed that the data at the given position
226 // passes validation when passed to `access_pos_mut`.
227 unsafe { Seal::new(&mut *bytes.as_mut_ptr().add(pos).cast()) }
228}
229
230/// Access a byte slice.
231///
232/// This function does not check that the bytes are valid to access. Use
233/// [`access`](high::access) to safely access the buffer using validation.
234///
235/// # Safety
236///
237/// The byte slice must represent a valid archived type when accessed at the
238/// default root position. See the [module docs](crate::api) for more
239/// information.
240///
241/// # Example
242///
243/// ```
244/// use rkyv::{
245/// access_unchecked, rancor::Error, to_bytes, Archive, Deserialize,
246/// Serialize,
247/// };
248///
249/// #[derive(Archive, Serialize, Deserialize)]
250/// struct Example {
251/// name: String,
252/// value: i32,
253/// }
254///
255/// let value = Example {
256/// name: "pi".to_string(),
257/// value: 31415926,
258/// };
259///
260/// let bytes = to_bytes::<Error>(&value).unwrap();
261///
262/// let archived = unsafe { access_unchecked::<ArchivedExample>(&*bytes) };
263/// assert_eq!(archived.name, "pi");
264/// assert_eq!(archived.value, 31415926);
265/// ```
266pub unsafe fn access_unchecked<T: Portable>(bytes: &[u8]) -> &T {
267 // SAFETY: The caller has guaranteed that a valid `T` is located at the root
268 // position in the byte slice.
269 unsafe { access_pos_unchecked::<T>(bytes, root_position::<T>(bytes.len())) }
270}
271
272/// Mutably access a byte slice.
273///
274/// This function does not check that the bytes are valid to access. Use
275/// [`access_mut`](high::access_mut) to safely access the buffer using
276/// validation.
277///
278/// # Safety
279///
280/// The byte slice must represent a valid archived type when accessed at the
281/// default root position. See the [module docs](crate::api) for more
282/// information.
283///
284/// # Example
285///
286/// ```
287/// use rkyv::{
288/// to_bytes, access_unchecked_mut, util::Align, Archive,
289/// munge::munge, Serialize, Deserialize, rancor::Error,
290/// };
291///
292/// #[derive(Archive, Serialize, Deserialize)]
293/// struct Example {
294/// name: String,
295/// value: i32,
296/// }
297///
298/// let value = Example {
299/// name: "pi".to_string(),
300/// value: 31415926,
301/// };
302///
303/// let mut bytes = to_bytes::<Error>(&value).unwrap();
304///
305/// let mut archived = unsafe {
306/// access_unchecked_mut::<ArchivedExample>(&mut *bytes)
307/// };
308/// assert_eq!(archived.name, "pi");
309/// assert_eq!(archived.value, 31415926);
310///
311/// // Because the access is mutable, we can mutate the archived data
312/// munge!(let ArchivedExample { mut value, .. } = archived);
313/// assert_eq!(*value, 31415926);
314/// *value = 12345.into();
315/// assert_eq!(*value, 12345);
316/// ```
317pub unsafe fn access_unchecked_mut<T: Portable>(
318 bytes: &mut [u8],
319) -> Seal<'_, T> {
320 // SAFETY: The caller has guaranteed that the given bytes pass validation
321 // when passed to `access_mut`.
322 unsafe {
323 access_pos_unchecked_mut::<T>(bytes, root_position::<T>(bytes.len()))
324 }
325}
326
327/// Serialize a value using the given serializer.
328///
329/// Returns the position of the serialized value.
330///
331/// Most of the time, [`to_bytes`](high::to_bytes) is a more ergonomic way to
332/// serialize a value to bytes.
333///
334/// # Example
335///
336/// ```
337/// use rkyv::{
338/// access,
339/// api::serialize_using,
340/// rancor::Error,
341/// ser::{sharing::Share, Serializer},
342/// util::{with_arena, AlignedVec},
343/// Archive, Deserialize, Serialize,
344/// };
345///
346/// #[derive(Archive, Serialize, Deserialize)]
347/// struct Example {
348/// name: String,
349/// value: i32,
350/// }
351///
352/// let bytes = with_arena(|arena| {
353/// let mut serializer = Serializer::new(
354/// AlignedVec::<4>::new(),
355/// arena.acquire(),
356/// Share::new(),
357/// );
358///
359/// let value = Example {
360/// name: "pi".to_string(),
361/// value: 31415926,
362/// };
363///
364/// serialize_using::<_, Error>(&value, &mut serializer).unwrap();
365/// serializer.into_writer()
366/// });
367///
368/// let archived = access::<ArchivedExample, Error>(&*bytes).unwrap();
369/// assert_eq!(archived.value, 31415926);
370/// ```
371pub fn serialize_using<S, E>(
372 value: &impl SerializeUnsized<Strategy<S, E>>,
373 serializer: &mut S,
374) -> Result<usize, E>
375where
376 S: Writer<E> + ?Sized,
377{
378 value.serialize_unsized(Strategy::wrap(serializer))
379}
380
381/// Deserialize a value using the given deserializer.
382///
383/// Most of the time, [`deserialize`](high::deserialize) is a more ergonomic way
384/// to deserialize an archived value.
385///
386/// # Example
387///
388/// ```
389/// use rkyv::{
390/// access, api::deserialize_using, de::Pool, rancor::Error, to_bytes,
391/// Archive, Deserialize, Serialize,
392/// };
393///
394/// #[derive(Archive, Serialize, Deserialize)]
395/// struct Example {
396/// name: String,
397/// value: i32,
398/// }
399///
400/// let value = Example {
401/// name: "pi".to_string(),
402/// value: 31415926,
403/// };
404///
405/// let bytes = to_bytes::<Error>(&value).unwrap();
406/// let archived = access::<ArchivedExample, Error>(&bytes).unwrap();
407/// let deserialized =
408/// deserialize_using::<Example, _, Error>(archived, &mut Pool::new())
409/// .unwrap();
410/// ```
411pub fn deserialize_using<T, D, E>(
412 value: &impl Deserialize<T, Strategy<D, E>>,
413 deserializer: &mut D,
414) -> Result<T, E> {
415 value.deserialize(Strategy::wrap(deserializer))
416}