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}