Skip to main content

rkyv/api/
checked.rs

1use bytecheck::CheckBytes;
2use ptr_meta::Pointee;
3use rancor::{Source, Strategy};
4
5use crate::{
6    api::{access_pos_unchecked, root_position},
7    validation::{ArchiveContext, ArchiveContextExt},
8    Portable,
9};
10
11/// Check a byte slice with a given root position and context.
12///
13/// Most of the time, `access` is a more ergonomic way to check and access a
14/// byte slice.
15///
16/// # Example
17///
18/// ```
19/// use rkyv::{
20///     api::{check_pos_with_context, root_position},
21///     rancor::Error,
22///     to_bytes,
23///     validation::{
24///         archive::ArchiveValidator, shared::SharedValidator, Validator,
25///     },
26///     Archive, Deserialize, Serialize,
27/// };
28///
29/// #[derive(Archive, Serialize, Deserialize)]
30/// struct Example {
31///     name: String,
32///     value: i32,
33/// }
34///
35/// let value = Example {
36///     name: "pi".to_string(),
37///     value: 31415926,
38/// };
39///
40/// let bytes = to_bytes::<Error>(&value).unwrap();
41///
42/// check_pos_with_context::<ArchivedExample, _, Error>(
43///     &*bytes,
44///     root_position::<ArchivedExample>(bytes.len()),
45///     &mut Validator::new(
46///         ArchiveValidator::new(&*bytes),
47///         SharedValidator::new(),
48///     ),
49/// )
50/// .unwrap();
51/// ```
52pub fn check_pos_with_context<T, C, E>(
53    bytes: &[u8],
54    pos: usize,
55    context: &mut C,
56) -> Result<(), E>
57where
58    T: CheckBytes<Strategy<C, E>> + Pointee<Metadata = ()>,
59    C: ArchiveContext<E> + ?Sized,
60    E: Source,
61{
62    let context = Strategy::<C, E>::wrap(context);
63    let ptr = bytes.as_ptr().wrapping_add(pos).cast::<T>();
64    context.in_subtree(ptr, |context| {
65        // SAFETY: `in_subtree` has guaranteed that `ptr` is properly aligned
66        // and points to enough bytes for a `T`.
67        unsafe { T::check_bytes(ptr, context) }
68    })
69}
70
71/// Access a byte slice with a given root position and context.
72///
73/// This is a safe alternative to [`access_pos_unchecked`].
74///
75/// Most of the time, the context should be newly-created and not reused. Prefer
76/// `access_pos` whenever possible.
77///
78/// # Example
79///
80/// ```
81/// use rkyv::{
82///     api::{access_pos_with_context, root_position},
83///     rancor::Error,
84///     to_bytes,
85///     validation::{
86///         archive::ArchiveValidator, shared::SharedValidator, Validator,
87///     },
88///     Archive, Deserialize, Serialize,
89/// };
90///
91/// #[derive(Archive, Serialize, Deserialize)]
92/// struct Example {
93///     name: String,
94///     value: i32,
95/// }
96///
97/// let value = Example {
98///     name: "pi".to_string(),
99///     value: 31415926,
100/// };
101///
102/// let bytes = to_bytes::<Error>(&value).unwrap();
103///
104/// let archived = access_pos_with_context::<ArchivedExample, _, Error>(
105///     &*bytes,
106///     root_position::<ArchivedExample>(bytes.len()),
107///     &mut Validator::new(
108///         ArchiveValidator::new(&*bytes),
109///         SharedValidator::new(),
110///     ),
111/// )
112/// .unwrap();
113///
114/// assert_eq!(archived.name.as_str(), "pi");
115/// assert_eq!(archived.value.to_native(), 31415926);
116/// ```
117pub fn access_pos_with_context<'a, T, C, E>(
118    bytes: &'a [u8],
119    pos: usize,
120    context: &mut C,
121) -> Result<&'a T, E>
122where
123    T: Portable + CheckBytes<Strategy<C, E>> + Pointee<Metadata = ()>,
124    C: ArchiveContext<E> + ?Sized,
125    E: Source,
126{
127    check_pos_with_context::<T, C, E>(bytes, pos, context)?;
128    unsafe { Ok(access_pos_unchecked::<T>(bytes, pos)) }
129}
130
131/// Access a byte slice with a given context.
132///
133/// This is a safe alternative to [`access_unchecked`].
134///
135/// Most of the time, the context should be newly-created and not reused. Prefer
136/// `access` whenever possible.
137///
138/// [`access_unchecked`]: crate::api::access_unchecked
139///
140/// # Example
141///
142/// ```
143/// use rkyv::{
144///     api::{access_with_context, root_position},
145///     rancor::Error,
146///     to_bytes,
147///     validation::{
148///         archive::ArchiveValidator, shared::SharedValidator, Validator,
149///     },
150///     Archive, Deserialize, Serialize,
151/// };
152///
153/// #[derive(Archive, Serialize, Deserialize)]
154/// struct Example {
155///     name: String,
156///     value: i32,
157/// }
158///
159/// let value = Example {
160///     name: "pi".to_string(),
161///     value: 31415926,
162/// };
163///
164/// let bytes = to_bytes::<Error>(&value).unwrap();
165///
166/// let archived = access_with_context::<ArchivedExample, _, Error>(
167///     &*bytes,
168///     &mut Validator::new(
169///         ArchiveValidator::new(&*bytes),
170///         SharedValidator::new(),
171///     ),
172/// )
173/// .unwrap();
174///
175/// assert_eq!(archived.name.as_str(), "pi");
176/// assert_eq!(archived.value.to_native(), 31415926);
177/// ```
178pub fn access_with_context<'a, T, C, E>(
179    bytes: &'a [u8],
180    context: &mut C,
181) -> Result<&'a T, E>
182where
183    T: Portable + CheckBytes<Strategy<C, E>> + Pointee<Metadata = ()>,
184    C: ArchiveContext<E> + ?Sized,
185    E: Source,
186{
187    access_pos_with_context::<T, C, E>(
188        bytes,
189        root_position::<T>(bytes.len()),
190        context,
191    )
192}