Avoid a few small allocations when decoding
This commit is contained in:
parent
316a772fec
commit
d29ec9ffc4
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "preserves"
|
name = "preserves"
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
authors = ["Tony Garnock-Jones <tonyg@leastfixedpoint.com>"]
|
authors = ["Tony Garnock-Jones <tonyg@leastfixedpoint.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "Implementation of the Preserves serialization format via serde."
|
description = "Implementation of the Preserves serialization format via serde."
|
||||||
|
|
|
@ -65,6 +65,35 @@ pub struct Decoder<'a, 'b, R: Read, N: NestedValue<D>, D: Domain> {
|
||||||
read_annotations: bool,
|
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 {
|
fn decodeint(bs: &[u8]) -> BigInt {
|
||||||
BigInt::from_signed_bytes_be(bs)
|
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)
|
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 {
|
if *self.buf != PeekState::Empty {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
let mut bs = vec![0; n];
|
match self.read.read_exact(bs) {
|
||||||
match self.read.read_exact(&mut bs) {
|
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
self.index += n;
|
self.index += bs.len();
|
||||||
Ok(bs)
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(e) =>
|
Err(e) =>
|
||||||
if e.kind() == std::io::ErrorKind::UnexpectedEof {
|
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)> {
|
pub fn decodeop(b: u8) -> Result<(Op, u8)> {
|
||||||
Ok((Op::try_from(b >> 4)?, b & 15))
|
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 {
|
match minor {
|
||||||
CompoundMinor::Record =>
|
CompoundMinor::Record =>
|
||||||
if pieces.is_empty() {
|
match pieces.next() {
|
||||||
Err(Error::Syntax("Too few elements in encoded record"))
|
None => Err(Error::Syntax("Too few elements in encoded record")),
|
||||||
} else {
|
Some(labelres) => {
|
||||||
let label = pieces.remove(0);
|
let label = labelres?;
|
||||||
Ok(Value::record(label, pieces).wrap())
|
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 => {
|
CompoundMinor::Set => {
|
||||||
let mut s = Set::new();
|
let mut s = Set::new();
|
||||||
while let Some(v) = pieces.pop() {
|
for res in pieces { s.insert(res?); }
|
||||||
s.insert(v);
|
|
||||||
}
|
|
||||||
Ok(Value::Set(s).wrap())
|
Ok(Value::Set(s).wrap())
|
||||||
}
|
}
|
||||||
CompoundMinor::Dictionary =>
|
CompoundMinor::Dictionary => {
|
||||||
if pieces.len() % 2 != 0 {
|
let mut d = Map::new();
|
||||||
Err(Error::Syntax("Missing dictionary value"))
|
while let Some(kres) = pieces.next() {
|
||||||
} else {
|
let k = kres?;
|
||||||
let mut d = Map::new();
|
match pieces.next() {
|
||||||
while let Some(v) = pieces.pop() {
|
Some(vres) => { d.insert(k, vres?); }
|
||||||
let k = pieces.pop().unwrap();
|
None => return Err(Error::Syntax("Missing dictionary value")),
|
||||||
d.insert(k, v);
|
|
||||||
}
|
}
|
||||||
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> {
|
pub fn valuestream(&mut self, minor: CompoundMinor) -> Result<N> {
|
||||||
let mut pieces: Vec<N> = Vec::new();
|
Self::decodecompound(minor, DelimitedStream { decoder: self })
|
||||||
while !self.peekend()? {
|
|
||||||
pieces.push(self.next()?);
|
|
||||||
}
|
|
||||||
Self::decodecompound(minor, pieces)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next(&mut self) -> Result<N> {
|
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), 0) => Ok(Value::from(false).wrap()),
|
||||||
(Op::Misc(0), 1) => Ok(Value::from(true).wrap()),
|
(Op::Misc(0), 1) => Ok(Value::from(true).wrap()),
|
||||||
(Op::Misc(0), 2) => {
|
(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())
|
Ok(Value::from(f32::from_bits(u32::from_be_bytes(bs.try_into().unwrap()))).wrap())
|
||||||
}
|
}
|
||||||
(Op::Misc(0), 3) => {
|
(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())
|
Ok(Value::from(f64::from_bits(u64::from_be_bytes(bs.try_into().unwrap()))).wrap())
|
||||||
}
|
}
|
||||||
(Op::Misc(0), 5) => {
|
(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::Misc(_), _) => unreachable!(),
|
||||||
(Op::Atom(minor), arg) => {
|
(Op::Atom(minor), arg) => {
|
||||||
let count = self.wirelength(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) => {
|
(Op::Compound(minor), arg) => {
|
||||||
let count = self.wirelength(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(3), 15) => continue,
|
||||||
(Op::Reserved(_), _) => Err(InvalidOp.into()),
|
(Op::Reserved(_), _) => Err(InvalidOp.into()),
|
||||||
|
|
Loading…
Reference in New Issue