Avoid a few small allocations when decoding

This commit is contained in:
Tony Garnock-Jones 2020-05-22 10:38:34 +02:00
parent 316a772fec
commit d29ec9ffc4
2 changed files with 66 additions and 44 deletions

View File

@ -1,6 +1,6 @@
[package]
name = "preserves"
version = "0.5.0"
version = "0.5.1"
authors = ["Tony Garnock-Jones <tonyg@leastfixedpoint.com>"]
edition = "2018"
description = "Implementation of the Preserves serialization format via serde."

View File

@ -65,6 +65,35 @@ pub struct Decoder<'a, 'b, R: Read, N: NestedValue<D>, D: Domain> {
read_annotations: bool,
}
struct CountedStream<'de, 'a, 'b, R: Read, N: NestedValue<D>, D: Domain> {
count: usize,
decoder: &'de mut Decoder<'a, 'b, R, N, D>,
}
impl<'de, 'a, 'b, R: Read, N: NestedValue<D>, D: Domain> Iterator for CountedStream<'de, 'a, 'b, R, N, D> {
type Item = Result<N>;
fn next(&mut self) -> Option<Self::Item> {
if self.count == 0 { return None }
self.count -= 1;
Some(self.decoder.next())
}
}
struct DelimitedStream<'de, 'a, 'b, R: Read, N: NestedValue<D>, D: Domain> {
decoder: &'de mut Decoder<'a, 'b, R, N, D>,
}
impl<'de, 'a, 'b, R: Read, N: NestedValue<D>, D: Domain> Iterator for DelimitedStream<'de, 'a, 'b, R, N, D> {
type Item = Result<N>;
fn next(&mut self) -> Option<Self::Item> {
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>, D: Domain> Decoder<'a, 'b, R, N, D> {
Ok(v)
}
pub fn readbytes(&mut self, n: usize) -> Result<Vec<u8>> {
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>, D: Domain> Decoder<'a, 'b, R, N, D> {
}
}
pub fn readvalues(&mut self, mut count: usize) -> Result<Vec<N>> {
let mut pieces: Vec<N> = 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>, D: Domain> Decoder<'a, 'b, R, N, D> {
})
}
pub fn decodecompound(minor: CompoundMinor, mut pieces: Vec<N>) -> Result<N> {
pub fn decodecompound<I: Iterator<Item = Result<N>>>(minor: CompoundMinor, mut pieces: I) ->
Result<N>
{
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::<Result<Vec<N>>>()?).wrap())
}
},
CompoundMinor::Sequence => Ok(Value::Sequence(pieces).wrap()),
CompoundMinor::Sequence => {
Ok(Value::Sequence(pieces.collect::<Result<Vec<N>>>()?).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>, D: Domain> Decoder<'a, 'b, R, N, D> {
}
pub fn valuestream(&mut self, minor: CompoundMinor) -> Result<N> {
let mut pieces: Vec<N> = 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<N> {
@ -251,11 +269,13 @@ impl<'a, 'b, R: Read, N: NestedValue<D>, 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>, 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()),