From e7fff61c951a698da20f7d6c2066fef09ccc354e Mon Sep 17 00:00:00 2001 From: Avril Date: Tue, 25 May 2021 19:48:24 +0100 Subject: [PATCH] added stream byte counter --- src/ext.rs | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/formats.rs | 9 +++-- 2 files changed, 102 insertions(+), 5 deletions(-) diff --git a/src/ext.rs b/src/ext.rs index 9762f26..84a962b 100644 --- a/src/ext.rs +++ b/src/ext.rs @@ -1,4 +1,7 @@ use super::*; +use std::{ + io::{self, Read, Write}, +}; pub trait Tuple2Ext: Sized { @@ -11,3 +14,98 @@ impl Tuple2Ext for (T, U) (self.1, self.0) } } + +/// A counter for num of bytes read/written from a `Read`/`Write` stream. +#[derive(Debug)] +pub struct IOCounter(usize, T); + +impl io::Read for IOCounter +{ + #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { + let w = self.1.read(buf)?; + self.0+=w; + Ok(w) + } +} + +impl io::Write for IOCounter +{ + #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { + let w= self.1.write(buf)?; + self.0+=w; + Ok(w) + } + #[inline(always)] fn flush(&mut self) -> io::Result<()> { + self.1.flush() + } +} + +impl IOCounter +{ + /// The current counted bytes i/o'd + #[inline] pub fn count(&self) -> usize + { + self.0 + } + /// Reference to the inner stream + #[inline] pub fn inner(&self) -> &T + { + &self.1 + } + /// Mutable reference to the inner stream + #[inline] pub fn inner_mut(&mut self) -> &mut T + { + &mut self.1 + } + /// Mutable reference to the count. + /// Use this to set the count. + #[inline(always)] pub fn count_mut(&mut self) -> &mut usize + { + &mut self.0 + } + /// Reset count to 0. + #[inline] pub fn reset(&mut self) + { + *self.count_mut() = 0; + } +} +impl IOCounter +{ + /// Create a new i/o counting wrapper. + #[inline(always)] pub fn new(val: T) -> Self + { + Self(0, val) + } + + /// Consume into inner stream + #[inline(always)] pub fn into_inner(self) -> T + { + self.1 + } +} + +pub trait IOCounterReadExt +{ + /// Wrap an `IOCounter` over this `Read` stream. + fn with_counter(self) -> IOCounter; +} +pub trait IOCounterWriteExt +{ + /// Wrap an `IOCounter` over this `Write` stream. + fn with_counter(self) -> IOCounter; +} + +impl IOCounterWriteExt for W +{ + #[inline] fn with_counter(self) -> IOCounter { + IOCounter::new(self) + } +} + +impl IOCounterReadExt for R +{ + #[inline] fn with_counter(self) -> IOCounter { + IOCounter::new(self) + } +} + diff --git a/src/formats.rs b/src/formats.rs index e0280f1..695ed54 100644 --- a/src/formats.rs +++ b/src/formats.rs @@ -25,7 +25,7 @@ pub struct FormatDirective pub trait Format { fn encode(cfg: &Config, to: W, obj: &Object) -> Result; - fn decode(cfg: &Config, from: R) -> Result; //TODO: An `io::Read` wrapper that counter num of bytes read internally. That way we can extract `(Object, usize)` from just `Object` here. + fn decode(cfg: &Config, from: R) -> Result; } macro_rules! directive { @@ -36,13 +36,12 @@ macro_rules! directive { }) }; (for $fmt:path => $($name:literal),+) => { - //TODO: $fmt will be a struct implementing `Format`. - // Will perform input conversions to trait methods. - // Will perform input/output conversions for `Format::decode` to extract `(Object, usize)` from `Object` function output and a `io::Read` input wrapper that counts bytes read from the stream. directive!($($name),+ => |c, w, o| { <$fmt as Format>::encode(c, w, o) }, |c, r| { - todo!("We need a io::Read stream wrapper that counts the bytes read `r` to satisfy the return value requirements of this function pointer") + let mut r = r.with_counter(); + let obj = <$fmt as Format>::decode(c, &mut r)?; + Ok((obj, r.count())) }) } }