From bf9b81e669f4ce98c8d58df5d776ae90726d7ec2 Mon Sep 17 00:00:00 2001 From: zirkonya Date: Sat, 29 Aug 2026 22:11:23 +0200 Subject: Add transport layer --- src/codec/encode.rs | 304 +++++++++++++++++++++++++++++++++++++++++++++------- src/codec/error.rs | 35 ++---- 2 files changed, 275 insertions(+), 64 deletions(-) (limited to 'src/codec') diff --git a/src/codec/encode.rs b/src/codec/encode.rs index b9ac961..ae5eb4e 100644 --- a/src/codec/encode.rs +++ b/src/codec/encode.rs @@ -1,83 +1,270 @@ //! Encoding: writing protocol values into a byte stream. -use crate::codec::error::Error; +use crate::codec::error::Result; use crate::context::Context; -use std::{io::Write, sync::Arc}; +use std::{ + collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}, + io::Write, +}; macro_rules! impl_encode { + (u8) => { + impl Encode for u8 { + /// write number using big endian + fn encode(&self, buffer: &mut dyn Write, _: &Context) -> Result { + let size = buffer.write(&self.to_be_bytes())?; + Ok(size) + } + + /// write raw bytes + fn encode_slice( + slice: &[Self], + buffer: &mut dyn Write, + _: &Context, + ) -> Result { + buffer.write(slice).map_err(Into::into) + } + } + }; ($t: ty) => { impl Encode for $t { /// write number using big endian - fn encode(&self, buffer: &mut dyn Write, _: &Context) -> Result { + fn encode(&self, buffer: &mut dyn Write, _: &Context) -> Result { let size = buffer.write(&self.to_be_bytes())?; Ok(size) } + + fn encode_slice( + slice: &[Self], + buffer: &mut dyn Write, + _: &Context, + ) -> Result { + let len = buffer.write( + &slice + .iter() + .flat_map(|n| n.to_be_bytes()) + .collect::>(), + )?; + Ok(len) + } + } + }; +} + +macro_rules! impl_encode_tuples { + ($($generic: ident),+) => { + impl Encode for ($($generic,)+) + where + $($generic: Encode),+ + { + #[allow(non_snake_case)] + fn encode(&self, buffer: &mut dyn Write, ctx: &Context) -> Result { + let ($($generic,)+): &($($generic,)+) = self; + let mut len = 0; + $(len += $generic.encode(buffer, ctx)?;)+ + Ok(len) + } } }; } /// Write a value into a byte stream pub trait Encode { - fn encode(&self, buffer: &mut dyn Write, ctx: &Context) -> Result; + fn encode(&self, buffer: &mut dyn Write, ctx: &Context) -> Result; + fn encode_slice(slice: &[Self], buffer: &mut dyn Write, ctx: &Context) -> Result + where + Self: Sized, + { + let mut len = 0; + for item in slice { + len += item.encode(buffer, ctx)?; + } + Ok(len) + } } -impl Encode for bool { - fn encode(&self, buffer: &mut dyn Write, _: &Context) -> Result { - let size = buffer.write(&[*self as u8])?; - Ok(size) +// ~ Encode arrays + +impl> Encode for Vec { + /// Encode each element of Vec + /// use `CountPrefix` to prefix the vector with number of elements + /// use `LenPrefix` to prefix the vector with encoded byte size + fn encode(&self, buffer: &mut dyn Write, ctx: &Context) -> Result { + T::encode_slice(self, buffer, ctx) } } -impl> Encode for Option { - /// Encode `T` if Some(T) or do nothing if None - fn encode(&self, buffer: &mut dyn Write, ctx: &Context) -> Result { - match self { - Some(val) => { - let size = val.encode(buffer, ctx)?; - Ok(size) - } - None => Ok(0), - } +impl> Encode for VecDeque { + /// Encode each element of VecDeque + /// use `CountPrefix` to prefix the VecDeque with number of elements + /// use `LenPrefix` to prefix the VecDeque with encoded byte size + fn encode(&self, buffer: &mut dyn Write, ctx: &Context) -> Result { + let (front, _) = self.as_slices(); + T::encode_slice(front, buffer, ctx) } } -impl> Encode for Vec { - /// Encode each element of vector - /// use `CountPrefix` to prefix the vector with number of elements - /// use `LenPrefix` to prefix the vector with encoded byte size - fn encode(&self, buffer: &mut dyn Write, ctx: &Context) -> Result { - let mut size = 0; - for item in self { - size += item.encode(buffer, ctx)?; - } - Ok(size) +impl> Encode for LinkedList +where + T: Clone, +{ + /// Encode each element of LinkedList (use clone..) + /// use `CountPrefix` to prefix the LinkedList with number of elements + /// use `LenPrefix` to prefix the LinkedList with encoded byte size + fn encode(&self, buffer: &mut dyn Write, ctx: &Context) -> Result { + let mut view = Vec::with_capacity(self.len()); + view.extend(self.iter().cloned()); + T::encode_slice(&view, buffer, ctx) + } +} + +// ~ Encode slices + +impl> Encode for &[T] { + /// Encode each element of slice (use clone..) + /// use `CountPrefix` to prefix the slice with number of elements + /// use `LenPrefix` to prefix the slice with encoded byte size + fn encode(&self, buffer: &mut dyn Write, ctx: &Context) -> Result { + T::encode_slice(self, buffer, ctx) + } +} + +impl, const S: usize> Encode for [T; S] { + /// Encode each element of slice (use clone..) + /// use `CountPrefix` to prefix the slice with number of elements + /// use `LenPrefix` to prefix the slice with encoded byte size + fn encode(&self, buffer: &mut dyn Write, ctx: &Context) -> Result { + T::encode_slice(self, buffer, ctx) + } +} + +impl> Encode for [T] { + /// Encode each element of slice (use clone..) + /// use `CountPrefix` to prefix the slice with number of elements + /// use `LenPrefix` to prefix the slice with encoded byte size + fn encode(&self, buffer: &mut dyn Write, ctx: &Context) -> Result { + T::encode_slice(self, buffer, ctx) } } +// ~ Encode set + +impl> Encode for HashSet +where + T: Clone, +{ + /// Encode each element of HashSet (use clone..) + /// use `CountPrefix` to prefix the HashSet with number of elements + /// use `LenPrefix` to prefix the HashSet with encoded byte size + fn encode(&self, buffer: &mut dyn Write, ctx: &Context) -> Result { + let mut view = Vec::with_capacity(self.len()); + view.extend(self.iter().cloned()); + T::encode_slice(&view, buffer, ctx) + } +} + +impl> Encode for BTreeSet +where + T: Clone, +{ + /// Encode each element of BTreeSet (use clone..) + /// use `CountPrefix` to prefix the BTreeSet with number of elements + /// use `LenPrefix` to prefix the BTreeSet with encoded byte size + fn encode(&self, buffer: &mut dyn Write, ctx: &Context) -> Result { + let mut view = Vec::with_capacity(self.len()); + view.extend(self.iter().cloned()); + T::encode_slice(&view, buffer, ctx) + } +} + +// ~ Encode misc + +impl Encode for BinaryHeap +where + T: Encode, +{ + fn encode(&self, buffer: &mut dyn Write, ctx: &Context) -> Result { + T::encode_slice(self.as_slice(), buffer, ctx) + } +} + +// ~ Encode maps + +impl Encode for HashMap +where + K: Encode + Clone, + V: Encode + Clone, +{ + /// Encode each element of HashMap (use clone..) + /// use `CountPrefix` to prefix the HashMap with number of pairs + /// use `LenPrefix` to prefix the HashMap with encoded byte size + fn encode(&self, buffer: &mut dyn Write, ctx: &Context) -> Result { + let slice: Vec<(K, V)> = self.clone().into_iter().collect(); + <(K, V) as Encode>::encode_slice(&slice, buffer, ctx) + } +} + +impl Encode for BTreeMap +where + K: Encode + Clone, + V: Encode + Clone, +{ + /// Encode each element of BTreeMap (use clone..) + /// use `CountPrefix` to prefix the BTreeMap with number of pairs + /// use `LenPrefix` to prefix the BTreeMap with encoded byte size + fn encode(&self, buffer: &mut dyn Write, ctx: &Context) -> Result { + let slice: Vec<(K, V)> = self.clone().into_iter().collect(); + <(K, V) as Encode>::encode_slice(&slice, buffer, ctx) + } +} + +// ~ Encode string impl Encode for String { /// Encode the string using utf8 /// use `CountPrefix` to prefix the string with char length /// use `LenPrefix` to prefix the string with utf8 bytes length - fn encode(&self, buffer: &mut dyn Write, _: &Context) -> Result { + fn encode(&self, buffer: &mut dyn Write, _: &Context) -> Result { let utf8 = self.as_bytes(); buffer.write_all(utf8)?; Ok(utf8.len()) } } -impl Encode for Arc<[u8]> { - /// write raw slice into the buffer - /// use `LenPrefix` to prefix with byte length - fn encode(&self, buffer: &mut dyn Write, _: &Context) -> Result { - let len = buffer.write(self)?; - Ok(len) +impl Encode for &str { + /// Encode the string using utf8 + /// use `CountPrefix` to prefix the string with char length + /// use `LenPrefix` to prefix the string with utf8 bytes length + fn encode(&self, buffer: &mut dyn Write, _: &Context) -> Result { + let utf8 = self.as_bytes(); + buffer.write_all(utf8)?; + Ok(utf8.len()) } } -impl Encode for [u8; S] { - /// write raw slice into the buffer - /// use `LenPrefix` to prefix with byte length - fn encode(&self, buffer: &mut dyn Write, _: &Context) -> Result { - let len = buffer.write(self)?; +impl> Encode for Option { + /// Encode `T` if Some(T) or do nothing if None + fn encode(&self, buffer: &mut dyn Write, ctx: &Context) -> Result { + match self { + Some(val) => { + let size = val.encode(buffer, ctx)?; + Ok(size) + } + None => Ok(0), + } + } +} + +// ~ Encode primitive +impl Encode for bool { + fn encode(&self, buffer: &mut dyn Write, _: &Context) -> Result { + let size = buffer.write(&[*self as u8])?; + Ok(size) + } + + fn encode_slice(slice: &[Self], buffer: &mut dyn Write, _: &Context) -> Result + where + Self: Sized, + { + let len = buffer.write(&slice.iter().map(|n| *n as u8).collect::>())?; Ok(len) } } @@ -96,5 +283,42 @@ impl_encode!(i64); impl_encode!(i128); impl_encode!(isize); +#[cfg(feature = "f16")] +impl_encode!(f16); impl_encode!(f32); impl_encode!(f64); +#[cfg(feature = "f128")] +impl_encode!(f128); + +// ~ Encode tuple + +impl Encode for () { + fn encode(&self, _: &mut dyn Write, _: &Context) -> Result { + Ok(0) + } + + fn encode_slice(_: &[Self], _: &mut dyn Write, _: &Context) -> Result + where + Self: Sized, + { + Ok(0) + } +} + +impl_encode_tuples!(A); +impl_encode_tuples!(A, B); +impl_encode_tuples!(A, B, C); +impl_encode_tuples!(A, B, C, D); +impl_encode_tuples!(A, B, C, D, E); +impl_encode_tuples!(A, B, C, D, E, F); +impl_encode_tuples!(A, B, C, D, E, F, G); +impl_encode_tuples!(A, B, C, D, E, F, G, H); +impl_encode_tuples!(A, B, C, D, E, F, G, H, I); +impl_encode_tuples!(A, B, C, D, E, F, G, H, I, J); +impl_encode_tuples!(A, B, C, D, E, F, G, H, I, J, K); +impl_encode_tuples!(A, B, C, D, E, F, G, H, I, J, K, L); +impl_encode_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M); +impl_encode_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N); +impl_encode_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O); +impl_encode_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P); +impl_encode_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q); diff --git a/src/codec/error.rs b/src/codec/error.rs index c1bd4f7..7d88d55 100644 --- a/src/codec/error.rs +++ b/src/codec/error.rs @@ -1,37 +1,24 @@ -use std::fmt::Display; +use thiserror::Error; -// TODO : better error (using thiserror) +#[derive(Debug, Error)] +pub enum CodecError { + #[error("io error: {0}")] + IoError(#[from] std::io::Error), -#[derive(Debug)] -pub enum Error { - IoError(std::io::Error), + #[error("{0}")] Custom(String), } -impl std::error::Error for Error {} +pub type Result = core::result::Result; -impl Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{self:?}") - } -} - -pub type Result = core::result::Result; - -impl From for Error { - fn from(value: std::io::Error) -> Self { - Self::IoError(value) +impl From<&str> for CodecError { + fn from(value: &str) -> Self { + Self::Custom(value.to_string()) } } -impl From for Error { +impl From for CodecError { fn from(value: String) -> Self { Self::Custom(value) } } - -impl From<&str> for Error { - fn from(value: &str) -> Self { - Self::Custom(value.to_string()) - } -} -- cgit v1.2.3