1use borsh::{io::Error, BorshDeserialize, BorshSchema, BorshSerialize};
15
16pub fn get_packed_len<S: BorshSchema>() -> usize {
26 crate::borsh1::get_packed_len::<S>()
28}
29
30pub fn try_from_slice_unchecked<T: BorshDeserialize>(data: &[u8]) -> Result<T, Error> {
45 crate::borsh1::try_from_slice_unchecked::<T>(data)
47}
48
49pub fn get_instance_packed_len<T: BorshSerialize>(instance: &T) -> Result<usize, Error> {
61 crate::borsh1::get_instance_packed_len(instance)
63}
64
65macro_rules! impl_get_packed_len_v0 {
66 ($borsh:ident $(,#[$meta:meta])?) => {
67 $(#[$meta])?
72 pub fn get_packed_len<S: $borsh::BorshSchema>() -> usize {
73 let $borsh::schema::BorshSchemaContainer { declaration, definitions } =
74 &S::schema_container();
75 get_declaration_packed_len(declaration, definitions)
76 }
77
78 fn get_declaration_packed_len(
80 declaration: &str,
81 definitions: &std::collections::HashMap<$borsh::schema::Declaration, $borsh::schema::Definition>,
82 ) -> usize {
83 match definitions.get(declaration) {
84 Some($borsh::schema::Definition::Array { length, elements }) => {
85 *length as usize * get_declaration_packed_len(elements, definitions)
86 }
87 Some($borsh::schema::Definition::Enum { variants }) => {
88 1 + variants
89 .iter()
90 .map(|(_, declaration)| get_declaration_packed_len(declaration, definitions))
91 .max()
92 .unwrap_or(0)
93 }
94 Some($borsh::schema::Definition::Struct { fields }) => match fields {
95 $borsh::schema::Fields::NamedFields(named_fields) => named_fields
96 .iter()
97 .map(|(_, declaration)| get_declaration_packed_len(declaration, definitions))
98 .sum(),
99 $borsh::schema::Fields::UnnamedFields(declarations) => declarations
100 .iter()
101 .map(|declaration| get_declaration_packed_len(declaration, definitions))
102 .sum(),
103 $borsh::schema::Fields::Empty => 0,
104 },
105 Some($borsh::schema::Definition::Sequence {
106 elements: _elements,
107 }) => panic!("Missing support for Definition::Sequence"),
108 Some($borsh::schema::Definition::Tuple { elements }) => elements
109 .iter()
110 .map(|element| get_declaration_packed_len(element, definitions))
111 .sum(),
112 None => match declaration {
113 "bool" | "u8" | "i8" => 1,
114 "u16" | "i16" => 2,
115 "u32" | "i32" => 4,
116 "u64" | "i64" => 8,
117 "u128" | "i128" => 16,
118 "nil" => 0,
119 _ => panic!("Missing primitive type: {declaration}"),
120 },
121 }
122 }
123 }
124}
125pub(crate) use impl_get_packed_len_v0;
126
127macro_rules! impl_get_packed_len_v1 {
128 ($borsh:ident $(,#[$meta:meta])?) => {
129 $(#[$meta])?
134 pub fn get_packed_len<S: $borsh::BorshSchema>() -> usize {
135 let container = $borsh::schema_container_of::<S>();
136 get_declaration_packed_len(container.declaration(), &container)
137 }
138
139 fn get_declaration_packed_len(
141 declaration: &str,
142 container: &$borsh::schema::BorshSchemaContainer,
143 ) -> usize {
144 match container.get_definition(declaration) {
145 Some($borsh::schema::Definition::Sequence { length_width, length_range, elements }) if *length_width == 0 => {
146 *length_range.end() as usize * get_declaration_packed_len(elements, container)
147 }
148 Some($borsh::schema::Definition::Enum { tag_width, variants }) => {
149 (*tag_width as usize) + variants
150 .iter()
151 .map(|(_, _, declaration)| get_declaration_packed_len(declaration, container))
152 .max()
153 .unwrap_or(0)
154 }
155 Some($borsh::schema::Definition::Struct { fields }) => match fields {
156 $borsh::schema::Fields::NamedFields(named_fields) => named_fields
157 .iter()
158 .map(|(_, declaration)| get_declaration_packed_len(declaration, container))
159 .sum(),
160 $borsh::schema::Fields::UnnamedFields(declarations) => declarations
161 .iter()
162 .map(|declaration| get_declaration_packed_len(declaration, container))
163 .sum(),
164 $borsh::schema::Fields::Empty => 0,
165 },
166 Some($borsh::schema::Definition::Sequence {
167 ..
168 }) => panic!("Missing support for Definition::Sequence"),
169 Some($borsh::schema::Definition::Tuple { elements }) => elements
170 .iter()
171 .map(|element| get_declaration_packed_len(element, container))
172 .sum(),
173 Some($borsh::schema::Definition::Primitive(size)) => *size as usize,
174 None => match declaration {
175 "bool" | "u8" | "i8" => 1,
176 "u16" | "i16" => 2,
177 "u32" | "i32" => 4,
178 "u64" | "i64" => 8,
179 "u128" | "i128" => 16,
180 "nil" => 0,
181 _ => panic!("Missing primitive type: {declaration}"),
182 },
183 }
184 }
185 }
186}
187pub(crate) use impl_get_packed_len_v1;
188
189macro_rules! impl_try_from_slice_unchecked {
190 ($borsh:ident, $borsh_io:ident $(,#[$meta:meta])?) => {
191 $(#[$meta])?
201 pub fn try_from_slice_unchecked<T: $borsh::BorshDeserialize>(data: &[u8]) -> Result<T, $borsh_io::Error> {
202 let mut data_mut = data;
203 let result = T::deserialize(&mut data_mut)?;
204 Ok(result)
205 }
206 }
207}
208pub(crate) use impl_try_from_slice_unchecked;
209
210macro_rules! impl_get_instance_packed_len {
211 ($borsh:ident, $borsh_io:ident $(,#[$meta:meta])?) => {
212 #[derive(Default)]
214 struct WriteCounter {
215 count: usize,
216 }
217
218 impl $borsh_io::Write for WriteCounter {
219 fn write(&mut self, data: &[u8]) -> Result<usize, $borsh_io::Error> {
220 let amount = data.len();
221 self.count += amount;
222 Ok(amount)
223 }
224
225 fn flush(&mut self) -> Result<(), $borsh_io::Error> {
226 Ok(())
227 }
228 }
229
230 $(#[$meta])?
237 pub fn get_instance_packed_len<T: $borsh::BorshSerialize>(instance: &T) -> Result<usize, $borsh_io::Error> {
238 let mut counter = WriteCounter::default();
239 instance.serialize(&mut counter)?;
240 Ok(counter.count)
241 }
242 }
243}
244pub(crate) use impl_get_instance_packed_len;
245
246#[cfg(test)]
247macro_rules! impl_tests {
248 ($borsh:ident, $borsh_io:ident) => {
249 extern crate alloc;
250 use {
251 super::*,
252 std::{collections::HashMap, mem::size_of},
253 $borsh::{BorshDeserialize, BorshSerialize},
254 $borsh_io::ErrorKind,
255 };
256
257 type Child = [u8; 64];
258 type Parent = Vec<Child>;
259
260 #[test]
261 fn unchecked_deserialization() {
262 let parent = vec![[0u8; 64], [1u8; 64], [2u8; 64]];
263
264 let mut byte_vec = vec![0u8; 4 + get_packed_len::<Child>() * 3];
266 let mut bytes = byte_vec.as_mut_slice();
267 parent.serialize(&mut bytes).unwrap();
268 let deserialized = Parent::try_from_slice(&byte_vec).unwrap();
269 assert_eq!(deserialized, parent);
270 let deserialized = try_from_slice_unchecked::<Parent>(&byte_vec).unwrap();
271 assert_eq!(deserialized, parent);
272
273 let mut byte_vec = vec![0u8; 4 + get_packed_len::<Child>() * 10];
275 let mut bytes = byte_vec.as_mut_slice();
276 parent.serialize(&mut bytes).unwrap();
277 let err = Parent::try_from_slice(&byte_vec).unwrap_err();
278 assert_eq!(err.kind(), ErrorKind::InvalidData);
279 let deserialized = try_from_slice_unchecked::<Parent>(&byte_vec).unwrap();
280 assert_eq!(deserialized, parent);
281 }
282
283 #[test]
284 fn packed_len() {
285 assert_eq!(get_packed_len::<u64>(), size_of::<u64>());
286 assert_eq!(get_packed_len::<Child>(), size_of::<u8>() * 64);
287 }
288
289 #[test]
290 fn instance_packed_len_matches_packed_len() {
291 let child = [0u8; 64];
292 assert_eq!(
293 get_packed_len::<Child>(),
294 get_instance_packed_len(&child).unwrap(),
295 );
296 assert_eq!(
297 get_packed_len::<u8>(),
298 get_instance_packed_len(&0u8).unwrap(),
299 );
300 assert_eq!(
301 get_packed_len::<u16>(),
302 get_instance_packed_len(&0u16).unwrap(),
303 );
304 assert_eq!(
305 get_packed_len::<u32>(),
306 get_instance_packed_len(&0u32).unwrap(),
307 );
308 assert_eq!(
309 get_packed_len::<u64>(),
310 get_instance_packed_len(&0u64).unwrap(),
311 );
312 assert_eq!(
313 get_packed_len::<u128>(),
314 get_instance_packed_len(&0u128).unwrap(),
315 );
316 assert_eq!(
317 get_packed_len::<[u8; 10]>(),
318 get_instance_packed_len(&[0u8; 10]).unwrap(),
319 );
320 assert_eq!(
321 get_packed_len::<(i8, i16, i32, i64, i128)>(),
322 get_instance_packed_len(&(i8::MAX, i16::MAX, i32::MAX, i64::MAX, i128::MAX))
323 .unwrap(),
324 );
325 }
326
327 #[test]
328 fn instance_packed_len_with_vec() {
329 let parent = vec![
330 [0u8; 64], [1u8; 64], [2u8; 64], [3u8; 64], [4u8; 64], [5u8; 64],
331 ];
332 assert_eq!(
333 get_instance_packed_len(&parent).unwrap(),
334 4 + parent.len() * get_packed_len::<Child>()
335 );
336 }
337
338 #[test]
339 fn instance_packed_len_with_varying_sizes_in_hashmap() {
340 let mut data = HashMap::new();
341 let key1 = "the first string, it's actually really really long".to_string();
342 let value1 = "".to_string();
343 let key2 = "second string, shorter".to_string();
344 let value2 = "a real value".to_string();
345 let key3 = "third".to_string();
346 let value3 = "an even longer value".to_string();
347 data.insert(key1.clone(), value1.clone());
348 data.insert(key2.clone(), value2.clone());
349 data.insert(key3.clone(), value3.clone());
350 assert_eq!(
351 get_instance_packed_len(&data).unwrap(),
352 4 + get_instance_packed_len(&key1).unwrap()
353 + get_instance_packed_len(&value1).unwrap()
354 + get_instance_packed_len(&key2).unwrap()
355 + get_instance_packed_len(&value2).unwrap()
356 + get_instance_packed_len(&key3).unwrap()
357 + get_instance_packed_len(&value3).unwrap()
358 );
359 }
360 };
361}
362#[cfg(test)]
363pub(crate) use impl_tests;