Skip to main content

slice_codec/
decode_from.rs

1// Copyright (c) ZeroC, Inc.
2
3use crate::buffer::InputSource;
4use crate::decoder::Decoder;
5use crate::Result;
6
7/// TODO
8pub trait DecodeFrom: Sized {
9    /// Decodes a value of this type from the provided decoder.
10    fn decode_from(decoder: &mut Decoder<impl InputSource>) -> Result<Self>;
11}
12
13// =============================================================================
14// Macros to streamline implementing `DecodeFrom` on common types.
15// =============================================================================
16
17/// This macro implements [`DecodeFrom`] on a numeric primitive type by calling `from_le_bytes` on it, which constructs
18/// a new instance of the type from a series of little-endian bytes. We have to use a macro because there is no common
19/// trait for numeric types, they all just happen to have this function with the same name and behavior.
20///
21/// This works out-of-the-box because both Rust and Slice use two's complement for representing signed integers,
22/// and IEEE-754 for floating point numbers.
23#[doc(hidden)]
24#[macro_export]
25macro_rules! implement_decode_from_on_numeric_primitive_type {
26    ($ty:ty, $doc_text:literal) => {
27        impl DecodeFrom for $ty {
28            #[doc = $doc_text]
29            fn decode_from(decoder: &mut Decoder<impl InputSource>) -> Result<Self> {
30                let bytes = decoder.read_bytes_exact()?;
31                Ok(Self::from_le_bytes(*bytes))
32            }
33        }
34    };
35}
36pub use implement_decode_from_on_numeric_primitive_type; // Re-export the macro so it can be used in other modules.
37
38/// This macro provides the logic for decoding a dictionary's elements, after its size has been decoded, and the
39/// dictionary itself has been allocated. We have to use a macro because there is no common trait for dictionary types,
40/// and this macro isn't a full implementation because of small differences in how the dictionaries must be constructed.
41#[doc(hidden)]
42#[macro_export]
43macro_rules! decode_dictionary_entries {
44    ($dictionary:ident, $decoder:ident, $length:ident) => {
45        // Decode each entry, and insert them into the dictionary, one by one.
46        for _ in 0..$length {
47            let key = $decoder.decode()?;
48            let value = $decoder.decode()?;
49
50            // Insert the (key,value) pair into the dictionary. If the decoded key is already present, return an error.
51            if $dictionary.insert(key, value).is_some() {
52                return Err(InvalidDataErrorKind::DuplicateDictionaryKey.into());
53            }
54        }
55    };
56}
57pub use decode_dictionary_entries; // Re-export the macro so it can be used in other modules.