mod strings;
use core::marker::{PhantomData};
use tarrasque::{Extract, ExtractResult, Stream, be_u16, be_u32, extract};
use super::{OffsetSize};
pub use self::strings::*;
#[inline]
fn be_u24(bytes: &[u8]) -> u32 {
assert!(bytes.len() >= 3);
let a = u32::from(bytes[0]) << 16;
let b = u32::from(bytes[1]) << 8;
let c = u32::from(bytes[2]);
a + b + c
}
extract! {
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
struct Offsets<'s>(count: usize, size: usize) {
size: usize = size,
bytes: &'s [u8] = [count * size],
}
}
impl<'s> Offsets<'s> {
#[inline]
fn get(&self, index: usize) -> usize {
match self.size {
1 => self.bytes[index] as usize,
2 => be_u16(&self.bytes[index * 2..]) as usize,
3 => be_u24(&self.bytes[index * 3..]) as usize,
4 => be_u32(&self.bytes[index * 4..]) as usize,
_ => unreachable!(),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Index<'s, T> where T: Extract<'s, ()> {
count: usize,
offsets: Offsets<'s>,
bytes: &'s [u8],
_marker: PhantomData<*const T>,
}
impl<'s, T> Index<'s, T> where T: Extract<'s, ()> {
#[inline]
pub fn len(&self) -> usize {
self.count
}
#[inline]
pub fn is_empty(&self) -> bool {
self.count == 0
}
#[inline]
pub fn get(&self, index: usize) -> Option<&'s [u8]> {
if index < self.count {
let start = self.offsets.get(index) - 1;
let end = self.offsets.get(index + 1) - 1;
Some(&self.bytes[start..end])
} else {
None
}
}
#[inline]
pub fn parse_object(&self, index: usize) -> Option<ExtractResult<'s, T>> {
self.get(index).map(|b| Stream(b).extract(()))
}
#[inline]
pub fn objects(self) -> ObjectIter<'s, T> {
let objects = self.len();
ObjectIter { index: self, object: 0, objects }
}
}
impl<'s, T> Extract<'s, ()> for Index<'s, T> where T: Extract<'s, ()> {
#[inline]
fn extract(stream: &mut Stream<'s>, _: ()) -> ExtractResult<'s, Self> {
let count = stream.extract::<u16, _>(())? as usize;
let size = stream.extract::<OffsetSize, _>(())?.0 as usize;
let offsets: Offsets<'s> = stream.extract((count + 1, size))?;
let bytes = stream.extract(offsets.get(count) - 1)?;
Ok(Index { count, offsets, bytes, _marker: PhantomData })
}
}
#[derive(Copy, Clone, Debug)]
pub struct ObjectIter<'s, T> where T: Extract<'s, ()> {
index: Index<'s, T>,
object: usize,
objects: usize,
}
impl<'s, T> Iterator for ObjectIter<'s, T> where T: Extract<'s, ()> {
type Item = ExtractResult<'s, T>;
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.objects - self.object;
(size, Some(size))
}
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.object != self.objects {
self.object += 1;
self.index.parse_object(self.object - 1)
} else {
None
}
}
}
impl<'s, T> DoubleEndedIterator for ObjectIter<'s, T> where T: Extract<'s, ()> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
if self.object != self.objects {
self.objects -= 1;
self.index.parse_object(self.objects)
} else {
None
}
}
}
impl<'s, T> ExactSizeIterator for ObjectIter<'s, T> where T: Extract<'s, ()> { }