dcbor_pattern/pattern/
mod.rs

1mod matcher;
2mod meta;
3mod structure;
4mod value;
5mod vm;
6
7use dcbor::prelude::*;
8pub use matcher::*;
9pub use meta::*;
10pub use structure::*;
11pub use value::*;
12pub use vm::*;
13
14use crate::{Error, Result};
15
16pub type Path = Vec<CBOR>;
17
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub enum Pattern {
20    Value(ValuePattern),
21    Structure(StructurePattern),
22    Meta(MetaPattern),
23}
24
25impl Pattern {
26    /// Creates a pattern that matches any boolean value.
27    pub fn any_bool() -> Self {
28        Pattern::Value(ValuePattern::Bool(
29            crate::pattern::value::BoolPattern::any(),
30        ))
31    }
32
33    /// Creates a pattern that matches a specific boolean value.
34    pub fn bool(value: bool) -> Self {
35        Pattern::Value(ValuePattern::Bool(
36            crate::pattern::value::BoolPattern::value(value),
37        ))
38    }
39
40    /// Creates a pattern that matches any number value.
41    pub fn any_number() -> Self {
42        Pattern::Value(ValuePattern::Number(
43            crate::pattern::value::NumberPattern::any(),
44        ))
45    }
46
47    /// Creates a pattern that matches a specific number value.
48    pub fn number<T>(value: T) -> Self
49    where
50        T: Into<f64>,
51    {
52        Pattern::Value(ValuePattern::Number(
53            crate::pattern::value::NumberPattern::value(value),
54        ))
55    }
56
57    /// Creates a pattern that matches numbers within a range.
58    pub fn number_range<A>(range: std::ops::RangeInclusive<A>) -> Self
59    where
60        A: Into<f64> + Copy,
61    {
62        Pattern::Value(ValuePattern::Number(
63            crate::pattern::value::NumberPattern::range(range),
64        ))
65    }
66
67    /// Creates a pattern that matches numbers greater than the specified value.
68    pub fn number_greater_than<T>(value: T) -> Self
69    where
70        T: Into<f64>,
71    {
72        Pattern::Value(ValuePattern::Number(
73            crate::pattern::value::NumberPattern::greater_than(value),
74        ))
75    }
76
77    /// Creates a pattern that matches numbers greater than or equal to the
78    /// specified value.
79    pub fn number_greater_than_or_equal<T>(value: T) -> Self
80    where
81        T: Into<f64>,
82    {
83        Pattern::Value(ValuePattern::Number(
84            crate::pattern::value::NumberPattern::greater_than_or_equal(value),
85        ))
86    }
87
88    /// Creates a pattern that matches numbers less than the specified value.
89    pub fn number_less_than<T>(value: T) -> Self
90    where
91        T: Into<f64>,
92    {
93        Pattern::Value(ValuePattern::Number(
94            crate::pattern::value::NumberPattern::less_than(value),
95        ))
96    }
97
98    /// Creates a pattern that matches numbers less than or equal to the
99    /// specified value.
100    pub fn number_less_than_or_equal<T>(value: T) -> Self
101    where
102        T: Into<f64>,
103    {
104        Pattern::Value(ValuePattern::Number(
105            crate::pattern::value::NumberPattern::less_than_or_equal(value),
106        ))
107    }
108
109    /// Creates a pattern that matches NaN values.
110    pub fn number_nan() -> Self {
111        Pattern::Value(ValuePattern::Number(
112            crate::pattern::value::NumberPattern::nan(),
113        ))
114    }
115
116    /// Creates a pattern that matches positive infinity values.
117    pub fn number_infinity() -> Self {
118        Pattern::Value(ValuePattern::Number(
119            crate::pattern::value::NumberPattern::infinity(),
120        ))
121    }
122
123    /// Creates a pattern that matches negative infinity values.
124    pub fn number_neg_infinity() -> Self {
125        Pattern::Value(ValuePattern::Number(
126            crate::pattern::value::NumberPattern::neg_infinity(),
127        ))
128    }
129
130    /// Creates a pattern that matches any text value.
131    pub fn any_text() -> Self {
132        Pattern::Value(ValuePattern::Text(
133            crate::pattern::value::TextPattern::any(),
134        ))
135    }
136
137    /// Creates a pattern that matches a specific text value.
138    pub fn text<T: Into<String>>(value: T) -> Self {
139        Pattern::Value(ValuePattern::Text(
140            crate::pattern::value::TextPattern::value(value),
141        ))
142    }
143
144    /// Creates a pattern that matches text using a regex.
145    pub fn text_regex(regex: regex::Regex) -> Self {
146        Pattern::Value(ValuePattern::Text(
147            crate::pattern::value::TextPattern::regex(regex),
148        ))
149    }
150
151    /// Creates a pattern that matches any byte string value.
152    pub fn any_byte_string() -> Self {
153        Pattern::Value(ValuePattern::ByteString(
154            crate::pattern::value::ByteStringPattern::any(),
155        ))
156    }
157
158    /// Creates a pattern that matches a specific byte string value.
159    pub fn byte_string(value: impl AsRef<[u8]>) -> Self {
160        Pattern::Value(ValuePattern::ByteString(
161            crate::pattern::value::ByteStringPattern::value(value),
162        ))
163    }
164
165    /// Creates a pattern that matches byte strings using a binary regex.
166    pub fn byte_string_regex(regex: regex::bytes::Regex) -> Self {
167        Pattern::Value(ValuePattern::ByteString(
168            crate::pattern::value::ByteStringPattern::regex(regex),
169        ))
170    }
171
172    /// Creates a pattern that matches any date value.
173    pub fn any_date() -> Self {
174        Pattern::Value(ValuePattern::Date(
175            crate::pattern::value::DatePattern::any(),
176        ))
177    }
178
179    /// Creates a pattern that matches a specific date value.
180    pub fn date(date: Date) -> Self {
181        Pattern::Value(ValuePattern::Date(
182            crate::pattern::value::DatePattern::value(date),
183        ))
184    }
185
186    /// Creates a pattern that matches dates within a range (inclusive).
187    pub fn date_range(range: std::ops::RangeInclusive<Date>) -> Self {
188        Pattern::Value(ValuePattern::Date(
189            crate::pattern::value::DatePattern::range(range),
190        ))
191    }
192
193    /// Creates a pattern that matches dates that are on or after the specified
194    /// date.
195    pub fn date_earliest(date: Date) -> Self {
196        Pattern::Value(ValuePattern::Date(
197            crate::pattern::value::DatePattern::earliest(date),
198        ))
199    }
200
201    /// Creates a pattern that matches dates that are on or before the specified
202    /// date.
203    pub fn date_latest(date: Date) -> Self {
204        Pattern::Value(ValuePattern::Date(
205            crate::pattern::value::DatePattern::latest(date),
206        ))
207    }
208
209    /// Creates a pattern that matches a date by its ISO-8601 string
210    /// representation.
211    pub fn date_iso8601(iso_string: impl Into<String>) -> Self {
212        Pattern::Value(ValuePattern::Date(
213            crate::pattern::value::DatePattern::string(iso_string),
214        ))
215    }
216
217    /// Creates a pattern that matches dates whose ISO-8601 string
218    /// representation matches the given regex pattern.
219    pub fn date_regex(regex: regex::Regex) -> Self {
220        Pattern::Value(ValuePattern::Date(
221            crate::pattern::value::DatePattern::regex(regex),
222        ))
223    }
224
225    /// Creates a pattern that matches null values.
226    pub fn null() -> Self {
227        Pattern::Value(ValuePattern::Null(crate::pattern::value::NullPattern))
228    }
229
230    /// Creates a pattern that matches any known value.
231    pub fn any_known_value() -> Self {
232        Pattern::Value(ValuePattern::KnownValue(
233            crate::pattern::value::KnownValuePattern::any(),
234        ))
235    }
236
237    /// Creates a pattern that matches a specific known value.
238    pub fn known_value(value: known_values::KnownValue) -> Self {
239        Pattern::Value(ValuePattern::KnownValue(
240            crate::pattern::value::KnownValuePattern::value(value),
241        ))
242    }
243
244    /// Creates a pattern that matches a known value by name.
245    pub fn known_value_named(name: impl Into<String>) -> Self {
246        Pattern::Value(ValuePattern::KnownValue(
247            crate::pattern::value::KnownValuePattern::named(name),
248        ))
249    }
250
251    /// Creates a pattern that matches known values using a regex on their
252    /// names.
253    pub fn known_value_regex(regex: regex::Regex) -> Self {
254        Pattern::Value(ValuePattern::KnownValue(
255            crate::pattern::value::KnownValuePattern::regex(regex),
256        ))
257    }
258
259    // Digest pattern convenience methods
260
261    /// Creates a pattern that matches any digest value.
262    pub fn any_digest() -> Self {
263        Pattern::Value(ValuePattern::Digest(
264            crate::pattern::value::DigestPattern::any(),
265        ))
266    }
267
268    /// Creates a pattern that matches a specific digest.
269    pub fn digest(digest: bc_components::Digest) -> Self {
270        Pattern::Value(ValuePattern::Digest(
271            crate::pattern::value::DigestPattern::digest(digest),
272        ))
273    }
274
275    /// Creates a pattern that matches digests with the specified prefix.
276    pub fn digest_prefix(prefix: impl AsRef<[u8]>) -> Self {
277        Pattern::Value(ValuePattern::Digest(
278            crate::pattern::value::DigestPattern::prefix(prefix),
279        ))
280    }
281
282    /// Creates a pattern that matches digests using a binary regex.
283    pub fn digest_binary_regex(regex: regex::bytes::Regex) -> Self {
284        Pattern::Value(ValuePattern::Digest(
285            crate::pattern::value::DigestPattern::binary_regex(regex),
286        ))
287    }
288
289    /// Creates a pattern that always matches any CBOR value.
290    pub fn any() -> Self {
291        Pattern::Meta(MetaPattern::Any(crate::pattern::meta::AnyPattern::new()))
292    }
293
294    /// Creates a pattern that matches if all contained patterns match.
295    pub fn and(patterns: Vec<Pattern>) -> Self {
296        Pattern::Meta(MetaPattern::And(crate::pattern::meta::AndPattern::new(
297            patterns,
298        )))
299    }
300
301    /// Creates a pattern that matches if any contained pattern matches.
302    pub fn or(patterns: Vec<Pattern>) -> Self {
303        Pattern::Meta(MetaPattern::Or(crate::pattern::meta::OrPattern::new(
304            patterns,
305        )))
306    }
307
308    /// Creates a pattern that matches if the inner pattern does not match.
309    pub fn not_matching(pattern: Pattern) -> Self {
310        Pattern::Meta(MetaPattern::Not(crate::pattern::meta::NotPattern::new(
311            pattern,
312        )))
313    }
314
315    /// Creates a pattern that captures matches with the given name.
316    pub fn capture(name: impl AsRef<str>, pattern: Pattern) -> Self {
317        Pattern::Meta(MetaPattern::Capture(
318            crate::pattern::meta::CapturePattern::new(name, pattern),
319        ))
320    }
321
322    /// Creates a search pattern that recursively searches the entire dCBOR
323    /// tree.
324    pub fn search(pattern: Pattern) -> Self {
325        Pattern::Meta(MetaPattern::Search(
326            crate::pattern::meta::SearchPattern::new(pattern),
327        ))
328    }
329
330    /// Creates a pattern that matches with repetition using a quantifier.
331    pub fn repeat(pattern: Pattern, quantifier: crate::Quantifier) -> Self {
332        Pattern::Meta(MetaPattern::Repeat(
333            crate::pattern::meta::RepeatPattern::repeat(pattern, quantifier),
334        ))
335    }
336
337    /// Creates a pattern that wraps another pattern (matches exactly once).
338    pub fn group(pattern: Pattern) -> Self {
339        Pattern::Meta(MetaPattern::Repeat(
340            crate::pattern::meta::RepeatPattern::new(pattern),
341        ))
342    }
343
344    /// Creates a sequence pattern that matches patterns in order.
345    pub fn sequence(patterns: Vec<Pattern>) -> Self {
346        Pattern::Meta(MetaPattern::Sequence(
347            crate::pattern::meta::SequencePattern::new(patterns),
348        ))
349    }
350
351    /// Creates a pattern that matches any array.
352    pub fn any_array() -> Self {
353        Pattern::Structure(crate::pattern::structure::StructurePattern::Array(
354            crate::pattern::structure::ArrayPattern::any(),
355        ))
356    }
357
358    /// Creates a pattern that matches any map.
359    pub fn any_map() -> Self {
360        Pattern::Structure(crate::pattern::structure::StructurePattern::Map(
361            crate::pattern::structure::MapPattern::any(),
362        ))
363    }
364}
365
366impl Pattern {
367    /// Creates a pattern that matches any tagged value.
368    pub fn any_tagged() -> Self {
369        Pattern::Structure(crate::pattern::structure::StructurePattern::Tagged(
370            crate::pattern::structure::TaggedPattern::any(),
371        ))
372    }
373
374    /// Creates a pattern that matches a tagged item with content pattern.
375    pub fn tagged(tag: impl Into<Tag>, pattern: Pattern) -> Self {
376        Pattern::Structure(crate::pattern::structure::StructurePattern::Tagged(
377            crate::pattern::structure::TaggedPattern::with_tag(tag, pattern),
378        ))
379    }
380
381    /// Creates a pattern that matches a tagged item with content pattern and
382    /// a specific tag name.
383    pub fn tagged_name(name: impl Into<String>, pattern: Pattern) -> Self {
384        Pattern::Structure(crate::pattern::structure::StructurePattern::Tagged(
385            crate::pattern::structure::TaggedPattern::with_name(name, pattern),
386        ))
387    }
388
389    /// Creates a pattern that matches a tagged item with content pattern and
390    /// a regex for the tag name.
391    pub fn tagged_regex(regex: regex::Regex, pattern: Pattern) -> Self {
392        Pattern::Structure(crate::pattern::structure::StructurePattern::Tagged(
393            crate::pattern::structure::TaggedPattern::with_regex(
394                regex, pattern,
395            ),
396        ))
397    }
398}
399
400impl TryFrom<&str> for Pattern {
401    type Error = Error;
402
403    fn try_from(value: &str) -> Result<Self> { Self::parse(value) }
404}
405
406impl Matcher for Pattern {
407    fn paths_with_captures(
408        &self,
409        haystack: &CBOR,
410    ) -> (Vec<Path>, std::collections::HashMap<String, Vec<Path>>) {
411        // Collect all capture names from this pattern
412        let mut capture_names = Vec::new();
413        self.collect_capture_names(&mut capture_names);
414
415        // If no captures, use the faster direct path matching
416        if capture_names.is_empty() {
417            return (self.paths(haystack), std::collections::HashMap::new());
418        }
419
420        // For certain pattern types, delegate directly to their
421        // paths_with_captures
422        match self {
423            Pattern::Meta(pattern) => {
424                // Meta patterns like SearchPattern handle their own capture
425                // logic
426                return pattern.paths_with_captures(haystack);
427            }
428            Pattern::Structure(pattern) => {
429                // Structure patterns like ArrayPattern handle their own capture
430                // logic, including special handling for SequencePattern
431                return pattern.paths_with_captures(haystack);
432            }
433            _ => {
434                // Use VM for other pattern types that need it
435            }
436        }
437
438        // Compile pattern to VM program for capture-aware matching
439        let mut code = Vec::new();
440        let mut literals = Vec::new();
441        let mut captures = Vec::new();
442
443        self.compile(&mut code, &mut literals, &mut captures);
444        code.push(crate::pattern::vm::Instr::Accept);
445
446        let program = crate::pattern::vm::Program {
447            code,
448            literals,
449            capture_names: captures,
450        };
451
452        // Run VM to get paths and captures
453        crate::pattern::vm::run(&program, haystack)
454    }
455
456    fn paths(&self, haystack: &CBOR) -> Vec<Path> {
457        match self {
458            Pattern::Value(pattern) => pattern.paths(haystack),
459            Pattern::Structure(pattern) => pattern.paths(haystack),
460            Pattern::Meta(pattern) => pattern.paths(haystack),
461        }
462    }
463
464    fn compile(
465        &self,
466        code: &mut Vec<Instr>,
467        literals: &mut Vec<Pattern>,
468        captures: &mut Vec<String>,
469    ) {
470        match self {
471            Pattern::Value(pattern) => {
472                pattern.compile(code, literals, captures);
473            }
474            Pattern::Structure(pattern) => {
475                pattern.compile(code, literals, captures);
476            }
477            Pattern::Meta(pattern) => {
478                pattern.compile(code, literals, captures);
479            }
480        }
481    }
482
483    /// Recursively collect all capture names from this pattern.
484    fn collect_capture_names(&self, names: &mut Vec<String>) {
485        match self {
486            Pattern::Value(_) => {
487                // Value patterns don't contain captures
488            }
489            Pattern::Structure(pattern) => {
490                pattern.collect_capture_names(names);
491            }
492            Pattern::Meta(pattern) => {
493                pattern.collect_capture_names(names);
494            }
495        }
496    }
497
498    fn is_complex(&self) -> bool {
499        match self {
500            Pattern::Value(pattern) => pattern.is_complex(),
501            Pattern::Structure(_pattern) => false, /* TODO: implement when */
502            // ready
503            Pattern::Meta(pattern) => pattern.is_complex(),
504        }
505    }
506}
507
508impl std::fmt::Display for Pattern {
509    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
510        match self {
511            Pattern::Value(pattern) => write!(f, "{}", pattern),
512            Pattern::Structure(pattern) => write!(f, "{}", pattern),
513            Pattern::Meta(pattern) => write!(f, "{}", pattern),
514        }
515    }
516}