From ff1172f2abfb840caf115056ff0b2ae95b92a6aa Mon Sep 17 00:00:00 2001 From: hinto-janai Date: Fri, 21 Jun 2024 20:25:21 -0400 Subject: [PATCH] epee: make `{read,write}_varint` public, create `write_{bytes,container}` (#185) * make `{read,write}_varint` public, create `write_{container,bytes}` * add doc tests to varint functions * `write_container` -> `write_iterator` * add `write_{iterator,bytes}` doc test * fix `write_iterator()` doc --- net/epee-encoding/src/lib.rs | 83 +++++++++++++++++++++++++- net/epee-encoding/src/value.rs | 100 +++++--------------------------- net/epee-encoding/src/varint.rs | 32 ++++++++++ 3 files changed, 130 insertions(+), 85 deletions(-) diff --git a/net/epee-encoding/src/lib.rs b/net/epee-encoding/src/lib.rs index ffb0a1e..92046d3 100644 --- a/net/epee-encoding/src/lib.rs +++ b/net/epee-encoding/src/lib.rs @@ -77,7 +77,7 @@ pub use error::*; use io::*; pub use marker::{InnerMarker, Marker}; pub use value::EpeeValue; -use varint::*; +pub use varint::{read_varint, write_varint}; /// Header that needs to be at the beginning of every binary blob that follows /// this binary serialization format. @@ -212,6 +212,87 @@ fn write_epee_value(val: T, w: &mut B) -> Result<()> { val.write(w) } +/// Write a byte array to `w` with [`write_varint`]. +/// +/// This function: +/// - Writes the length of `t`'s bytes into `w` using [`write_varint`] +/// - Writes `t`'s bytes into `w` +/// +/// It is used as the internal [`EpeeValue::write`] +/// implementation of byte-like containers such as: +/// - [`EpeeValue::>::write`] +/// - [`EpeeValue::::write`] +/// +/// # Errors +/// This will error if: +/// - [`write_varint`] fails +/// - `w` does not have enough capacity +/// +/// # Example +/// ```rust +/// let t: [u8; 8] = [3, 0, 0, 0, 1, 0, 0, 0]; +/// let mut w = vec![]; +/// +/// epee_encoding::write_bytes(t, &mut w).unwrap(); +/// +/// assert_eq!(w.len(), 9); // length of bytes + bytes +/// assert_eq!(w[1..], t); +/// ``` +pub fn write_bytes, B: BufMut>(t: T, w: &mut B) -> Result<()> { + let bytes = t.as_ref(); + let len = bytes.len(); + + write_varint(len.try_into()?, w)?; + + if w.remaining_mut() < len { + return Err(Error::IO("Not enough capacity to write bytes")); + } + + w.put_slice(bytes); + + Ok(()) +} + +/// Write an [`Iterator`] of [`EpeeValue`]s to `w` with [`write_varint`]. +/// +/// This function: +/// - Writes the length of the `iterator`, into `w` using [`write_varint`] +/// - [`EpeeValue::write`]s each `T` of the iterator into `w` +/// +/// It is used as the internal [`EpeeValue::write`] +/// implementation of containers such as [`EpeeValue::>::write`]. +/// +/// # Errors +/// This will error if: +/// - [`write_varint`] fails +/// - [`EpeeValue::::write`] fails +/// +/// # Example +/// ```rust +/// let t: u64 = 3; +/// let vec: Vec = vec![t, t]; +/// let mut w = vec![]; +/// +/// let iter: std::vec::IntoIter = vec.into_iter(); +/// epee_encoding::write_iterator(iter, &mut w).unwrap(); +/// +/// assert_eq!(w.len(), 17); +/// assert_eq!(w[1..9], [3, 0, 0, 0, 0, 0, 0, 0]); +/// assert_eq!(w[9..], [3, 0, 0, 0, 0, 0, 0, 0]); +/// ``` +pub fn write_iterator(iterator: I, w: &mut B) -> Result<()> +where + T: EpeeValue, + I: Iterator + ExactSizeIterator, + B: BufMut, +{ + write_varint(iterator.len().try_into()?, w)?; + for item in iterator.into_iter() { + item.write(w)?; + } + Ok(()) +} + /// A helper object builder that just skips every field. #[derive(Default)] struct SkipObjectBuilder; diff --git a/net/epee-encoding/src/value.rs b/net/epee-encoding/src/value.rs index 74dea35..0dcd45a 100644 --- a/net/epee-encoding/src/value.rs +++ b/net/epee-encoding/src/value.rs @@ -9,7 +9,10 @@ use bytes::{Buf, BufMut, Bytes, BytesMut}; use fixed_bytes::{ByteArray, ByteArrayVec}; use crate::{ - io::*, varint::*, EpeeObject, Error, InnerMarker, Marker, Result, MAX_STRING_LEN_POSSIBLE, + io::{checked_read_primitive, checked_write_primitive}, + varint::{read_varint, write_varint}, + write_bytes, write_iterator, EpeeObject, Error, InnerMarker, Marker, Result, + MAX_STRING_LEN_POSSIBLE, }; /// A trait for epee values. @@ -83,11 +86,7 @@ impl EpeeValue for Vec { } fn write(self, w: &mut B) -> Result<()> { - write_varint(self.len().try_into()?, w)?; - for item in self.into_iter() { - item.write(w)?; - } - Ok(()) + write_iterator(self.into_iter(), w) } } @@ -105,11 +104,7 @@ impl EpeeValue for [T; N] { } fn write(self, w: &mut B) -> Result<()> { - write_varint(self.len().try_into()?, w)?; - for item in self.into_iter() { - item.write(w)?; - } - Ok(()) + write_iterator(self.into_iter(), w) } } @@ -191,14 +186,7 @@ impl EpeeValue for Vec { } fn write(self, w: &mut B) -> Result<()> { - write_varint(self.len().try_into()?, w)?; - - if w.remaining_mut() < self.len() { - return Err(Error::IO("Not enough capacity to write bytes")); - } - - w.put_slice(&self); - Ok(()) + write_bytes(self, w) } } @@ -231,14 +219,7 @@ impl EpeeValue for Bytes { } fn write(self, w: &mut B) -> Result<()> { - write_varint(self.len().try_into()?, w)?; - - if w.remaining_mut() < self.len() { - return Err(Error::IO("Not enough capacity to write bytes")); - } - - w.put(self); - Ok(()) + write_bytes(self, w) } } @@ -274,14 +255,7 @@ impl EpeeValue for BytesMut { } fn write(self, w: &mut B) -> Result<()> { - write_varint(self.len().try_into()?, w)?; - - if w.remaining_mut() < self.len() { - return Err(Error::IO("Not enough capacity to write bytes")); - } - - w.put(self); - Ok(()) + write_bytes(self, w) } } @@ -316,15 +290,7 @@ impl EpeeValue for ByteArrayVec { fn write(self, w: &mut B) -> Result<()> { let bytes = self.take_bytes(); - - write_varint(bytes.len().try_into()?, w)?; - - if w.remaining_mut() < bytes.len() { - return Err(Error::IO("Not enough capacity to write bytes")); - } - - w.put(bytes); - Ok(()) + write_bytes(bytes, w) } } @@ -351,15 +317,7 @@ impl EpeeValue for ByteArray { fn write(self, w: &mut B) -> Result<()> { let bytes = self.take_bytes(); - - write_varint(N.try_into().unwrap(), w)?; - - if w.remaining_mut() < N { - return Err(Error::IO("Not enough capacity to write bytes")); - } - - w.put(bytes); - Ok(()) + write_bytes(bytes, w) } } @@ -380,14 +338,7 @@ impl EpeeValue for String { } fn write(self, w: &mut B) -> Result<()> { - write_varint(self.len().try_into()?, w)?; - - if w.remaining_mut() < self.len() { - return Err(Error::IO("Not enough capacity to write bytes")); - } - - w.put_slice(self.as_bytes()); - Ok(()) + write_bytes(self, w) } } @@ -405,14 +356,7 @@ impl EpeeValue for [u8; N] { } fn write(self, w: &mut B) -> Result<()> { - write_varint(self.len().try_into()?, w)?; - - if w.remaining_mut() < self.len() { - return Err(Error::IO("Not enough capacity to write bytes")); - } - - w.put_slice(&self); - Ok(()) + write_bytes(self, w) } } @@ -446,11 +390,7 @@ impl EpeeValue for Vec<[u8; N]> { } fn write(self, w: &mut B) -> Result<()> { - write_varint(self.len().try_into()?, w)?; - for item in self.into_iter() { - item.write(w)?; - } - Ok(()) + write_iterator(self.into_iter(), w) } } @@ -486,11 +426,7 @@ macro_rules! epee_seq { } fn write(self, w: &mut B) -> Result<()> { - write_varint(self.len().try_into()?, w)?; - for item in self.into_iter() { - item.write(w)?; - } - Ok(()) + write_iterator(self.into_iter(), w) } } @@ -508,11 +444,7 @@ macro_rules! epee_seq { } fn write(self, w: &mut B) -> Result<()> { - write_varint(self.len().try_into()?, w)?; - for item in self.into_iter() { - item.write(w)?; - } - Ok(()) + write_iterator(self.into_iter(), w) } } }; diff --git a/net/epee-encoding/src/varint.rs b/net/epee-encoding/src/varint.rs index 5de4eed..e574ba8 100644 --- a/net/epee-encoding/src/varint.rs +++ b/net/epee-encoding/src/varint.rs @@ -7,6 +7,18 @@ const FITS_IN_ONE_BYTE: u64 = 2_u64.pow(8 - SIZE_OF_SIZE_MARKER) - 1; const FITS_IN_TWO_BYTES: u64 = 2_u64.pow(16 - SIZE_OF_SIZE_MARKER) - 1; const FITS_IN_FOUR_BYTES: u64 = 2_u64.pow(32 - SIZE_OF_SIZE_MARKER) - 1; +/// Read an epee variable sized number from `r`. +/// +/// ```rust +/// use epee_encoding::read_varint; +/// +/// assert_eq!(read_varint(&mut [252].as_slice()).unwrap(), 63); +/// assert_eq!(read_varint(&mut [1, 1].as_slice()).unwrap(), 64); +/// assert_eq!(read_varint(&mut [253, 255].as_slice()).unwrap(), 16_383); +/// assert_eq!(read_varint(&mut [2, 0, 1, 0].as_slice()).unwrap(), 16_384); +/// assert_eq!(read_varint(&mut [254, 255, 255, 255].as_slice()).unwrap(), 1_073_741_823); +/// assert_eq!(read_varint(&mut [3, 0, 0, 0, 1, 0, 0, 0].as_slice()).unwrap(), 1_073_741_824); +/// ``` pub fn read_varint(r: &mut B) -> Result { if !r.has_remaining() { Err(Error::IO("Not enough bytes to build VarInt"))? @@ -26,6 +38,26 @@ pub fn read_varint(r: &mut B) -> Result { Ok(vi) } +/// Write an epee variable sized number into `w`. +/// +/// ```rust +/// use epee_encoding::write_varint; +/// +/// let mut buf = vec![]; +/// +/// for (number, expected_bytes) in [ +/// (63, [252].as_slice()), +/// (64, [1, 1].as_slice()), +/// (16_383, [253, 255].as_slice()), +/// (16_384, [2, 0, 1, 0].as_slice()), +/// (1_073_741_823, [254, 255, 255, 255].as_slice()), +/// (1_073_741_824, [3, 0, 0, 0, 1, 0, 0, 0].as_slice()), +/// ] { +/// buf.clear(); +/// write_varint(number, &mut buf); +/// assert_eq!(buf.as_slice(), expected_bytes); +/// } +/// ``` pub fn write_varint(number: u64, w: &mut B) -> Result<()> { let size_marker = match number { 0..=FITS_IN_ONE_BYTE => 0,