Skip to main content

rkyv/api/low/
checked.rs

1//! Low-level checked APIs.
2//!
3//! These APIs require user-provided writers and allocators, and do not support
4//! shared pointers.
5
6use bytecheck::CheckBytes;
7use rancor::{Source, Strategy};
8
9use crate::{
10    api::{
11        access_pos_unchecked_mut, access_pos_with_context, access_with_context,
12        check_pos_with_context, deserialize_using, root_position,
13    },
14    de::pooling::Unpool,
15    seal::Seal,
16    validation::{archive::ArchiveValidator, Validator},
17    Archive, Deserialize, Portable,
18};
19
20/// A low-level validator.
21///
22/// This is part of the [low-level API](crate::api::low).
23pub type LowValidator<'a, E> = Strategy<Validator<ArchiveValidator<'a>, ()>, E>;
24
25fn validator(bytes: &[u8]) -> Validator<ArchiveValidator<'_>, ()> {
26    Validator::new(ArchiveValidator::new(bytes), ())
27}
28
29/// Access a byte slice with a given root position.
30///
31/// This is a safe alternative to [`access_pos_unchecked`] and is part of the
32/// [low-level API](crate::api::low).
33///
34/// [`access_pos_unchecked`]: crate::api::access_pos_unchecked
35///
36/// # Example
37///
38/// ```
39/// use core::mem::MaybeUninit;
40///
41/// use rkyv::{
42///     api::{
43///         low::{access_pos, to_bytes_in_with_alloc},
44///         root_position,
45///     },
46///     rancor::Failure,
47///     ser::{allocator::SubAllocator, writer::Buffer},
48///     util::Align,
49///     with::InlineAsBox,
50///     Archive, Serialize,
51/// };
52///
53/// let mut output = Align([MaybeUninit::<u8>::uninit(); 256]);
54/// let mut alloc = [MaybeUninit::<u8>::uninit(); 256];
55///
56/// #[derive(Archive, Serialize)]
57/// struct Example<'a> {
58///     #[rkyv(with = InlineAsBox)]
59///     inner: &'a i32,
60/// }
61///
62/// let forty_two = 42;
63/// let value = Example { inner: &forty_two };
64///
65/// let bytes = to_bytes_in_with_alloc::<_, _, Failure>(
66///     &value,
67///     Buffer::from(&mut *output),
68///     SubAllocator::new(&mut alloc),
69/// )
70/// .unwrap();
71///
72/// let archived = access_pos::<ArchivedExample<'_>, Failure>(
73///     &*bytes,
74///     root_position::<ArchivedExample<'_>>(bytes.len()),
75/// )
76/// .unwrap();
77/// assert_eq!(*archived.inner, 42);
78/// ```
79pub fn access_pos<T, E>(bytes: &[u8], pos: usize) -> Result<&T, E>
80where
81    T: Portable + for<'a> CheckBytes<LowValidator<'a, E>>,
82    E: Source,
83{
84    access_pos_with_context::<_, _, E>(bytes, pos, &mut validator(bytes))
85}
86
87/// Access a byte slice.
88///
89/// This is a safe alternative to [`access_unchecked`] and is part of the
90/// [low-level API](crate::api::low).
91///
92/// [`access_unchecked`]: crate::api::access_unchecked
93///
94/// # Example
95///
96/// ```
97/// use core::mem::MaybeUninit;
98///
99/// use rkyv::{
100///     api::{
101///         low::{access, to_bytes_in_with_alloc},
102///         root_position,
103///     },
104///     rancor::Failure,
105///     ser::{allocator::SubAllocator, writer::Buffer},
106///     util::Align,
107///     with::InlineAsBox,
108///     Archive, Serialize,
109/// };
110///
111/// let mut output = Align([MaybeUninit::<u8>::uninit(); 256]);
112/// let mut alloc = [MaybeUninit::<u8>::uninit(); 256];
113///
114/// #[derive(Archive, Serialize)]
115/// struct Example<'a> {
116///     #[rkyv(with = InlineAsBox)]
117///     inner: &'a i32,
118/// }
119///
120/// let forty_two = 42;
121/// let value = Example { inner: &forty_two };
122///
123/// let bytes = to_bytes_in_with_alloc::<_, _, Failure>(
124///     &value,
125///     Buffer::from(&mut *output),
126///     SubAllocator::new(&mut alloc),
127/// )
128/// .unwrap();
129///
130/// let archived = access::<ArchivedExample<'_>, Failure>(&*bytes).unwrap();
131/// assert_eq!(*archived.inner, 42);
132/// ```
133pub fn access<T, E>(bytes: &[u8]) -> Result<&T, E>
134where
135    T: Portable + for<'a> CheckBytes<LowValidator<'a, E>>,
136    E: Source,
137{
138    access_with_context::<_, _, E>(bytes, &mut validator(bytes))
139}
140
141/// Mutably access a byte slice with a given root position.
142///
143/// This is a safe alternative to [`access_pos_unchecked_mut`] and is part of
144/// the [low-level API](crate::api::low).
145///
146/// [`access_pos_unchecked_mut`]: crate::api::access_pos_unchecked_mut
147///
148/// # Example
149///
150/// ```
151/// use core::mem::MaybeUninit;
152///
153/// use rkyv::{
154///     api::{root_position, low::{to_bytes_in_with_alloc, access_pos_mut}},
155///     rancor::Failure,
156///     ser::{allocator::SubAllocator, writer::Buffer},
157///     util::Align,
158///     with::InlineAsBox,
159///     Archive, Serialize,
160///     munge::munge,
161/// };
162///
163/// let mut output = Align([MaybeUninit::<u8>::uninit(); 256]);
164/// let mut alloc = [MaybeUninit::<u8>::uninit(); 256];
165///
166/// #[derive(Archive, Serialize)]
167/// struct Example {
168///     inner: i32,
169/// }
170///
171/// let value = Example { inner: 42 };
172///
173/// let mut bytes = to_bytes_in_with_alloc::<_, _, Failure>(
174///     &value,
175///     Buffer::from(&mut *output),
176///     SubAllocator::new(&mut alloc),
177/// )
178/// .unwrap();
179///
180/// let root_pos = root_position::<ArchivedExample>(bytes.len());
181/// let mut archived = access_pos_mut::<ArchivedExample, Failure>(
182///     &mut *bytes,
183///     root_pos,
184/// ).unwrap();
185///
186/// // Because the access is mutable, we can mutate the archived data
187/// munge!(let ArchivedExample { mut inner, .. } = archived);
188/// assert_eq!(*inner, 42);
189/// *inner = 12345.into();
190/// assert_eq!(*inner, 12345);
191/// ```
192pub fn access_pos_mut<T, E>(
193    bytes: &mut [u8],
194    pos: usize,
195) -> Result<Seal<'_, T>, E>
196where
197    T: Portable + for<'a> CheckBytes<LowValidator<'a, E>>,
198    E: Source,
199{
200    let mut context = validator(bytes);
201    check_pos_with_context::<T, _, E>(bytes, pos, &mut context)?;
202    unsafe { Ok(access_pos_unchecked_mut::<T>(bytes, pos)) }
203}
204
205/// Mutably accesses a byte slice.
206///
207/// This is a safe alternative to [`access_unchecked_mut`] and is part of the
208/// [low-level API](crate::api::low).
209///
210/// [`access_unchecked_mut`]: crate::api::access_unchecked_mut
211///
212/// # Example
213///
214/// ```
215/// use core::mem::MaybeUninit;
216///
217/// use rkyv::{
218///     api::low::{to_bytes_in_with_alloc, access_mut},
219///     rancor::Failure,
220///     ser::{allocator::SubAllocator, writer::Buffer},
221///     util::Align,
222///     with::InlineAsBox,
223///     Archive, Serialize,
224///     munge::munge,
225/// };
226///
227/// let mut output = Align([MaybeUninit::<u8>::uninit(); 256]);
228/// let mut alloc = [MaybeUninit::<u8>::uninit(); 256];
229///
230/// #[derive(Archive, Serialize)]
231/// struct Example {
232///     inner: i32,
233/// }
234///
235/// let value = Example { inner: 42 };
236///
237/// let mut bytes = to_bytes_in_with_alloc::<_, _, Failure>(
238///     &value,
239///     Buffer::from(&mut *output),
240///     SubAllocator::new(&mut alloc),
241/// )
242/// .unwrap();
243///
244/// let mut archived = access_mut::<ArchivedExample, Failure>(
245///     &mut *bytes,
246/// ).unwrap();
247///
248/// // Because the access is mutable, we can mutate the archived data
249/// munge!(let ArchivedExample { mut inner, .. } = archived);
250/// assert_eq!(*inner, 42);
251/// *inner = 12345.into();
252/// assert_eq!(*inner, 12345);
253/// ```
254pub fn access_mut<T, E>(bytes: &mut [u8]) -> Result<Seal<'_, T>, E>
255where
256    T: Portable + for<'a> CheckBytes<LowValidator<'a, E>>,
257    E: Source,
258{
259    let mut context = validator(bytes);
260    let pos = root_position::<T>(bytes.len());
261    check_pos_with_context::<T, _, E>(bytes, pos, &mut context)?;
262    unsafe { Ok(access_pos_unchecked_mut::<T>(bytes, pos)) }
263}
264
265/// Deserialize a value from the given bytes.
266///
267/// This is a safe alternative to [`from_bytes_unchecked`] and is part of the
268/// [low-level API](crate::api::low).
269///
270/// [`from_bytes_unchecked`]: crate::api::low::from_bytes_unchecked
271///
272/// # Example
273///
274/// ```
275/// use core::mem::MaybeUninit;
276///
277/// use rkyv::{
278///     api::low::{from_bytes, to_bytes_in_with_alloc},
279///     rancor::Failure,
280///     ser::{allocator::SubAllocator, writer::Buffer},
281///     util::Align,
282///     Archive, Deserialize, Serialize,
283/// };
284///
285/// let mut output = Align([MaybeUninit::<u8>::uninit(); 256]);
286/// let mut alloc = [MaybeUninit::<u8>::uninit(); 256];
287///
288/// #[derive(Archive, Serialize, Deserialize, PartialEq, Debug)]
289/// struct Example {
290///     inner: i32,
291/// }
292///
293/// let value = Example { inner: 42 };
294///
295/// let bytes = to_bytes_in_with_alloc::<_, _, Failure>(
296///     &value,
297///     Buffer::from(&mut *output),
298///     SubAllocator::new(&mut alloc),
299/// )
300/// .unwrap();
301///
302/// let deserialized = from_bytes::<Example, Failure>(&*bytes).unwrap();
303/// assert_eq!(value, deserialized);
304/// ```
305pub fn from_bytes<T, E>(bytes: &[u8]) -> Result<T, E>
306where
307    T: Archive,
308    T::Archived: for<'a> CheckBytes<LowValidator<'a, E>>
309        + Deserialize<T, Strategy<Unpool, E>>,
310    E: Source,
311{
312    deserialize_using(access::<T::Archived, E>(bytes)?, &mut Unpool)
313}