testnumbat_codec/
top_de.rs

1use alloc::boxed::Box;
2
3use crate::{
4    codec_err::DecodeError, nested_de::*, top_de_input::TopDecodeInput, NestedDecodeInput, TypeInfo,
5};
6
7/// Trait that allows zero-copy read of values from an underlying API in big endian format.
8///
9/// 'Top' stands for the fact that values are deserialized on their own,
10/// so we have the benefit of knowing their length.
11/// This is useful in many scnearios, such as not having to encode Vec length and others.
12///
13/// The opther optimization that can be done when deserializing top-level objects
14/// is using special functions from the underlying API that do some of the work for the deserializer.
15/// These include getting values directly as i64/u64 or wrapping them directly into an owned Box<[u8]>.
16///
17/// BigInt/BigUint handling is not included here, because these are API-dependent
18/// and would overly complicate the trait.
19///
20pub trait TopDecode: Sized {
21    #[doc(hidden)]
22    const TYPE_INFO: TypeInfo = TypeInfo::Unknown;
23
24    /// Attempt to deserialize the value from input.
25    fn top_decode<I: TopDecodeInput>(input: I) -> Result<Self, DecodeError>;
26
27    /// Version of `top_decode` that exits quickly in case of error.
28    /// Its purpose is to create smaller implementations
29    /// in cases where the application is supposed to exit directly on decode error.
30    #[inline]
31    fn top_decode_or_exit<I: TopDecodeInput, ExitCtx: Clone>(
32        input: I,
33        c: ExitCtx,
34        exit: fn(ExitCtx, DecodeError) -> !,
35    ) -> Self {
36        match Self::top_decode(input) {
37            Ok(v) => v,
38            Err(e) => exit(c, e),
39        }
40    }
41
42    /// Allows types to provide optimized implementations for their boxed version.
43    /// Especially designed for byte arrays that can be transmuted directly from the input sometimes.
44    #[doc(hidden)]
45    #[inline]
46    fn top_decode_boxed<I: TopDecodeInput>(input: I) -> Result<Box<Self>, DecodeError> {
47        Ok(Box::new(Self::top_decode(input)?))
48    }
49
50    #[doc(hidden)]
51    #[inline]
52    fn top_decode_boxed_or_exit<I: TopDecodeInput, ExitCtx: Clone>(
53        input: I,
54        c: ExitCtx,
55        exit: fn(ExitCtx, DecodeError) -> !,
56    ) -> Box<Self> {
57        Box::new(Self::top_decode_or_exit(input, c, exit))
58    }
59}
60
61/// Top-decodes the result using the NestedDecode implementation.
62pub fn top_decode_from_nested<T, I>(input: I) -> Result<T, DecodeError>
63where
64    I: TopDecodeInput,
65    T: NestedDecode,
66{
67    let mut nested_buffer = input.into_nested_buffer();
68    let result = T::dep_decode(&mut nested_buffer)?;
69    if !nested_buffer.is_depleted() {
70        return Err(DecodeError::INPUT_TOO_LONG);
71    }
72    Ok(result)
73}
74
75/// Top-decodes the result using the NestedDecode implementation.
76/// Uses the fast-exit mechanism in case of error.
77pub fn top_decode_from_nested_or_exit<T, I, ExitCtx: Clone>(
78    input: I,
79    c: ExitCtx,
80    exit: fn(ExitCtx, DecodeError) -> !,
81) -> T
82where
83    I: TopDecodeInput,
84    T: NestedDecode,
85{
86    let mut nested_buffer = input.into_nested_buffer();
87    let result = T::dep_decode_or_exit(&mut nested_buffer, c.clone(), exit);
88    if !nested_buffer.is_depleted() {
89        exit(c, DecodeError::INPUT_TOO_LONG);
90    }
91    result
92}