From 384644f5ea98e1218595e4e9f15ee152536b18a2 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Thu, 10 Nov 2022 22:45:51 +0100 Subject: [PATCH] Package up Indexer --- implementations/rust/oo/src/packed/view.rs | 115 ++++++++++++--------- 1 file changed, 69 insertions(+), 46 deletions(-) diff --git a/implementations/rust/oo/src/packed/view.rs b/implementations/rust/oo/src/packed/view.rs index 35fe35b..73fafcd 100644 --- a/implementations/rust/oo/src/packed/view.rs +++ b/implementations/rust/oo/src/packed/view.rs @@ -40,16 +40,6 @@ fn tag_at(packed: &[u8], i: usize) -> io::Result { Ok(Tag::try_from(at(packed, i)?)?) } -fn skip_annotations(packed: &[u8], mut i: usize) -> io::Result { - loop { - if tag_at(packed, i)? == Tag::Annotation { - i = skip_value(packed, i + 1)?; - } else { - return Ok(i); - } - } -} - fn varint(packed: &[u8], mut i: usize) -> io::Result<(u64, usize)> { let mut shift = 0; let mut acc: u64 = 0; @@ -64,51 +54,84 @@ fn varint(packed: &[u8], mut i: usize) -> io::Result<(u64, usize)> { } } -fn skip_value(packed: &[u8], mut i: usize) -> io::Result { - loop { - let next_i = match tag_at(packed, i)? { - Tag::False => i + 1, - Tag::True => i + 1, - Tag::Float => i + 5, - Tag::Double => i + 9, - Tag::End => Err(io::Error::new(io::ErrorKind::InvalidData, "Unexpected end tag"))?, - Tag::Annotation => { - i = skip_value(packed, i + 1)?; - continue; +struct Indexer<'de> { + packed: &'de [u8], + offset: usize, +} + +impl<'de> Indexer<'de> { + fn skip_annotations(&mut self) -> io::Result<()> { + loop { + if tag_at(&self.packed, self.offset)? == Tag::Annotation { + self.offset += 1; + self.skip_value()?; + } else { + return Ok(()); } - Tag::Embedded => { - i = i + 1; - continue; - } - Tag::SmallInteger(_) => i + 1, - Tag::MediumInteger(n) => i + 1 + (n as usize), - Tag::SignedInteger | Tag::ByteString => { - let (n, i) = varint(packed, i + 1)?; - i + (n as usize) - } - Tag::String | Tag::Symbol => { - let (n, i) = varint(packed, i + 1)?; - std::str::from_utf8(&packed[i .. i + (n as usize)]).map_err( - |_| io::Error::new(io::ErrorKind::InvalidData, "Invalid UTF-8"))?; - i + (n as usize) - } - Tag::Record | Tag::Sequence | Tag::Set | Tag::Dictionary => { - i = i + 1; - while tag_at(packed, i)? != Tag::End { - i = skip_value(packed, i)?; + } + } + + fn tag(&mut self) -> io::Result { + let tag = tag_at(&self.packed, self.offset)?; + Ok(tag) + } + + fn varint(&mut self) -> io::Result { + let (n, i) = varint(&self.packed, self.offset + 1)?; + self.offset = i; + Ok(n) + } + + fn skip_value(&mut self) -> io::Result<()> { + loop { + match self.tag()? { + Tag::False => self.offset += 1, + Tag::True => self.offset += 1, + Tag::Float => self.offset += 5, + Tag::Double => self.offset += 9, + Tag::End => Err(io::Error::new(io::ErrorKind::InvalidData, "Unexpected end tag"))?, + Tag::Annotation => { + self.offset += 1; + self.skip_value()?; + continue; + } + Tag::Embedded => { + self.offset += 1; + continue; + } + Tag::SmallInteger(_) => self.offset += 1, + Tag::MediumInteger(n) => self.offset += 1 + n as usize, + Tag::SignedInteger | Tag::ByteString => { + let n = self.varint()?; + self.offset += n as usize; + } + Tag::String | Tag::Symbol => { + let n = self.varint()?; + std::str::from_utf8(&self.packed[self.offset .. self.offset + (n as usize)]) + .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Invalid UTF-8"))?; + self.offset += n as usize; + } + Tag::Record | Tag::Sequence | Tag::Set | Tag::Dictionary => { + self.offset += 1; + while tag_at(&self.packed, self.offset)? != Tag::End { + self.skip_value()?; + } + self.offset += 1; } - i + 1 } - }; - return Ok(next_i); + return Ok(()); + } } } impl<'de, Packed: AsRef<[u8]> + 'de> View<'de, Packed> { pub fn new(packed: Packed) -> io::Result { // println!("packed {:?}", &packed.as_ref()); - let value_offset = skip_annotations(packed.as_ref(), 0)?; - let value_end = skip_value(packed.as_ref(), value_offset)?; + let mut indexer = Indexer { packed: packed.as_ref(), offset: 0 }; + indexer.skip_annotations()?; + let value_offset = indexer.offset; + indexer.skip_value()?; + let value_end = indexer.offset; if value_end > packed.as_ref().len() { Err(io_eof())? } Ok(View { packed, value_offset, value_end, phantom: PhantomData }) }