1use crate::{depth::Depth, engine::error::EngineError};
3use std::{convert::Infallible, fmt::Display, io, ops::Deref};
4
5pub mod approx_span;
6pub mod count;
7pub mod empty;
8pub mod index;
9pub mod nodes;
10mod output_queue;
11
12pub type MatchCount = u64;
14
15pub type MatchIndex = usize;
17
18#[derive(Clone, Copy)]
27pub struct MatchSpan {
28 start_idx: MatchIndex,
30 len: usize,
32}
33
34pub struct Match {
37 bytes: Vec<u8>,
39 span_start: usize,
41}
42
43impl MatchSpan {
44 pub(crate) fn from_indices(start_idx: usize, end_idx: usize) -> Self {
45 assert!(
46 start_idx <= end_idx,
47 "start of span {start_idx} is greater than end {end_idx}"
48 );
49 Self {
50 start_idx,
51 len: end_idx - start_idx,
52 }
53 }
54
55 #[inline(always)]
57 #[must_use]
58 pub fn start_idx(&self) -> usize {
59 self.start_idx
60 }
61
62 #[inline(always)]
64 #[must_use]
65 pub fn end_idx(&self) -> usize {
66 self.start_idx + self.len
67 }
68
69 #[inline(always)]
71 #[must_use]
72 #[allow(
73 clippy::len_without_is_empty,
74 reason = "is_empty makes no sense for a match (matches are non-empty)"
75 )]
76 pub fn len(&self) -> usize {
77 self.len
78 }
79}
80
81impl Match {
82 pub(crate) fn from_start_and_bytes(span_start: usize, bytes: Vec<u8>) -> Self {
83 Self { bytes, span_start }
84 }
85
86 #[inline(always)]
88 #[must_use]
89 pub fn bytes(&self) -> &[u8] {
90 &self.bytes
91 }
92
93 #[inline(always)]
95 #[must_use]
96 pub fn into_bytes(self) -> Vec<u8> {
97 self.bytes
98 }
99
100 #[inline(always)]
103 #[must_use]
104 pub fn span(&self) -> MatchSpan {
105 MatchSpan {
106 start_idx: self.span_start,
107 len: self.bytes.len(),
108 }
109 }
110}
111
112impl Display for MatchSpan {
113 #[inline]
114 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115 write!(f, "[{}..{}]", self.start_idx, self.end_idx())
116 }
117}
118
119impl Display for Match {
120 #[inline]
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 let display = String::from_utf8_lossy(&self.bytes);
123 write!(f, "{display}")
124 }
125}
126
127pub trait Sink<D> {
129 type Error: std::error::Error + Send + Sync + 'static;
131
132 fn add_match(&mut self, data: D) -> Result<(), Self::Error>;
139}
140
141impl<D> Sink<D> for Vec<D> {
142 type Error = Infallible;
143
144 #[inline(always)]
145 fn add_match(&mut self, data: D) -> Result<(), Infallible> {
146 self.push(data);
147 Ok(())
148 }
149}
150
151pub struct NullSink;
153
154impl<D> Sink<D> for NullSink {
155 type Error = Infallible;
156
157 #[inline(always)]
158 fn add_match(&mut self, _data: D) -> Result<(), Infallible> {
159 Ok(())
160 }
161}
162
163pub struct MatchWriter<W>(W);
165
166impl<W> From<W> for MatchWriter<W>
167where
168 W: io::Write,
169{
170 #[inline(always)]
171 fn from(value: W) -> Self {
172 Self(value)
173 }
174}
175
176impl<D, W> Sink<D> for MatchWriter<W>
177where
178 D: Display,
179 W: io::Write,
180{
181 type Error = io::Error;
182
183 #[inline(always)]
184 fn add_match(&mut self, data: D) -> Result<(), io::Error> {
185 writeln!(self.0, "{data}")
186 }
187}
188
189#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
191pub enum MatchedNodeType {
192 Atomic,
194 Complex,
196}
197
198pub trait InputRecorder<B: Deref<Target = [u8]>> {
200 fn record_block_start(&self, new_block: B);
205}
206
207pub trait Recorder<B: Deref<Target = [u8]>>: InputRecorder<B> {
210 fn record_match(&self, idx: usize, depth: Depth, ty: MatchedNodeType) -> Result<(), EngineError>;
219
220 fn record_value_terminator(&self, idx: usize, depth: Depth) -> Result<(), EngineError>;
228}