diff options
| author | zirkonya <zirkonya@iridium.lan> | 2026-09-01 09:51:18 +0200 |
|---|---|---|
| committer | zirkonya <zirkonya@iridium.lan> | 2026-09-01 09:51:18 +0200 |
| commit | be62f065a62048b798e8bb2b8e3699bdd5b6d517 (patch) | |
| tree | 8b3f4b05838b5fa34c3ae24e35004343baadf2af /src/codec/decode.rs | |
| parent | fdc02f07cbd1994c1efb057f24a37a96faaa51fa (diff) | |
add proc macros ; benchmark ; example
Diffstat (limited to 'src/codec/decode.rs')
| -rw-r--r-- | src/codec/decode.rs | 251 |
1 files changed, 131 insertions, 120 deletions
diff --git a/src/codec/decode.rs b/src/codec/decode.rs index 529c448..d068760 100644 --- a/src/codec/decode.rs +++ b/src/codec/decode.rs @@ -1,150 +1,133 @@ -//! Decoding: reading protocol values from a byte stream. use std::{ collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet}, hash::Hash, - io::Read, sync::Arc, }; -use crate::{DEFAULT_BUFFER_LEN, codec::error::Result}; -use crate::{codec::error::CodecError, context::Context}; +use crate::{codec::error::Result, codec::error::CodecError, context::Context}; macro_rules! impl_decode { - (u8) => { - impl<Data> Decode<Data> for u8 { - fn decode(reader: &mut dyn Read, _: &Context<Data>) -> Result<Self> + ($t:ty) => { + impl<Data> Decode<Data> for $t { + fn decode(buf: &mut &[u8], _: &Context<Data>) -> Result<Self> where Self: Sized, { - let mut byte = [0u8; 1]; - reader.read_exact(&mut byte)?; - Ok(byte[0]) + const BYTES: usize = std::mem::size_of::<$t>(); + if buf.len() < BYTES { + return Err(CodecError::IoError(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "insufficient bytes", + ))); + } + let (bytes, rest) = buf.split_at(BYTES); + *buf = rest; + Ok(<$t>::from_be_bytes(bytes.try_into().unwrap())) } - fn decode_slice(reader: &mut dyn Read, _: &Context<Data>) -> Result<Vec<Self>> + fn decode_slice(buf: &mut &[u8], _: &Context<Data>) -> Result<Vec<Self>> where Self: Sized, { - let mut buf = Vec::new(); - reader.read_to_end(&mut buf)?; - Ok(buf) + const BYTES: usize = std::mem::size_of::<$t>(); + let count = buf.len() / BYTES; + let mut vec = Vec::with_capacity(count); + for _ in 0..count { + let (bytes, rest) = buf.split_at(BYTES); + *buf = rest; + vec.push(<$t>::from_be_bytes(bytes.try_into().unwrap())); + } + Ok(vec) } } }; - ($type: ty) => { - impl<Data> Decode<Data> for $type { - // decode number using big endian - fn decode(reader: &mut dyn Read, _: &Context<Data>) -> Result<Self> - where - Self: Sized, - { - const BYTES: usize = (<$type>::BITS / 8) as usize; - let mut bytes = [0; BYTES]; - reader.read_exact(&mut bytes)?; - Ok(<$type>::from_be_bytes(bytes)) - } +} - fn decode_slice(reader: &mut dyn Read, _: &Context<Data>) -> Result<Vec<Self>> +macro_rules! impl_decode_tuples { + ($($generic: ident),+) => { + impl<Data, $($generic),+> Decode<Data> for ($($generic,)+) + where + $($generic: Decode<Data>),+ + { + #[allow(non_snake_case)] + fn decode(buf: &mut &[u8], ctx: &Context<Data>) -> Result<Self> where Self: Sized, { - let mut buf = Vec::with_capacity(DEFAULT_BUFFER_LEN); - reader.read_to_end(&mut buf); - const BYTES: usize = <$type>::BITS as usize / 8; - Ok(buf - .chunks(BYTES) - .map(|slice| { - let Some(bytes): Option<&[u8; BYTES]> = slice.as_array() else { - unreachable!() - }; - <$type>::from_be_bytes(*bytes) - }) - .collect()) + $( + let $generic = $generic::decode(buf, ctx)?; + )+ + Ok(($($generic,)+)) } } }; } -macro_rules! impl_decode_tuples { - ($($generic: ident),+) => { - impl<Data, $($generic),+> Decode<Data> for ($($generic,)+) where $($generic: Decode<Data>,)+ { - #[allow(non_snake_case)] - fn decode(reader: &mut dyn Read, ctx: &Context<Data>) -> Result<Self> - where - Self: Sized { - $( - let $generic = $generic::decode(reader, ctx)?; - )+ - Ok(($($generic,)+)) - } - } - }; -} - -/// Read a value from a byte stream +/// Zero-copy decoding: reads directly from a byte slice pub trait Decode<Data> { - fn decode(reader: &mut dyn Read, ctx: &Context<Data>) -> Result<Self> + fn decode(buf: &mut &[u8], ctx: &Context<Data>) -> Result<Self> where Self: Sized; - // TODO : change for anything else than Vec - /// assume reader contains only the slice to decode - fn decode_slice(reader: &mut dyn Read, ctx: &Context<Data>) -> Result<Vec<Self>> + fn decode_slice(buf: &mut &[u8], ctx: &Context<Data>) -> Result<Vec<Self>> where Self: Sized, { - let mut buf = Vec::new(); - loop { - match Self::decode(reader, ctx) { - Ok(value) => buf.push(value), + let mut vec = Vec::new(); + while !buf.is_empty() { + match Self::decode(buf, ctx) { + Ok(value) => vec.push(value), Err(CodecError::IoError(err)) - if let std::io::ErrorKind::UnexpectedEof = err.kind() => + if err.kind() == std::io::ErrorKind::UnexpectedEof => { - return Ok(buf); + return Ok(vec); } Err(err) => return Err(err), } } + Ok(vec) } } -// ~ Decode arrays +// ── Decode arrays ─────────────────────────────────────────────────────── impl<Data, T: Decode<Data>> Decode<Data> for Vec<T> { - fn decode(reader: &mut dyn Read, ctx: &Context<Data>) -> Result<Self> + fn decode(buf: &mut &[u8], ctx: &Context<Data>) -> Result<Self> where Self: Sized, { - let len = usize::decode(reader, ctx)?; + let len = usize::decode(buf, ctx)?; let mut vec = Vec::with_capacity(len); for _ in 0..len { - vec.push(T::decode(reader, ctx)?); + vec.push(T::decode(buf, ctx)?); } Ok(vec) } } impl<Data, T: Decode<Data>> Decode<Data> for Option<T> { - /// Assume is always some - fn decode(reader: &mut dyn Read, ctx: &Context<Data>) -> Result<Self> + fn decode(buf: &mut &[u8], ctx: &Context<Data>) -> Result<Self> where Self: Sized, { - T::decode(reader, ctx).map(Some) + if buf.is_empty() { + return Ok(None); + } + T::decode(buf, ctx).map(Some) } } -// ~ Decode slices +// ── Decode slices ─────────────────────────────────────────────────────── impl<Data, T, const S: usize> Decode<Data> for [T; S] where T: Decode<Data> + Default + Copy, { - fn decode(reader: &mut dyn Read, ctx: &Context<Data>) -> Result<Self> + fn decode(buf: &mut &[u8], ctx: &Context<Data>) -> Result<Self> where Self: Sized, { - let slice = T::decode_slice(reader, ctx)?; + let slice = T::decode_slice(buf, ctx)?; let got = slice.len(); slice .as_array() @@ -157,7 +140,7 @@ impl<Data, T> Decode<Data> for &[T] where T: Decode<Data> + Default + Copy, { - fn decode(_: &mut dyn Read, _: &Context<Data>) -> Result<Self> + fn decode(_: &mut &[u8], _: &Context<Data>) -> Result<Self> where Self: Sized, { @@ -165,18 +148,22 @@ where } } -// ~ Decode set +// ── Decode set ────────────────────────────────────────────────────────── impl<Data, T> Decode<Data> for HashSet<T> where T: Decode<Data> + Eq + Hash, { - fn decode(reader: &mut dyn Read, ctx: &Context<Data>) -> Result<Self> + fn decode(buf: &mut &[u8], ctx: &Context<Data>) -> Result<Self> where Self: Sized, { - let slice = T::decode_slice(reader, ctx)?; - Ok(slice.into_iter().collect()) + let len = usize::decode(buf, ctx)?; + let mut set = HashSet::with_capacity(len); + for _ in 0..len { + set.insert(T::decode(buf, ctx)?); + } + Ok(set) } } @@ -184,43 +171,57 @@ impl<Data, T> Decode<Data> for BTreeSet<T> where T: Decode<Data> + Ord, { - fn decode(reader: &mut dyn Read, ctx: &Context<Data>) -> Result<Self> + fn decode(buf: &mut &[u8], ctx: &Context<Data>) -> Result<Self> where Self: Sized, { - let slice = T::decode_slice(reader, ctx)?; - Ok(slice.into_iter().collect()) + let len = usize::decode(buf, ctx)?; + let mut set = BTreeSet::new(); + for _ in 0..len { + set.insert(T::decode(buf, ctx)?); + } + Ok(set) } } -// ~ Decode misc +// ── Decode misc ───────────────────────────────────────────────────────── impl<Data, T> Decode<Data> for BinaryHeap<T> where T: Decode<Data> + Ord, { - fn decode(reader: &mut dyn Read, ctx: &Context<Data>) -> Result<Self> + fn decode(buf: &mut &[u8], ctx: &Context<Data>) -> Result<Self> where Self: Sized, { - let slice = T::decode_slice(reader, ctx)?; - Ok(BinaryHeap::from_iter(slice)) + let len = usize::decode(buf, ctx)?; + let mut heap = BinaryHeap::with_capacity(len); + for _ in 0..len { + heap.push(T::decode(buf, ctx)?); + } + Ok(heap) } } -// ~ Decode maps +// ── Decode maps ───────────────────────────────────────────────────────── impl<Data, K, V> Decode<Data> for HashMap<K, V> where K: Decode<Data> + Eq + Hash, V: Decode<Data>, { - fn decode(reader: &mut dyn Read, ctx: &Context<Data>) -> Result<Self> + fn decode(buf: &mut &[u8], ctx: &Context<Data>) -> Result<Self> where Self: Sized, { - let slice = <(K, V) as Decode<Data>>::decode_slice(reader, ctx)?; - Ok(slice.into_iter().collect()) + let len = usize::decode(buf, ctx)?; + let mut map = HashMap::with_capacity(len); + for _ in 0..len { + let key = K::decode(buf, ctx)?; + let val = V::decode(buf, ctx)?; + map.insert(key, val); + } + Ok(map) } } @@ -229,19 +230,25 @@ where K: Decode<Data> + Ord, V: Decode<Data>, { - fn decode(reader: &mut dyn Read, ctx: &Context<Data>) -> Result<Self> + fn decode(buf: &mut &[u8], ctx: &Context<Data>) -> Result<Self> where Self: Sized, { - let slice = <(K, V) as Decode<Data>>::decode_slice(reader, ctx)?; - Ok(slice.into_iter().collect()) + let len = usize::decode(buf, ctx)?; + let mut map = BTreeMap::new(); + for _ in 0..len { + let key = K::decode(buf, ctx)?; + let val = V::decode(buf, ctx)?; + map.insert(key, val); + } + Ok(map) } } -// ~ Decode string +// ── Decode string - requires length prefix ────────────────────────────── impl<Data> Decode<Data> for &str { - fn decode(_: &mut dyn Read, _: &Context<Data>) -> Result<Self> + fn decode(_: &mut &[u8], _: &Context<Data>) -> Result<Self> where Self: Sized, { @@ -250,17 +257,17 @@ impl<Data> Decode<Data> for &str { } impl<Data> Decode<Data> for String { - fn decode(reader: &mut dyn Read, _: &Context<Data>) -> Result<Self> + fn decode(buf: &mut &[u8], ctx: &Context<Data>) -> Result<Self> where Self: Sized, { - let mut bytes: Vec<u8> = Vec::new(); - reader.read_to_end(&mut bytes)?; - Ok(String::from_utf8_lossy(&bytes).to_string()) + // String must be length-prefixed - decode as LenPrefixed<u16, String> + crate::types::prefix::length::LenPrefixed::<u16, String>::decode(buf, ctx) + .map(|p| p.data().clone()) } } -// ~ Decode primitive +// ── Decode primitive ──────────────────────────────────────────────────── impl_decode!(u8); impl_decode!(u16); @@ -277,39 +284,43 @@ impl_decode!(i128); impl_decode!(isize); impl<Data> Decode<Data> for f64 { - fn decode(reader: &mut dyn Read, ctx: &Context<Data>) -> Result<Self> + fn decode(buf: &mut &[u8], ctx: &Context<Data>) -> Result<Self> where Self: Sized, { - let bits = u64::decode(reader, ctx)?; - let value = f64::from_bits(bits); - Ok(value) + let bits = u64::decode(buf, ctx)?; + Ok(f64::from_bits(bits)) } } impl<Data> Decode<Data> for f32 { - fn decode(reader: &mut dyn Read, ctx: &Context<Data>) -> Result<Self> + fn decode(buf: &mut &[u8], ctx: &Context<Data>) -> Result<Self> where Self: Sized, { - let bits = u32::decode(reader, ctx)?; - let value = f32::from_bits(bits); - Ok(value) + let bits = u32::decode(buf, ctx)?; + Ok(f32::from_bits(bits)) } } impl<Data> Decode<Data> for bool { - fn decode(reader: &mut dyn Read, _: &Context<Data>) -> Result<Self> + fn decode(buf: &mut &[u8], _: &Context<Data>) -> Result<Self> where Self: Sized, { - let mut byte = [0_u8]; - reader.read_exact(&mut byte)?; - Ok(byte[0] != 0) + if buf.is_empty() { + return Err(CodecError::IoError(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "insufficient bytes for bool", + ))); + } + let b = buf[0]; + *buf = &buf[1..]; + Ok(b != 0) } } -// ~ Decode tuple +// ── Decode tuple ──────────────────────────────────────────────────────── impl_decode_tuples!(A); impl_decode_tuples!(A, B); @@ -329,14 +340,14 @@ impl_decode_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O); impl_decode_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P); impl_decode_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q); -// ~ Decode pointer +// ── Decode pointer ────────────────────────────────────────────────────── impl<Data, T> Decode<Data> for std::sync::Arc<T> where T: Decode<Data>, { - fn decode(reader: &mut dyn Read, ctx: &Context<Data>) -> Result<Self> { - T::decode(reader, ctx).map(Arc::new) + fn decode(buf: &mut &[u8], ctx: &Context<Data>) -> Result<Self> { + T::decode(buf, ctx).map(Arc::new) } } @@ -344,11 +355,11 @@ impl<Data, T> Decode<Data> for Arc<[T]> where T: Decode<Data>, { - fn decode(reader: &mut dyn Read, ctx: &Context<Data>) -> Result<Self> + fn decode(buf: &mut &[u8], ctx: &Context<Data>) -> Result<Self> where Self: Sized, { - let slice = T::decode_slice(reader, ctx)?; + let slice = T::decode_slice(buf, ctx)?; Ok(slice.into()) } } |
