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}