concordium_base/common/
encoded.rs

1use super::{Deserial, ParseResult, Serial};
2
3/// Encoded data `A` using the Concordium specific serialization
4/// [`Serial`]/[`Deserial`].
5///
6/// This is a simple wrapper around [`Vec<u8>`](Vec) with bespoke serialization
7/// and provides [`serde`] implementation as a hex string.
8#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, derive_more::Into)]
9#[serde(transparent)]
10#[repr(transparent)]
11pub struct Encoded<A> {
12    #[serde(with = "crate::internal::byte_array_hex")]
13    pub(crate) bytes: Vec<u8>,
14    _kind: std::marker::PhantomData<A>,
15}
16
17impl<A> Encoded<A> {
18    /// Serialize `A` into `Encoded<A>`.
19    pub fn encode(item: &A) -> Self
20    where
21        A: Serial,
22    {
23        Self {
24            bytes: super::to_bytes(item),
25            _kind: Default::default(),
26        }
27    }
28
29    /// Attempt to decode the [`Encoded`] into `A`.
30    ///
31    /// This also checks that all data is used, i.e. there are no remaining
32    /// trailing bytes.
33    pub fn decode(&self) -> ParseResult<A>
34    where
35        A: Deserial,
36    {
37        use super::Get;
38        let mut source = std::io::Cursor::new(&self.bytes);
39        let payload = source.get()?;
40        // ensure payload length matches the stated size.
41        let consumed = source.position();
42        anyhow::ensure!(
43            consumed == self.bytes.len() as u64,
44            "Payload length information is inaccurate: {} bytes of input remaining.",
45            self.bytes.len() as u64 - consumed
46        );
47        Ok(payload)
48    }
49}
50
51impl<A> From<Vec<u8>> for Encoded<A> {
52    fn from(encoding: Vec<u8>) -> Self {
53        Self {
54            bytes: encoding,
55            _kind: Default::default(),
56        }
57    }
58}
59
60impl<A> AsRef<[u8]> for Encoded<A> {
61    fn as_ref(&self) -> &[u8] {
62        &self.bytes
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69
70    /// Ensure encoding and decoding produces the same item.
71    #[test]
72    fn test_encode_decode() {
73        let item = vec![1, 2, 4, 3, 4, 5, 6, 8, 4, 89, 5];
74        let encoded = Encoded::encode(&item);
75        let item_decoded = encoded.decode().expect("Failed decoding a vec");
76        assert_eq!(item, item_decoded)
77    }
78
79    /// Ensure the decoding fails when decoding does not consume every byte.
80    #[test]
81    fn test_decode_fails_when_leftover_bytes() {
82        let item = vec![0, 0, 0, 0, 32];
83        let encoded = Encoded::<u32>::from(item);
84        let result = encoded.decode();
85        assert!(result.is_err())
86    }
87}