use alloc::{string::ToString, vec, vec::Vec}; use bytes::{Buf, BufMut, Bytes, BytesMut}; use ref_cast::RefCast; use crate::{error::*, EpeeValue, InnerMarker, Marker}; #[derive(RefCast)] #[repr(transparent)] pub struct ContainerAsBlob(Vec); impl From> for ContainerAsBlob { fn from(value: Vec) -> Self { Self(value) } } impl From> for Vec { fn from(value: ContainerAsBlob) -> Self { value.0 } } impl<'a, T: Containerable + EpeeValue> From<&'a Vec> for &'a ContainerAsBlob { fn from(value: &'a Vec) -> Self { ContainerAsBlob::ref_cast(value) } } impl EpeeValue for ContainerAsBlob { const MARKER: Marker = Marker::new(InnerMarker::String); fn read(r: &mut B, marker: &Marker) -> Result { let bytes = Bytes::read(r, marker)?; if bytes.len() % T::SIZE != 0 { return Err(Error::Value( "Can't convert blob container to Vec type.".to_string(), )); } Ok(Self(bytes.chunks(T::SIZE).map(T::from_bytes).collect())) } fn should_write(&self) -> bool { !self.0.is_empty() } fn epee_default_value() -> Option { Some(Self(vec![])) } fn write(self, w: &mut B) -> Result<()> { let mut buf = BytesMut::with_capacity(self.0.len() * T::SIZE); self.0.iter().for_each(|tt| tt.push_bytes(&mut buf)); buf.write(w) } } pub trait Containerable { const SIZE: usize; /// Returns `Self` from bytes. /// /// `bytes` is guaranteed to be [`Self::SIZE`] long. fn from_bytes(bytes: &[u8]) -> Self; fn push_bytes(&self, buf: &mut BytesMut); } macro_rules! int_container_able { ($int:ty ) => { impl Containerable for $int { const SIZE: usize = size_of::<$int>(); fn from_bytes(bytes: &[u8]) -> Self { <$int>::from_le_bytes(bytes.try_into().unwrap()) } fn push_bytes(&self, buf: &mut BytesMut) { buf.put_slice(&self.to_le_bytes()) } } }; } int_container_able!(u16); int_container_able!(u32); int_container_able!(u64); int_container_able!(u128); int_container_able!(i8); int_container_able!(i16); int_container_able!(i32); int_container_able!(i64); int_container_able!(i128);