cuprate_epee_encoding/
container_as_blob.rs

1use alloc::{string::ToString, vec, vec::Vec};
2
3use bytes::{Buf, BufMut, Bytes, BytesMut};
4use ref_cast::RefCast;
5
6use crate::{error::*, EpeeValue, InnerMarker, Marker};
7
8#[derive(RefCast)]
9#[repr(transparent)]
10pub struct ContainerAsBlob<T: Containerable + EpeeValue>(Vec<T>);
11
12impl<T: Containerable + EpeeValue> From<Vec<T>> for ContainerAsBlob<T> {
13    fn from(value: Vec<T>) -> Self {
14        Self(value)
15    }
16}
17
18impl<T: Containerable + EpeeValue> From<ContainerAsBlob<T>> for Vec<T> {
19    fn from(value: ContainerAsBlob<T>) -> Self {
20        value.0
21    }
22}
23
24impl<'a, T: Containerable + EpeeValue> From<&'a Vec<T>> for &'a ContainerAsBlob<T> {
25    fn from(value: &'a Vec<T>) -> Self {
26        ContainerAsBlob::ref_cast(value)
27    }
28}
29
30impl<T: Containerable + EpeeValue> EpeeValue for ContainerAsBlob<T> {
31    const MARKER: Marker = Marker::new(InnerMarker::String);
32
33    fn read<B: Buf>(r: &mut B, marker: &Marker) -> Result<Self> {
34        let bytes = Bytes::read(r, marker)?;
35        if bytes.len() % T::SIZE != 0 {
36            return Err(Error::Value(
37                "Can't convert blob container to Vec type.".to_string(),
38            ));
39        }
40
41        Ok(Self(bytes.chunks(T::SIZE).map(T::from_bytes).collect()))
42    }
43
44    fn should_write(&self) -> bool {
45        !self.0.is_empty()
46    }
47
48    fn epee_default_value() -> Option<Self> {
49        Some(Self(vec![]))
50    }
51
52    fn write<B: BufMut>(self, w: &mut B) -> Result<()> {
53        let mut buf = BytesMut::with_capacity(self.0.len() * T::SIZE);
54        self.0.iter().for_each(|tt| tt.push_bytes(&mut buf));
55        buf.write(w)
56    }
57}
58
59pub trait Containerable {
60    const SIZE: usize;
61
62    /// Returns `Self` from bytes.
63    ///
64    /// `bytes` is guaranteed to be [`Self::SIZE`] long.
65    fn from_bytes(bytes: &[u8]) -> Self;
66
67    fn push_bytes(&self, buf: &mut BytesMut);
68}
69
70macro_rules! int_container_able {
71    ($int:ty ) => {
72        impl Containerable for $int {
73            const SIZE: usize = size_of::<$int>();
74
75            fn from_bytes(bytes: &[u8]) -> Self {
76                <$int>::from_le_bytes(bytes.try_into().unwrap())
77            }
78
79            fn push_bytes(&self, buf: &mut BytesMut) {
80                buf.put_slice(&self.to_le_bytes())
81            }
82        }
83    };
84}
85
86int_container_able!(u16);
87int_container_able!(u32);
88int_container_able!(u64);
89int_container_able!(u128);
90
91int_container_able!(i8);
92int_container_able!(i16);
93int_container_able!(i32);
94int_container_able!(i64);
95int_container_able!(i128);