Package up Indexer

This commit is contained in:
Tony Garnock-Jones 2022-11-10 22:45:51 +01:00
parent 4a1b021635
commit 384644f5ea
1 changed files with 69 additions and 46 deletions

View File

@ -40,16 +40,6 @@ fn tag_at(packed: &[u8], i: usize) -> io::Result<Tag> {
Ok(Tag::try_from(at(packed, i)?)?) Ok(Tag::try_from(at(packed, i)?)?)
} }
fn skip_annotations(packed: &[u8], mut i: usize) -> io::Result<usize> {
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)> { fn varint(packed: &[u8], mut i: usize) -> io::Result<(u64, usize)> {
let mut shift = 0; let mut shift = 0;
let mut acc: u64 = 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<usize> { struct Indexer<'de> {
loop { packed: &'de [u8],
let next_i = match tag_at(packed, i)? { offset: usize,
Tag::False => i + 1, }
Tag::True => i + 1,
Tag::Float => i + 5, impl<'de> Indexer<'de> {
Tag::Double => i + 9, fn skip_annotations(&mut self) -> io::Result<()> {
Tag::End => Err(io::Error::new(io::ErrorKind::InvalidData, "Unexpected end tag"))?, loop {
Tag::Annotation => { if tag_at(&self.packed, self.offset)? == Tag::Annotation {
i = skip_value(packed, i + 1)?; self.offset += 1;
continue; self.skip_value()?;
} else {
return Ok(());
} }
Tag::Embedded => { }
i = i + 1; }
continue;
} fn tag(&mut self) -> io::Result<Tag> {
Tag::SmallInteger(_) => i + 1, let tag = tag_at(&self.packed, self.offset)?;
Tag::MediumInteger(n) => i + 1 + (n as usize), Ok(tag)
Tag::SignedInteger | Tag::ByteString => { }
let (n, i) = varint(packed, i + 1)?;
i + (n as usize) fn varint(&mut self) -> io::Result<u64> {
} let (n, i) = varint(&self.packed, self.offset + 1)?;
Tag::String | Tag::Symbol => { self.offset = i;
let (n, i) = varint(packed, i + 1)?; Ok(n)
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) fn skip_value(&mut self) -> io::Result<()> {
} loop {
Tag::Record | Tag::Sequence | Tag::Set | Tag::Dictionary => { match self.tag()? {
i = i + 1; Tag::False => self.offset += 1,
while tag_at(packed, i)? != Tag::End { Tag::True => self.offset += 1,
i = skip_value(packed, i)?; 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(());
return Ok(next_i); }
} }
} }
impl<'de, Packed: AsRef<[u8]> + 'de> View<'de, Packed> { impl<'de, Packed: AsRef<[u8]> + 'de> View<'de, Packed> {
pub fn new(packed: Packed) -> io::Result<Self> { pub fn new(packed: Packed) -> io::Result<Self> {
// println!("packed {:?}", &packed.as_ref()); // println!("packed {:?}", &packed.as_ref());
let value_offset = skip_annotations(packed.as_ref(), 0)?; let mut indexer = Indexer { packed: packed.as_ref(), offset: 0 };
let value_end = skip_value(packed.as_ref(), value_offset)?; 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())? } if value_end > packed.as_ref().len() { Err(io_eof())? }
Ok(View { packed, value_offset, value_end, phantom: PhantomData }) Ok(View { packed, value_offset, value_end, phantom: PhantomData })
} }