use std::marker::PhantomData;
use crate::{BitMask, DataType};
pub trait ReadAt<'a> {
const MODE: DataType;
type ReadOutput;
fn read_at(buf: &'a [u8], offset: usize) -> Self::ReadOutput;
#[inline(always)]
fn read_with_tag_at(buf: &'a [u8], offset: usize, _tag:u8) -> Self::ReadOutput {
Self::read_at(buf, offset)
}
fn default_output() -> Self::ReadOutput;
#[inline(always)]
fn payload_block_end(_buf: &'a [u8], pos: usize) -> usize
where Self: Sized { pos + size_of::<Self>() }
}
macro_rules! impl_read_scalar {
($($t:ty),*) => {$(
impl<'a> ReadAt<'a> for $t {
const MODE: DataType = DataType::Inline;
type ReadOutput = Self;
#[inline(always)]
fn read_at(buf: &[u8], offset: usize) -> Self {
unsafe {
<$t>::from_le(
(buf.as_ptr().add(offset) as *const $t).read_unaligned()
)
}
}
#[inline(always)]
fn default_output() -> Self {
0
}
}
)*};
}
impl_read_scalar!(u8, u16, u32, u64, i8, i16, i32, i64, u128, i128);
impl<'a> ReadAt<'a> for f32 {
const MODE: DataType = DataType::Inline;
type ReadOutput = Self;
#[inline(always)]
fn read_at(buf: &[u8], offset: usize) -> Self {
Self::from_bits(u32::read_at(buf, offset))
}
#[inline(always)]
fn default_output() -> Self {
0.
}
}
impl<'a> ReadAt<'a> for f64 {
const MODE: DataType = DataType::Inline;
type ReadOutput = Self;
#[inline(always)]
fn read_at(buf: &[u8], offset: usize) -> Self {
Self::from_bits(u64::read_at(buf, offset))
}
#[inline(always)]
fn default_output() -> Self {
0.
}
}
impl<'a> ReadAt<'a> for bool {
const MODE: DataType = DataType::Inline;
type ReadOutput = bool;
#[inline(always)]
fn read_at(buf: &[u8], offset: usize) -> bool {
u8::read_at(buf, offset) != 0
}
#[inline(always)]
fn default_output() -> Self {
false
}
}
impl<'a> ReadAt<'a> for &str {
const MODE: DataType = DataType::Offset;
type ReadOutput = &'a str;
#[inline]
fn read_at(buf: &'a [u8], offset: usize) -> &'a str {
let len = u32::read_at(buf, offset) as usize;
unsafe {
let bytes = std::slice::from_raw_parts(
buf.as_ptr().add(offset + 4), len
);
std::str::from_utf8_unchecked(bytes)
}
}
#[inline(always)]
fn default_output() -> &'a str { "" }
#[inline(always)]
fn payload_block_end(buf: &'a [u8], pos: usize) -> usize {
pos + 4 + u32::read_at(buf, pos) as usize
}
}
impl<'a> ReadAt<'a> for String {
const MODE: DataType = DataType::Offset;
type ReadOutput = &'a str;
#[inline]
fn read_at(buf: &'a [u8], offset: usize) -> &'a str {
let len = u32::read_at(buf, offset) as usize;
unsafe {
let bytes = std::slice::from_raw_parts(
buf.as_ptr().add(offset + 4), len
);
std::str::from_utf8_unchecked(bytes)
}
}
#[inline(always)]
fn default_output() -> &'a str { "" }
#[inline(always)]
fn payload_block_end(buf: &'a [u8], pos: usize) -> usize {
pos + 4 + u32::read_at(buf, pos) as usize
}
}
impl<'a, T: ReadAt<'a>> ReadAt<'a> for Vec<T> {
const MODE: DataType = DataType::Offset;
type ReadOutput = ListView<'a, T>;
#[inline(always)]
fn read_at(buf: &'a [u8], offset: usize) -> ListView<'a, T> {
ListView::new(buf, offset + 4, u32::read_at(buf, offset) as usize)
}
#[inline(always)]
fn default_output() -> ListView<'a, T> { ListView::default() }
}
impl<'a, T: ReadAt<'a>, const N: usize> ReadAt<'a> for [T; N] {
const MODE: DataType = DataType::Offset;
type ReadOutput = ListView<'a, T>;
#[inline(always)]
fn read_at(buf: &'a [u8], offset: usize) -> ListView<'a, T> {
ListView::new(buf, offset, N)
}
#[inline(always)]
fn default_output() -> ListView<'a, T> { ListView::default() }
}
pub struct ListView<'a, T> {
pub buf: &'a [u8],
pub offset: usize,
pub len: usize,
pub back: usize,
pub next: usize,
pub skip: &'a BitMask,
_marker: PhantomData<T>,
}
static EMPTY_MASK: BitMask = BitMask{
bits: Vec::new(),
len: 0,
count:0,
};
impl<'a, T: ReadAt<'a>> ListView<'a, T> {
#[inline(always)]
pub fn new(buf: &'a [u8], offset: usize, len: usize) -> Self {
Self { buf, offset, len, back: len, next: 0, skip: &EMPTY_MASK, _marker: PhantomData }
}
#[inline(always)]
pub fn with_skip(mut self, skip: &'a BitMask) -> Self {
self.skip = skip;
self
}
#[inline(always)]
pub fn total_len(&self) -> usize { self.len }
#[inline(always)]
pub fn is_empty(&self) -> bool { self.len == 0 }
pub fn abs_pos(&self, index: usize) -> usize {
if T::MODE.is_inline_flag() {
self.offset + index * std::mem::size_of::<T>()
} else {
let ep = self.offset + index * 4;
let jump = u32::read_at(self.buf, ep) as usize;
if jump == 0 { 0 } else { ep + jump }
}
}
#[inline]
pub fn get(&self, index: usize) -> T::ReadOutput {
let offset = self.abs_pos(index);
if offset == 0 {return T::default_output()}
let tag = u8::read_at(self.buf,self.offset+ 4*self.total_len() + index);
T::read_with_tag_at(self.buf, offset, tag)
}
#[inline]
pub fn last_offset(&self) -> usize {
self.abs_pos(self.total_len() - 1)
}
#[inline]
pub fn read_last(&self) -> T::ReadOutput {
self.get(self.total_len()-1)
}
}
impl<'a, T: ReadAt<'a>> Iterator for ListView<'a, T> {
type Item = T::ReadOutput;
#[inline]
fn next(&mut self) -> Option<T::ReadOutput> {
if !self.skip.is_empty() {
while self.next < self.back && self.skip.is_set(&self.next) {
self.next += 1;
}
}
if self.next >= self.back { return None; }
let item = self.get(self.next);
self.next += 1;
Some(item)
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
let upper = self.back - self.next;
if self.skip.is_empty() {
(upper, Some(upper))
} else {
(0, Some(upper))
}
}
}
impl<'a, T: ReadAt<'a>> DoubleEndedIterator for ListView<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<T::ReadOutput> {
if !self.skip.is_empty() {
while self.next < self.back && self.skip.is_set(&(self.back - 1)) {
self.back -= 1;
}
}
if self.next >= self.back { return None; }
self.back -= 1;
Some(self.get(self.back))
}
}
impl<'a, T: ReadAt<'a>> ExactSizeIterator for ListView<'a, T> {
#[inline(always)]
fn len(&self) -> usize {
debug_assert!(
self.skip.is_empty(),
"ExactSizeIterator::len called on a ListView with an active skip list — \
result is an overcount; use size_hint or compute manually"
);
self.back - self.next
}
}
impl<'a, T: ReadAt<'a>> ReadAt<'a> for ListView<'a, T> {
const MODE: DataType = DataType::Offset;
type ReadOutput = ListView<'a, T>;
#[inline]
fn read_at(buf: &'a [u8], offset: usize) -> Self::ReadOutput {
ListView::new(buf, offset + 4, u32::read_at(buf, offset) as usize)
}
#[inline(always)]
fn default_output() -> ListView<'a, T> { ListView::default() }
}
impl<'a> From<ListView<'a, String>> for Vec<String> {
fn from(view: ListView<'a, String>) -> Vec<String> {
view.map(|s| s.to_string()).collect()
}
}
impl<'a, T: ReadAt<'a, ReadOutput = T> + Clone> From<ListView<'a, T>> for Vec<T> {
fn from(view: ListView<'a, T>) -> Vec<T> {
view.collect()
}
}
impl<'a, T> Default for ListView<'a, T> {
fn default() -> Self {
Self { buf: &[], offset: 0, len: 0, back: 0, next: 0, skip: &EMPTY_MASK, _marker: PhantomData }
}
}
#[derive(Clone, Copy, Default,)]
pub struct RawView<'a> {
pub buf: &'a [u8],
pub t_pos: usize,
pub v_pos: usize,
}
impl<'a> RawView<'a> {
pub const EMPTY: RawView<'static> = RawView { buf: &[], t_pos: 0, v_pos: 0 };
#[inline(always)]
pub fn new(buf: &'a [u8], table_pos: usize) -> Self {
let v_pos = (table_pos as i32 - i32::read_at(buf, table_pos)) as usize;
Self { buf, t_pos: table_pos, v_pos }
}
#[inline(always)]
pub fn from_slot(buf: &'a [u8], slot: usize) -> Self {
Self::new(buf, buf.len() - slot)
}
#[inline(always)]
pub fn voff(&self, field_idx: usize) -> usize {
u16::read_at(self.buf, self.v_pos + 4 + field_idx * 2) as usize
}
#[inline(always)]
pub fn is_present(&self, field_idx: usize) -> bool {
self.voff(field_idx) != 0
}
#[inline]
pub fn indirect_idx(&self, field_idx: usize) -> usize {
let field_pos = self.t_pos + self.voff(field_idx);
field_pos + u32::read_at(self.buf, field_pos) as usize
}
#[inline(always)]
pub fn vtable_bytes(&self) -> &'a [u8] {
let vt_size = u16::read_at(self.buf, self.v_pos) as usize;
&self.buf[self.v_pos..self.v_pos + vt_size]
}
}
pub trait HasRawView<'a> {
fn raw_view(&self) -> &RawView<'a>;
fn block_end_dyn(&self) -> usize;
}
impl<'a, T: ReadAt<'a>> PartialEq for ListView<'a, T>
where
T::ReadOutput: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
if self.total_len() != other.total_len() { return false; }
(0..self.total_len()).all(|i| self.get(i) == other.get(i))
}
}
impl<'a, T: ReadAt<'a>> std::fmt::Debug for ListView<'a, T>
where
T::ReadOutput: std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut list = f.debug_list();
for i in 0..self.total_len() {
list.entry(&self.get(i));
}
list.finish()
}
}
impl<'a, T: ReadAt<'a>> PartialEq<ListView<'a, T>> for Vec<T>
where
T: PartialEq<T::ReadOutput>,
{
fn eq(&self, other: &ListView<'a, T>) -> bool {
if self.len() != other.total_len() { return false; }
self.iter().enumerate().all(|(i, v)| *v == other.get(i))
}
}
impl<'a, T: ReadAt<'a>> PartialEq<Vec<T>> for ListView<'a, T>
where
T: PartialEq<T::ReadOutput>,
{
fn eq(&self, other: &Vec<T>) -> bool { other == self }
}