summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorzirkonya <zirkonya@iridium.lan>2026-07-26 22:22:32 +0200
committerzirkonya <zirkonya@iridium.lan>2026-07-26 22:22:32 +0200
commitda20363883b00aaf56b6ba068465d3e9bdf9fedf (patch)
tree792c6d0692392baf5ac380bafd7ea4a66b3346b6 /src
parent08c8e9d37f3e0f9a82c3792c1927967631de73cd (diff)
Add some prefixe
Diffstat (limited to 'src')
-rw-r--r--src/codec.rs1
-rw-r--r--src/codec/decode.rs88
-rw-r--r--src/codec/encode.rs55
-rw-r--r--src/codec/error.rs22
-rw-r--r--src/lib.rs2
-rw-r--r--src/types.rs (renamed from src/types/mod.rs)1
-rw-r--r--src/types/prefix.rs10
-rw-r--r--src/types/prefix/count.rs92
-rw-r--r--src/types/prefix/length.rs79
-rw-r--r--src/types/size.rs30
10 files changed, 367 insertions, 13 deletions
diff --git a/src/codec.rs b/src/codec.rs
index f11a88e..fcb18a3 100644
--- a/src/codec.rs
+++ b/src/codec.rs
@@ -2,6 +2,7 @@ use crate::codec::{decode::Decode, encode::Encode};
pub mod decode;
pub mod encode;
+pub mod error;
pub trait Codec: Encode + Decode {}
impl<T> Codec for T where T: Encode + Decode {}
diff --git a/src/codec/decode.rs b/src/codec/decode.rs
index 65f08b5..1059811 100644
--- a/src/codec/decode.rs
+++ b/src/codec/decode.rs
@@ -1,7 +1,91 @@
-use std::io::{self, Read};
+use std::{io::Read, sync::Arc};
+
+use crate::DEFAULT_BUFFER_LEN;
+
+macro_rules! impl_decode {
+ ($type: ty) => {
+ impl Decode for $type {
+ fn decode(reader: &mut dyn Read) -> crate::codec::error::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))
+ }
+ }
+ };
+}
pub trait Decode {
- fn decode(reader: &impl Read) -> io::Result<Self>
+ fn decode(reader: &mut dyn Read) -> crate::codec::error::Result<Self>
where
Self: Sized;
}
+
+impl Decode for bool {
+ fn decode(reader: &mut dyn Read) -> crate::codec::error::Result<Self>
+ where
+ Self: Sized,
+ {
+ let mut byte = [0_u8];
+ reader.read_exact(&mut byte)?;
+ Ok(byte[0] != 0)
+ }
+}
+
+impl Decode for Arc<[u8]> {
+ fn decode(reader: &mut dyn Read) -> crate::codec::error::Result<Self> {
+ let mut buf = Vec::with_capacity(DEFAULT_BUFFER_LEN);
+ reader.read_to_end(&mut buf)?;
+ Ok(Arc::<[u8]>::from(buf.into_boxed_slice()))
+ }
+}
+
+impl<const S: usize> Decode for [u8; S] {
+ fn decode(reader: &mut dyn Read) -> crate::codec::error::Result<Self>
+ where
+ Self: Sized,
+ {
+ let mut slice = [0_u8; S];
+ reader.read_exact(&mut slice)?;
+ Ok(slice)
+ }
+}
+
+impl_decode!(u8);
+impl_decode!(u16);
+impl_decode!(u32);
+impl_decode!(u64);
+impl_decode!(u128);
+impl_decode!(usize);
+
+impl_decode!(i8);
+impl_decode!(i16);
+impl_decode!(i32);
+impl_decode!(i64);
+impl_decode!(i128);
+impl_decode!(isize);
+
+impl Decode for f64 {
+ fn decode(reader: &mut dyn Read) -> crate::codec::error::Result<Self>
+ where
+ Self: Sized,
+ {
+ let bits = u64::decode(reader)?;
+ let value = f64::from_bits(bits);
+ Ok(value)
+ }
+}
+
+impl Decode for f32 {
+ fn decode(reader: &mut dyn Read) -> crate::codec::error::Result<Self>
+ where
+ Self: Sized,
+ {
+ let bits = u32::decode(reader)?;
+ let value = f32::from_bits(bits);
+ Ok(value)
+ }
+}
diff --git a/src/codec/encode.rs b/src/codec/encode.rs
index f23913b..a40f551 100644
--- a/src/codec/encode.rs
+++ b/src/codec/encode.rs
@@ -1,6 +1,55 @@
-use std::io::{self, Write};
+use crate::codec::error::Error;
+use std::{io::Write, sync::Arc};
+
+macro_rules! impl_encode {
+ ($t: ty) => {
+ impl Encode for $t {
+ fn encode(self, buffer: &mut dyn Write) -> Result<usize, Error> {
+ let size = buffer.write(&self.to_be_bytes())?;
+ Ok(size)
+ }
+ }
+ };
+}
pub trait Encode {
- fn encode(&self, write: &mut dyn Write) -> io::Result<usize>;
- fn encoded_size(&self) -> Option<usize>;
+ fn encode(self, buffer: &mut dyn Write) -> Result<usize, Error>;
+}
+
+impl Encode for bool {
+ fn encode(self, buffer: &mut dyn Write) -> Result<usize, Error> {
+ let size = buffer.write(&[self as u8])?;
+ Ok(size)
+ }
+}
+
+impl Encode for Arc<[u8]> {
+ fn encode(self, buffer: &mut dyn Write) -> Result<usize, Error> {
+ let len = buffer.write(&self)?;
+ Ok(len)
+ }
}
+
+impl<const S: usize> Encode for [u8; S] {
+ fn encode(self, buffer: &mut dyn Write) -> Result<usize, Error> {
+ let len = buffer.write(&self)?;
+ Ok(len)
+ }
+}
+
+impl_encode!(u8);
+impl_encode!(u16);
+impl_encode!(u32);
+impl_encode!(u64);
+impl_encode!(u128);
+impl_encode!(usize);
+
+impl_encode!(i8);
+impl_encode!(i16);
+impl_encode!(i32);
+impl_encode!(i64);
+impl_encode!(i128);
+impl_encode!(isize);
+
+impl_encode!(f32);
+impl_encode!(f64);
diff --git a/src/codec/error.rs b/src/codec/error.rs
new file mode 100644
index 0000000..6639c98
--- /dev/null
+++ b/src/codec/error.rs
@@ -0,0 +1,22 @@
+use std::fmt::Display;
+
+#[derive(Debug)]
+pub enum Error {
+ IoError(std::io::Error),
+}
+
+impl std::error::Error for Error {}
+
+impl Display for Error {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{self:?}")
+ }
+}
+
+pub type Result<T> = core::result::Result<T, Error>;
+
+impl From<std::io::Error> for Error {
+ fn from(value: std::io::Error) -> Self {
+ Self::IoError(value)
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 8ffd97a..24c2033 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,2 +1,4 @@
pub mod codec;
pub mod types;
+
+pub(crate) const DEFAULT_BUFFER_LEN: usize = 2048;
diff --git a/src/types/mod.rs b/src/types.rs
index 5a68507..b1575b5 100644
--- a/src/types/mod.rs
+++ b/src/types.rs
@@ -1 +1,2 @@
pub mod prefix;
+pub mod size;
diff --git a/src/types/prefix.rs b/src/types/prefix.rs
index e60c23b..67cf047 100644
--- a/src/types/prefix.rs
+++ b/src/types/prefix.rs
@@ -1,8 +1,2 @@
-use std::marker::PhantomData;
-
-use crate::codec::Codec;
-
-pub struct LenPrefixed<L: Codec, D: Codec> {
- data: D,
- _len: PhantomData<L>,
-}
+pub mod count;
+pub mod length;
diff --git a/src/types/prefix/count.rs b/src/types/prefix/count.rs
new file mode 100644
index 0000000..7495660
--- /dev/null
+++ b/src/types/prefix/count.rs
@@ -0,0 +1,92 @@
+use std::{io::Read, marker::PhantomData};
+
+use crate::{
+ codec::{Codec, decode::Decode, encode::Encode},
+ types::size::Size,
+};
+
+pub struct CountPrefix<I: Codec, L: Codec + Size, D: IntoIterator<Item = I>> {
+ data: D,
+ _len: PhantomData<L>,
+}
+
+impl<I, L, D> CountPrefix<I, L, D>
+where
+ I: Codec,
+ L: Codec + Size,
+ D: IntoIterator<Item = I>,
+{
+ pub fn new(data: D) -> Self {
+ Self {
+ data,
+ _len: PhantomData,
+ }
+ }
+}
+
+impl<I, L, D> AsRef<D> for CountPrefix<I, L, D>
+where
+ I: Codec,
+ L: Codec + Size,
+ D: IntoIterator<Item = I>,
+{
+ fn as_ref(&self) -> &D {
+ &self.data
+ }
+}
+
+impl<I, L, D> AsMut<D> for CountPrefix<I, L, D>
+where
+ I: Codec,
+ L: Codec + Size,
+ D: IntoIterator<Item = I>,
+{
+ fn as_mut(&mut self) -> &mut D {
+ &mut self.data
+ }
+}
+
+impl<I, L, D> Encode for CountPrefix<I, L, D>
+where
+ I: Codec,
+ L: Codec + Size,
+ D: IntoIterator<Item = I>,
+{
+ fn encode(
+ self,
+ buffer: &mut dyn std::io::prelude::Write,
+ ) -> Result<usize, crate::codec::error::Error>
+ where
+ Self: Sized,
+ {
+ let vec = self.data.into_iter().collect::<Vec<I>>();
+ let mut l = L::from_size(vec.len()).encode(buffer)?;
+ for item in vec {
+ l += item.encode(buffer)?;
+ }
+ Ok(l)
+ }
+}
+
+impl<I, L, D> Decode for CountPrefix<I, L, D>
+where
+ I: Codec,
+ L: Codec + Size,
+ D: IntoIterator<Item = I> + FromIterator<I>,
+{
+ fn decode(reader: &mut dyn Read) -> crate::codec::error::Result<Self>
+ where
+ Self: Sized,
+ {
+ let len = L::decode(reader)?.as_size();
+ let mut data = Vec::with_capacity(len);
+ for _ in 0..len {
+ let item = I::decode(reader)?;
+ data.push(item);
+ }
+ Ok(Self {
+ data: D::from_iter(data.into_iter()),
+ _len: PhantomData,
+ })
+ }
+}
diff --git a/src/types/prefix/length.rs b/src/types/prefix/length.rs
new file mode 100644
index 0000000..c825375
--- /dev/null
+++ b/src/types/prefix/length.rs
@@ -0,0 +1,79 @@
+use std::{io::Write, marker::PhantomData};
+
+use crate::{
+ DEFAULT_BUFFER_LEN,
+ codec::{self, Codec, decode::Decode, encode::Encode},
+ types::size::Size,
+};
+
+pub struct LenPrefixed<L: Codec + Size, D: Codec> {
+ data: D,
+ _len: PhantomData<L>,
+}
+
+impl<L, D> LenPrefixed<L, D>
+where
+ L: Codec + Size,
+ D: Codec,
+{
+ pub fn new(data: D) -> Self {
+ Self {
+ data,
+ _len: PhantomData,
+ }
+ }
+}
+
+impl<L, D> AsRef<D> for LenPrefixed<L, D>
+where
+ L: Codec + Size,
+ D: Codec,
+{
+ fn as_ref(&self) -> &D {
+ &self.data
+ }
+}
+
+impl<L, D> AsMut<D> for LenPrefixed<L, D>
+where
+ L: Codec + Size,
+ D: Codec,
+{
+ fn as_mut(&mut self) -> &mut D {
+ &mut self.data
+ }
+}
+
+impl<L, D> Encode for LenPrefixed<L, D>
+where
+ L: Codec + Size,
+ D: Codec,
+{
+ fn encode(self, writer: &mut dyn Write) -> Result<usize, codec::error::Error> {
+ let mut buf = Vec::with_capacity(DEFAULT_BUFFER_LEN);
+ self.data.encode(&mut buf)?;
+ let mut l = L::from_size(buf.len()).encode(writer)?;
+ l += writer.write(&buf)?;
+ Ok(l)
+ }
+}
+
+impl<L, D> Decode for LenPrefixed<L, D>
+where
+ L: Codec + Size,
+ D: Codec,
+{
+ fn decode(reader: &mut dyn std::io::prelude::Read) -> crate::codec::error::Result<Self>
+ where
+ Self: Sized,
+ {
+ let len = L::decode(reader)?.as_size();
+ let mut limited = vec![0_u8; len];
+ reader.read_exact(&mut limited)?;
+ let data = D::decode(&mut &limited[..])?;
+ Ok(Self {
+ data,
+ _len: PhantomData,
+ })
+ }
+}
diff --git a/src/types/size.rs b/src/types/size.rs
new file mode 100644
index 0000000..6bce689
--- /dev/null
+++ b/src/types/size.rs
@@ -0,0 +1,30 @@
+macro_rules! impl_size {
+ ($t: ty) => {
+ impl Size for $t {
+ fn from_size(size: usize) -> Self {
+ size as $t
+ }
+
+ fn as_size(self) -> usize {
+ self as usize
+ }
+ }
+ };
+}
+
+pub trait Size {
+ fn from_size(size: usize) -> Self;
+ fn as_size(self) -> usize;
+}
+
+impl_size!(u8);
+impl_size!(u16);
+impl_size!(u32);
+impl_size!(u64);
+impl_size!(u128);
+
+impl_size!(i8);
+impl_size!(i16);
+impl_size!(i32);
+impl_size!(i64);
+impl_size!(i128);