pub mod comment_ast;
pub mod type_node;
use core::marker::PhantomData;
use crate::format::kind::Kind;
use crate::format::node_record::{
COMMON_DATA_MASK, END_OFFSET, KIND_OFFSET, NODE_RECORD_SIZE, PARENT_INDEX_OFFSET, POS_OFFSET,
};
use super::helpers::read_u32;
use super::source_file::LazySourceFile;
pub trait LazyNode<'a>: Copy + Clone + Sized {
const KIND: Kind;
fn from_index(source_file: &'a LazySourceFile<'a>, node_index: u32, root_index: u32) -> Self;
fn source_file(&self) -> &'a LazySourceFile<'a>;
fn node_index(&self) -> u32;
fn root_index(&self) -> u32;
#[inline]
fn byte_offset(&self) -> usize {
self.source_file().nodes_offset as usize + self.node_index() as usize * NODE_RECORD_SIZE
}
#[inline]
fn kind(&self) -> Kind {
let byte = self.source_file().bytes()[self.byte_offset() + KIND_OFFSET];
Kind::from_u8(byte).expect("encoder must only emit defined Kinds")
}
#[inline]
fn common_data(&self) -> u8 {
self.source_file().bytes()[self.byte_offset() + 1] & COMMON_DATA_MASK
}
#[inline]
fn pos(&self) -> u32 {
read_u32(self.source_file().bytes(), self.byte_offset() + POS_OFFSET)
}
#[inline]
fn end(&self) -> u32 {
read_u32(self.source_file().bytes(), self.byte_offset() + END_OFFSET)
}
#[inline]
fn range(&self) -> [u32; 2] {
let base = self.source_file().get_root_base_offset(self.root_index());
[base + self.pos(), base + self.end()]
}
#[inline]
fn parent_index(&self) -> u32 {
read_u32(
self.source_file().bytes(),
self.byte_offset() + PARENT_INDEX_OFFSET,
)
}
}
#[derive(Debug, Clone, Copy)]
pub struct NodeListIter<'a, T> {
source_file: &'a LazySourceFile<'a>,
current_index: u32,
remaining: u32,
root_index: u32,
_marker: PhantomData<T>,
}
impl<'a, T: LazyNode<'a>> NodeListIter<'a, T> {
#[inline]
#[must_use]
pub const fn new(
source_file: &'a LazySourceFile<'a>,
head_index: u32,
count: u32,
root_index: u32,
) -> Self {
let (current, remaining) = if head_index == 0 || count == 0 {
(0, 0)
} else {
(head_index, count)
};
NodeListIter {
source_file,
current_index: current,
remaining,
root_index,
_marker: PhantomData,
}
}
#[inline]
#[must_use]
pub const fn is_empty(&self) -> bool {
self.remaining == 0
}
#[inline]
#[must_use]
pub const fn len(&self) -> usize {
self.remaining as usize
}
}
impl<'a, T: LazyNode<'a>> Iterator for NodeListIter<'a, T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
return None;
}
let item = T::from_index(self.source_file, self.current_index, self.root_index);
self.current_index =
super::helpers::read_next_sibling(self.source_file, self.current_index);
self.remaining -= 1;
Some(item)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let n = self.remaining as usize;
(n, Some(n))
}
}
impl<'a, T: LazyNode<'a>> ExactSizeIterator for NodeListIter<'a, T> {}
#[cfg(test)]
mod tests {
use super::*;
use core::mem::size_of;
#[test]
fn node_list_iter_is_compact() {
assert!(size_of::<NodeListIter<'static, ()>>() <= 24);
}
}