1use crate::{
4 Automaton, ByteDomain, ByteOffset, CaptureId, CodeUnitDomain, CodeUnitOffset, ExecutionLimit,
5 ExecutionOutcome, ExecutionReceipt, ScalarDomain, ScalarOffset, SymbolDomain, TextLimits,
6 UnsupportedFeature, execute_regular,
7};
8use sim_text::CodeUnitString;
9use std::collections::BTreeMap;
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub struct DomainCaptureSpan<D: SymbolDomain> {
14 pub start: D::Offset,
16 pub end: D::Offset,
18}
19
20#[derive(Clone, Debug, PartialEq, Eq)]
22pub struct DomainMatch<D: SymbolDomain> {
23 pub start: D::Offset,
25 pub end: D::Offset,
27 pub captures: BTreeMap<CaptureId, DomainCaptureSpan<D>>,
29}
30
31#[derive(Clone, Debug, PartialEq, Eq)]
33pub enum DomainExecutionOutcome<D: SymbolDomain> {
34 Match {
36 matched: DomainMatch<D>,
38 receipt: ExecutionReceipt,
40 },
41 NoMatch {
43 receipt: ExecutionReceipt,
45 },
46 Limit {
48 limit: ExecutionLimit,
50 receipt: ExecutionReceipt,
52 },
53 Unsupported {
55 feature: UnsupportedFeature,
57 receipt: ExecutionReceipt,
59 },
60}
61
62trait IndexedDomain: SymbolDomain {
63 fn offset(index: usize) -> Self::Offset;
64}
65
66impl IndexedDomain for ByteDomain {
67 fn offset(index: usize) -> Self::Offset {
68 ByteOffset(index)
69 }
70}
71
72impl IndexedDomain for ScalarDomain {
73 fn offset(index: usize) -> Self::Offset {
74 ScalarOffset::new(index)
75 }
76}
77
78impl IndexedDomain for CodeUnitDomain {
79 fn offset(index: usize) -> Self::Offset {
80 CodeUnitOffset::new(index)
81 }
82}
83
84fn typed<D: IndexedDomain>(outcome: ExecutionOutcome) -> DomainExecutionOutcome<D> {
85 match outcome {
86 ExecutionOutcome::Match { matched, receipt } => DomainExecutionOutcome::Match {
87 matched: DomainMatch {
88 start: D::offset(matched.start),
89 end: D::offset(matched.end),
90 captures: matched
91 .captures
92 .into_iter()
93 .map(|(id, span)| {
94 (
95 id,
96 DomainCaptureSpan {
97 start: D::offset(span.start),
98 end: D::offset(span.end),
99 },
100 )
101 })
102 .collect(),
103 },
104 receipt,
105 },
106 ExecutionOutcome::NoMatch { receipt } => DomainExecutionOutcome::NoMatch { receipt },
107 ExecutionOutcome::Limit { limit, receipt } => {
108 DomainExecutionOutcome::Limit { limit, receipt }
109 }
110 ExecutionOutcome::Unsupported { feature, receipt } => {
111 DomainExecutionOutcome::Unsupported { feature, receipt }
112 }
113 }
114}
115
116pub fn execute_bytes<E>(
118 automaton: &Automaton<u8, E>,
119 subject: &[u8],
120 limits: TextLimits,
121 extension_matches: impl Fn(&E, &u8) -> bool,
122) -> DomainExecutionOutcome<ByteDomain> {
123 typed(execute_regular(
124 automaton,
125 subject,
126 limits,
127 extension_matches,
128 ))
129}
130
131pub fn execute_scalars<E>(
133 automaton: &Automaton<char, E>,
134 subject: &[char],
135 limits: TextLimits,
136 extension_matches: impl Fn(&E, &char) -> bool,
137) -> DomainExecutionOutcome<ScalarDomain> {
138 typed(execute_regular(
139 automaton,
140 subject,
141 limits,
142 extension_matches,
143 ))
144}
145
146pub fn execute_code_units<E>(
157 automaton: &Automaton<u16, E>,
158 subject: &CodeUnitString,
159 limits: TextLimits,
160 extension_matches: impl Fn(&E, &u16) -> bool,
161) -> DomainExecutionOutcome<CodeUnitDomain> {
162 typed(execute_regular(
163 automaton,
164 subject.as_code_units(),
165 limits,
166 extension_matches,
167 ))
168}
169
170pub const fn require_code_unit_offset(offset: CodeUnitOffset) -> CodeUnitOffset {
172 offset
173}