summaryrefslogtreecommitdiff
path: root/src/codec/encode.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/codec/encode.rs')
-rw-r--r--src/codec/encode.rs336
1 files changed, 188 insertions, 148 deletions
diff --git a/src/codec/encode.rs b/src/codec/encode.rs
index 7463995..735aa70 100644
--- a/src/codec/encode.rs
+++ b/src/codec/encode.rs
@@ -1,49 +1,36 @@
-//! Encoding: writing protocol values into a byte stream.
use crate::codec::error::Result;
use crate::context::Context;
-use std::{
- collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque},
- io::Write,
-};
+use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque};
macro_rules! impl_encode {
- (u8) => {
- impl<Data> Encode<Data> for u8 {
- /// write number using big endian
- fn encode(&self, buffer: &mut dyn Write, _: &Context<Data>) -> Result<usize> {
- let size = buffer.write(&self.to_be_bytes())?;
- Ok(size)
+ ($t:ty) => {
+ impl<Data> Encode<Data> for $t {
+ fn encode(&self, buffer: &mut Vec<u8>, _: &Context<Data>) -> Result<usize> {
+ buffer.extend_from_slice(&self.to_be_bytes());
+ Ok(std::mem::size_of::<$t>())
}
- /// write raw bytes
- fn encode_slice(
- slice: &[Self],
- buffer: &mut dyn Write,
- _: &Context<Data>,
- ) -> Result<usize> {
- buffer.write(slice).map_err(Into::into)
- }
- }
- };
- ($t: ty) => {
- impl<Data> Encode<Data> for $t {
- /// write number using big endian
- fn encode(&self, buffer: &mut dyn Write, _: &Context<Data>) -> Result<usize> {
- let size = buffer.write(&self.to_be_bytes())?;
- Ok(size)
+ fn encode_slice(slice: &[Self], buffer: &mut Vec<u8>, _: &Context<Data>) -> Result<usize>
+ where
+ Self: Sized,
+ {
+ let len = slice.len() * std::mem::size_of::<$t>();
+ buffer.reserve(len);
+ for item in slice {
+ buffer.extend_from_slice(&item.to_be_bytes());
+ }
+ Ok(len)
}
- fn encode_slice(
- slice: &[Self],
- buffer: &mut dyn Write,
- _: &Context<Data>,
- ) -> Result<usize> {
- let len = buffer.write(
- &slice
- .iter()
- .flat_map(|n| n.to_be_bytes())
- .collect::<Box<[u8]>>(),
- )?;
+ fn encode_iter<'a, I>(iter: I, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize>
+ where
+ Self: 'a + Sized,
+ I: IntoIterator<Item = &'a Self>,
+ {
+ let mut len = 0;
+ for item in iter {
+ len += item.encode(buffer, ctx)?;
+ }
Ok(len)
}
}
@@ -57,7 +44,7 @@ macro_rules! impl_encode_tuples {
$($generic: Encode<Data>),+
{
#[allow(non_snake_case)]
- fn encode(&self, buffer: &mut dyn Write, ctx: &Context<Data>) -> Result<usize> {
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
let ($($generic,)+): &($($generic,)+) = self;
let mut len = 0;
$(len += $generic.encode(buffer, ctx)?;)+
@@ -67,10 +54,11 @@ macro_rules! impl_encode_tuples {
};
}
-/// Write a value into a byte stream
+/// Zero-copy encoding: writes directly into a byte buffer
pub trait Encode<Data> {
- fn encode(&self, buffer: &mut dyn Write, ctx: &Context<Data>) -> Result<usize>;
- fn encode_slice(slice: &[Self], buffer: &mut dyn Write, ctx: &Context<Data>) -> Result<usize>
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize>;
+
+ fn encode_slice(slice: &[Self], buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize>
where
Self: Sized,
{
@@ -80,204 +68,257 @@ pub trait Encode<Data> {
}
Ok(len)
}
+
+ fn encode_iter<'a, I>(iter: I, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize>
+ where
+ Self: 'a + Sized,
+ I: IntoIterator<Item = &'a Self>,
+ {
+ let mut len = 0;
+ for item in iter {
+ len += item.encode(buffer, ctx)?;
+ }
+ Ok(len)
+ }
}
-// ~ Encode arrays
+// ── Encode arrays ───────────────────────────────────────────────────────
impl<Data, T: Encode<Data>> Encode<Data> for Vec<T> {
- /// 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<Data>) -> Result<usize> {
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
T::encode_slice(self, buffer, ctx)
}
}
impl<Data, T: Encode<Data>> Encode<Data> for VecDeque<T> {
- /// 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<Data>) -> Result<usize> {
- let (front, _) = self.as_slices();
- T::encode_slice(front, buffer, ctx)
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
+ let (front, back) = self.as_slices();
+ let mut len = 0;
+ len += T::encode_slice(front, buffer, ctx)?;
+ len += T::encode_slice(back, buffer, ctx)?;
+ Ok(len)
}
}
-impl<Data, T: Encode<Data>> Encode<Data> for LinkedList<T>
-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<Data>) -> Result<usize> {
- let mut view = Vec::with_capacity(self.len());
- view.extend(self.iter().cloned());
- T::encode_slice(&view, buffer, ctx)
+impl<Data, T: Encode<Data>> Encode<Data> for LinkedList<T> {
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
+ let mut len = 0;
+ for item in self {
+ len += item.encode(buffer, ctx)?;
+ }
+ Ok(len)
}
}
-// ~ Encode slices
+// ── Encode slices ───────────────────────────────────────────────────────
impl<Data, T: Encode<Data>> Encode<Data> 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<Data>) -> Result<usize> {
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
T::encode_slice(self, buffer, ctx)
}
}
impl<Data, T: Encode<Data>, const S: usize> Encode<Data> 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<Data>) -> Result<usize> {
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
T::encode_slice(self, buffer, ctx)
}
}
impl<Data, T: Encode<Data>> Encode<Data> 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<Data>) -> Result<usize> {
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
+ T::encode_slice(self, buffer, ctx)
+ }
+}
+
+// ── Encode references to collections ────────────────────────────────────
+
+impl<Data, T: Encode<Data>> Encode<Data> for &Vec<T> {
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
T::encode_slice(self, buffer, ctx)
}
}
-// ~ Encode set
+impl<Data, T: Encode<Data>> Encode<Data> for &VecDeque<T> {
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
+ let (front, back) = self.as_slices();
+ let mut len = 0;
+ len += T::encode_slice(front, buffer, ctx)?;
+ len += T::encode_slice(back, buffer, ctx)?;
+ Ok(len)
+ }
+}
-impl<Data, T: Encode<Data>> Encode<Data> for HashSet<T>
+impl<Data, T: Encode<Data>> Encode<Data> for &LinkedList<T> {
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
+ let mut len = 0;
+ for item in (*self).iter() {
+ len += item.encode(buffer, ctx)?;
+ }
+ Ok(len)
+ }
+}
+
+impl<Data, T: Encode<Data>> Encode<Data> for &HashSet<T> {
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
+ T::encode_iter(self.iter(), buffer, ctx)
+ }
+}
+
+impl<Data, T: Encode<Data>> Encode<Data> for &BTreeSet<T> {
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
+ T::encode_iter(self.iter(), buffer, ctx)
+ }
+}
+
+impl<Data, T: Encode<Data>> Encode<Data> for &BinaryHeap<T> {
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
+ T::encode_slice(self.as_slice(), buffer, ctx)
+ }
+}
+
+impl<Data, K, V> Encode<Data> for &HashMap<K, V>
where
- T: Clone,
+ K: Encode<Data>,
+ V: Encode<Data>,
{
- /// 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<Data>) -> Result<usize> {
- let mut view = Vec::with_capacity(self.len());
- view.extend(self.iter().cloned());
- T::encode_slice(&view, buffer, ctx)
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
+ let mut len = 0;
+ for (k, v) in (*self).iter() {
+ len += k.encode(buffer, ctx)?;
+ len += v.encode(buffer, ctx)?;
+ }
+ Ok(len)
}
}
-impl<Data, T: Encode<Data>> Encode<Data> for BTreeSet<T>
+impl<Data, K, V> Encode<Data> for &BTreeMap<K, V>
where
- T: Clone,
+ K: Encode<Data>,
+ V: Encode<Data>,
{
- /// 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<Data>) -> Result<usize> {
- let mut view = Vec::with_capacity(self.len());
- view.extend(self.iter().cloned());
- T::encode_slice(&view, buffer, ctx)
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
+ let mut len = 0;
+ for (k, v) in (*self).iter() {
+ len += k.encode(buffer, ctx)?;
+ len += v.encode(buffer, ctx)?;
+ }
+ Ok(len)
}
}
-// ~ Encode misc
+// ── Encode set (owned) ──────────────────────────────────────────────────
+
+impl<Data, T: Encode<Data>> Encode<Data> for HashSet<T> {
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
+ T::encode_iter(self.iter(), buffer, ctx)
+ }
+}
+
+impl<Data, T: Encode<Data>> Encode<Data> for BTreeSet<T> {
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
+ T::encode_iter(self.iter(), buffer, ctx)
+ }
+}
+
+// ── Encode misc ─────────────────────────────────────────────────────────
impl<Data, T> Encode<Data> for BinaryHeap<T>
where
T: Encode<Data>,
{
- fn encode(&self, buffer: &mut dyn Write, ctx: &Context<Data>) -> Result<usize> {
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
T::encode_slice(self.as_slice(), buffer, ctx)
}
}
-// ~ Encode maps
+// ── Encode maps (owned) ─────────────────────────────────────────────────
impl<Data, K, V> Encode<Data> for HashMap<K, V>
where
- K: Encode<Data> + Clone,
- V: Encode<Data> + Clone,
+ K: Encode<Data>,
+ V: Encode<Data>,
{
- /// 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<Data>) -> Result<usize> {
- let slice: Vec<(K, V)> = self.clone().into_iter().collect();
- <(K, V) as Encode<Data>>::encode_slice(&slice, buffer, ctx)
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
+ let mut len = 0;
+ for (k, v) in self {
+ len += k.encode(buffer, ctx)?;
+ len += v.encode(buffer, ctx)?;
+ }
+ Ok(len)
}
}
impl<Data, K, V> Encode<Data> for BTreeMap<K, V>
where
- K: Encode<Data> + Clone,
- V: Encode<Data> + Clone,
+ K: Encode<Data>,
+ V: Encode<Data>,
{
- /// 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<Data>) -> Result<usize> {
- let slice: Vec<(K, V)> = self.clone().into_iter().collect();
- <(K, V) as Encode<Data>>::encode_slice(&slice, buffer, ctx)
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
+ let mut len = 0;
+ for (k, v) in self {
+ len += k.encode(buffer, ctx)?;
+ len += v.encode(buffer, ctx)?;
+ }
+ Ok(len)
}
}
-// ~ Encode string
+// ── Encode string ───────────────────────────────────────────────────────
+
impl<Data> Encode<Data> 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<Data>) -> Result<usize> {
+ fn encode(&self, buffer: &mut Vec<u8>, _: &Context<Data>) -> Result<usize> {
let utf8 = self.as_bytes();
- buffer.write_all(utf8)?;
+ buffer.extend_from_slice(utf8);
Ok(utf8.len())
}
}
impl<Data> Encode<Data> 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<Data>) -> Result<usize> {
+ fn encode(&self, buffer: &mut Vec<u8>, _: &Context<Data>) -> Result<usize> {
let utf8 = self.as_bytes();
- buffer.write_all(utf8)?;
+ buffer.extend_from_slice(utf8);
Ok(utf8.len())
}
}
impl<Data, T: Encode<Data>> Encode<Data> for Option<T> {
- /// Encode `T` if Some(T) or do nothing if None
- fn encode(&self, buffer: &mut dyn Write, ctx: &Context<Data>) -> Result<usize> {
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
match self {
- Some(val) => {
- let size = val.encode(buffer, ctx)?;
- Ok(size)
- }
+ Some(val) => val.encode(buffer, ctx),
None => Ok(0),
}
}
}
-// ~ Encode primitive
+// ── Encode primitive ────────────────────────────────────────────────────
+
impl<Data> Encode<Data> for bool {
- fn encode(&self, buffer: &mut dyn Write, _: &Context<Data>) -> Result<usize> {
- let size = buffer.write(&[*self as u8])?;
- Ok(size)
+ fn encode(&self, buffer: &mut Vec<u8>, _: &Context<Data>) -> Result<usize> {
+ buffer.push(*self as u8);
+ Ok(1)
}
- fn encode_slice(slice: &[Self], buffer: &mut dyn Write, _: &Context<Data>) -> Result<usize>
+ fn encode_slice(slice: &[Self], buffer: &mut Vec<u8>, _: &Context<Data>) -> Result<usize>
where
Self: Sized,
{
- let len = buffer.write(&slice.iter().map(|n| *n as u8).collect::<Box<[u8]>>())?;
+ let len = slice.len();
+ buffer.reserve(len);
+ for &b in slice {
+ buffer.push(b as u8);
+ }
Ok(len)
}
}
-// ~ Encode pointer
+// ── Encode pointer ──────────────────────────────────────────────────────
impl<Data, T> Encode<Data> for std::sync::Arc<T>
where
T: Encode<Data>,
{
- fn encode(&self, buffer: &mut dyn Write, ctx: &Context<Data>) -> Result<usize> {
- let data = self.as_ref();
- data.encode(buffer, ctx)
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
+ self.as_ref().encode(buffer, ctx)
}
}
@@ -285,9 +326,8 @@ impl<Data, T> Encode<Data> for std::sync::Arc<[T]>
where
T: Encode<Data>,
{
- fn encode(&self, buffer: &mut dyn Write, ctx: &Context<Data>) -> Result<usize> {
- let data = self.as_ref();
- data.encode(buffer, ctx)
+ fn encode(&self, buffer: &mut Vec<u8>, ctx: &Context<Data>) -> Result<usize> {
+ self.as_ref().encode(buffer, ctx)
}
}
@@ -312,14 +352,14 @@ impl_encode!(f64);
#[cfg(feature = "f128")]
impl_encode!(f128);
-// ~ Encode tuple
+// ── Encode tuple ────────────────────────────────────────────────────────
impl<Data> Encode<Data> for () {
- fn encode(&self, _: &mut dyn Write, _: &Context<Data>) -> Result<usize> {
+ fn encode(&self, _: &mut Vec<u8>, _: &Context<Data>) -> Result<usize> {
Ok(0)
}
- fn encode_slice(_: &[Self], _: &mut dyn Write, _: &Context<Data>) -> Result<usize>
+ fn encode_slice(_: &[Self], _: &mut Vec<u8>, _: &Context<Data>) -> Result<usize>
where
Self: Sized,
{