From d29ec9ffc4de6b0189863e0c6efec93e073d2141 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Fri, 22 May 2020 10:38:34 +0200 Subject: [PATCH] Avoid a few small allocations when decoding --- implementations/rust/Cargo.toml | 2 +- implementations/rust/src/value/decoder.rs | 108 +++++++++++++--------- 2 files changed, 66 insertions(+), 44 deletions(-) diff --git a/implementations/rust/Cargo.toml b/implementations/rust/Cargo.toml index d6b2b7c..74236de 100644 --- a/implementations/rust/Cargo.toml +++ b/implementations/rust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "preserves" -version = "0.5.0" +version = "0.5.1" authors = ["Tony Garnock-Jones "] edition = "2018" description = "Implementation of the Preserves serialization format via serde." diff --git a/implementations/rust/src/value/decoder.rs b/implementations/rust/src/value/decoder.rs index ee118df..795c2a6 100644 --- a/implementations/rust/src/value/decoder.rs +++ b/implementations/rust/src/value/decoder.rs @@ -65,6 +65,35 @@ pub struct Decoder<'a, 'b, R: Read, N: NestedValue, D: Domain> { read_annotations: bool, } +struct CountedStream<'de, 'a, 'b, R: Read, N: NestedValue, D: Domain> { + count: usize, + decoder: &'de mut Decoder<'a, 'b, R, N, D>, +} + +impl<'de, 'a, 'b, R: Read, N: NestedValue, D: Domain> Iterator for CountedStream<'de, 'a, 'b, R, N, D> { + type Item = Result; + fn next(&mut self) -> Option { + if self.count == 0 { return None } + self.count -= 1; + Some(self.decoder.next()) + } +} + +struct DelimitedStream<'de, 'a, 'b, R: Read, N: NestedValue, D: Domain> { + decoder: &'de mut Decoder<'a, 'b, R, N, D>, +} + +impl<'de, 'a, 'b, R: Read, N: NestedValue, D: Domain> Iterator for DelimitedStream<'de, 'a, 'b, R, N, D> { + type Item = Result; + fn next(&mut self) -> Option { + match self.decoder.peekend() { + Err(e) => Some(Err(e)), + Ok(true) => None, + Ok(false) => Some(self.decoder.next()), + } + } +} + fn decodeint(bs: &[u8]) -> BigInt { BigInt::from_signed_bytes_be(bs) } @@ -124,15 +153,14 @@ impl<'a, 'b, R: Read, N: NestedValue, D: Domain> Decoder<'a, 'b, R, N, D> { Ok(v) } - pub fn readbytes(&mut self, n: usize) -> Result> { + pub fn readbytes(&mut self, bs: &mut [u8]) -> Result<()> { if *self.buf != PeekState::Empty { unreachable!(); } - let mut bs = vec![0; n]; - match self.read.read_exact(&mut bs) { + match self.read.read_exact(bs) { Ok(()) => { - self.index += n; - Ok(bs) + self.index += bs.len(); + Ok(()) } Err(e) => if e.kind() == std::io::ErrorKind::UnexpectedEof { @@ -143,15 +171,6 @@ impl<'a, 'b, R: Read, N: NestedValue, D: Domain> Decoder<'a, 'b, R, N, D> { } } - pub fn readvalues(&mut self, mut count: usize) -> Result> { - let mut pieces: Vec = Vec::with_capacity(count); - while count > 0 { - pieces.push(self.next()?); - count -= 1; - } - Ok(pieces) - } - pub fn decodeop(b: u8) -> Result<(Op, u8)> { Ok((Op::try_from(b >> 4)?, b & 15)) } @@ -195,34 +214,37 @@ impl<'a, 'b, R: Read, N: NestedValue, D: Domain> Decoder<'a, 'b, R, N, D> { }) } - pub fn decodecompound(minor: CompoundMinor, mut pieces: Vec) -> Result { + pub fn decodecompound>>(minor: CompoundMinor, mut pieces: I) -> + Result + { match minor { CompoundMinor::Record => - if pieces.is_empty() { - Err(Error::Syntax("Too few elements in encoded record")) - } else { - let label = pieces.remove(0); - Ok(Value::record(label, pieces).wrap()) + match pieces.next() { + None => Err(Error::Syntax("Too few elements in encoded record")), + Some(labelres) => { + let label = labelres?; + Ok(Value::record(label, pieces.collect::>>()?).wrap()) + } }, - CompoundMinor::Sequence => Ok(Value::Sequence(pieces).wrap()), + CompoundMinor::Sequence => { + Ok(Value::Sequence(pieces.collect::>>()?).wrap()) + } CompoundMinor::Set => { let mut s = Set::new(); - while let Some(v) = pieces.pop() { - s.insert(v); - } + for res in pieces { s.insert(res?); } Ok(Value::Set(s).wrap()) } - CompoundMinor::Dictionary => - if pieces.len() % 2 != 0 { - Err(Error::Syntax("Missing dictionary value")) - } else { - let mut d = Map::new(); - while let Some(v) = pieces.pop() { - let k = pieces.pop().unwrap(); - d.insert(k, v); + CompoundMinor::Dictionary => { + let mut d = Map::new(); + while let Some(kres) = pieces.next() { + let k = kres?; + match pieces.next() { + Some(vres) => { d.insert(k, vres?); } + None => return Err(Error::Syntax("Missing dictionary value")), } - Ok(Value::Dictionary(d).wrap()) - }, + } + Ok(Value::Dictionary(d).wrap()) + } } } @@ -238,11 +260,7 @@ impl<'a, 'b, R: Read, N: NestedValue, D: Domain> Decoder<'a, 'b, R, N, D> { } pub fn valuestream(&mut self, minor: CompoundMinor) -> Result { - let mut pieces: Vec = Vec::new(); - while !self.peekend()? { - pieces.push(self.next()?); - } - Self::decodecompound(minor, pieces) + Self::decodecompound(minor, DelimitedStream { decoder: self }) } pub fn next(&mut self) -> Result { @@ -251,11 +269,13 @@ impl<'a, 'b, R: Read, N: NestedValue, D: Domain> Decoder<'a, 'b, R, N, D> { (Op::Misc(0), 0) => Ok(Value::from(false).wrap()), (Op::Misc(0), 1) => Ok(Value::from(true).wrap()), (Op::Misc(0), 2) => { - let bs: &[u8] = &self.readbytes(4)?; + let mut bs: [u8; 4] = Default::default(); + self.readbytes(&mut bs)?; Ok(Value::from(f32::from_bits(u32::from_be_bytes(bs.try_into().unwrap()))).wrap()) } (Op::Misc(0), 3) => { - let bs: &[u8] = &self.readbytes(8)?; + let mut bs: [u8; 8] = Default::default(); + self.readbytes(&mut bs)?; Ok(Value::from(f64::from_bits(u64::from_be_bytes(bs.try_into().unwrap()))).wrap()) } (Op::Misc(0), 5) => { @@ -295,11 +315,13 @@ impl<'a, 'b, R: Read, N: NestedValue, D: Domain> Decoder<'a, 'b, R, N, D> { (Op::Misc(_), _) => unreachable!(), (Op::Atom(minor), arg) => { let count = self.wirelength(arg)?; - Self::decodebinary(minor, self.readbytes(count)?) + let mut bs = vec![0; count]; + self.readbytes(&mut bs)?; + Self::decodebinary(minor, bs) } (Op::Compound(minor), arg) => { let count = self.wirelength(arg)?; - Self::decodecompound(minor, self.readvalues(count)?) + Self::decodecompound(minor, CountedStream { count, decoder: self }) } (Op::Reserved(3), 15) => continue, (Op::Reserved(_), _) => Err(InvalidOp.into()),