pub mod vue;
use vize_l0::{Allocator, Span, Vec};
pub use vue::Vue;
pub trait ContainerFormat {
fn split<'a>(&self, allocator: &'a Allocator, source: &'a str) -> Container<'a>;
}
#[derive(Debug)]
pub struct Container<'a> {
pub source: &'a str,
pub blocks: Vec<'a, Block<'a>>,
pub errors: Vec<'a, ContainerError>,
}
impl<'a> Container<'a> {
pub fn segments(&self) -> ContainerSegments<'_, 'a> {
ContainerSegments {
blocks: &self.blocks,
source_end: u32::try_from(self.source.len()).unwrap_or(u32::MAX),
index: 0,
}
}
}
#[derive(Debug)]
pub struct Block<'a> {
pub name: &'a str,
pub open_tag: Span,
pub attrs: Vec<'a, BlockAttr<'a>>,
pub content: Span,
pub close_tag: Option<Span>,
}
impl<'a> Block<'a> {
pub fn attr(&self, name: &str) -> Option<&BlockAttr<'a>> {
self.attrs.iter().find(|attr| attr.name == name)
}
pub const fn authored_span(&self) -> Span {
Span::new(
self.open_tag.start,
match self.close_tag {
Some(close) => close.end,
None => self.content.end,
},
)
}
}
#[derive(Debug)]
pub enum ContainerSegment<'container, 'source> {
Interstitial(Span),
Block(&'container Block<'source>),
}
impl ContainerSegment<'_, '_> {
pub const fn span(&self) -> Span {
match self {
Self::Interstitial(span) => *span,
Self::Block(block) => block.authored_span(),
}
}
}
#[derive(Debug)]
pub struct ContainerSegments<'container, 'source> {
blocks: &'container [Block<'source>],
source_end: u32,
index: usize,
}
impl<'container, 'source> Iterator for ContainerSegments<'container, 'source> {
type Item = ContainerSegment<'container, 'source>;
fn next(&mut self) -> Option<Self::Item> {
let len = self.blocks.len().checked_mul(2)?.checked_add(1)?;
if self.index >= len {
return None;
}
let index = self.index;
self.index += 1;
if index % 2 == 1 {
return self.blocks.get(index / 2).map(ContainerSegment::Block);
}
let gap = index / 2;
let start = gap
.checked_sub(1)
.and_then(|previous| self.blocks.get(previous))
.map_or(0, |block| block.authored_span().end);
let end = self
.blocks
.get(gap)
.map_or(self.source_end, |block| block.open_tag.start);
Some(ContainerSegment::Interstitial(Span::new(start, end)))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.len();
(remaining, Some(remaining))
}
}
impl ExactSizeIterator for ContainerSegments<'_, '_> {
fn len(&self) -> usize {
self.blocks
.len()
.checked_mul(2)
.and_then(|len| len.checked_add(1))
.unwrap_or(usize::MAX)
.saturating_sub(self.index)
}
}
impl core::iter::FusedIterator for ContainerSegments<'_, '_> {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BlockAttr<'a> {
pub name: &'a str,
pub value: Option<&'a str>,
pub span: Span,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ContainerError {
pub code: ContainerErrorCode,
pub offset: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ContainerErrorCode {
SourceTooLarge,
UncertainInterpolation,
UnterminatedOpenTag,
MissingCloseTag,
DuplicateBlock,
}