use crate::{depth::Depth, engine::error::EngineError};
use std::{convert::Infallible, fmt::Display, io, ops::Deref};
pub mod approx_span;
pub mod count;
pub mod empty;
pub mod index;
pub mod nodes;
mod output_queue;
pub type MatchCount = u64;
pub type MatchIndex = usize;
#[derive(Clone, Copy)]
pub struct MatchSpan {
start_idx: MatchIndex,
len: usize,
}
pub struct Match {
bytes: Vec<u8>,
span_start: usize,
}
impl MatchSpan {
pub(crate) fn from_indices(start_idx: usize, end_idx: usize) -> Self {
assert!(
start_idx <= end_idx,
"start of span {start_idx} is greater than end {end_idx}"
);
Self {
start_idx,
len: end_idx - start_idx,
}
}
#[inline(always)]
#[must_use]
pub fn start_idx(&self) -> usize {
self.start_idx
}
#[inline(always)]
#[must_use]
pub fn end_idx(&self) -> usize {
self.start_idx + self.len
}
#[inline(always)]
#[must_use]
#[allow(
clippy::len_without_is_empty,
reason = "is_empty makes no sense for a match (matches are non-empty)"
)]
pub fn len(&self) -> usize {
self.len
}
}
impl Match {
pub(crate) fn from_start_and_bytes(span_start: usize, bytes: Vec<u8>) -> Self {
Self { bytes, span_start }
}
#[inline(always)]
#[must_use]
pub fn bytes(&self) -> &[u8] {
&self.bytes
}
#[inline(always)]
#[must_use]
pub fn into_bytes(self) -> Vec<u8> {
self.bytes
}
#[inline(always)]
#[must_use]
pub fn span(&self) -> MatchSpan {
MatchSpan {
start_idx: self.span_start,
len: self.bytes.len(),
}
}
}
impl Display for MatchSpan {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[{}..{}]", self.start_idx, self.end_idx())
}
}
impl Display for Match {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let display = String::from_utf8_lossy(&self.bytes);
write!(f, "{display}")
}
}
pub trait Sink<D> {
type Error: std::error::Error + Send + Sync + 'static;
fn add_match(&mut self, data: D) -> Result<(), Self::Error>;
}
impl<D> Sink<D> for Vec<D> {
type Error = Infallible;
#[inline(always)]
fn add_match(&mut self, data: D) -> Result<(), Infallible> {
self.push(data);
Ok(())
}
}
pub struct NullSink;
impl<D> Sink<D> for NullSink {
type Error = Infallible;
#[inline(always)]
fn add_match(&mut self, _data: D) -> Result<(), Infallible> {
Ok(())
}
}
pub struct MatchWriter<W>(W);
impl<W> From<W> for MatchWriter<W>
where
W: io::Write,
{
#[inline(always)]
fn from(value: W) -> Self {
Self(value)
}
}
impl<D, W> Sink<D> for MatchWriter<W>
where
D: Display,
W: io::Write,
{
type Error = io::Error;
#[inline(always)]
fn add_match(&mut self, data: D) -> Result<(), io::Error> {
writeln!(self.0, "{data}")
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum MatchedNodeType {
Atomic,
Complex,
}
pub trait InputRecorder<B: Deref<Target = [u8]>> {
fn record_block_start(&self, new_block: B);
}
pub trait Recorder<B: Deref<Target = [u8]>>: InputRecorder<B> {
fn record_match(&self, idx: usize, depth: Depth, ty: MatchedNodeType) -> Result<(), EngineError>;
fn record_value_terminator(&self, idx: usize, depth: Depth) -> Result<(), EngineError>;
}