bc_envelope_pattern/pattern/
pattern_impl.rs

1//! # Pattern
2//!
3//! ## Types of patterns
4//!
5//! The patterns in this crate are divided into three main categories:
6//!
7//! - **Leaf Patterns**: These patterns match specific CBOR values, such as
8//!   booleans, numbers, text, byte strings, dates, and more. They are the most
9//!   basic building blocks of the pattern system.
10//! - **Structure Patterns**: These patterns are used to match the structure of
11//!   envelopes. They can match specific structures, such as assertions,
12//!   subjects, predicates, objects, and more.
13//! - **Meta Patterns**: These patterns are used to combine and modify other
14//!   patterns. They allow you to create complex matching logic by combining
15//!   simpler patterns.
16//!
17//! ## On the difference between *regular* and *binary* regexes
18//!
19//! The text-based patterns in this crate are designed to work with the standard
20//! Rust `str` type, which is a UTF-8 encoded string. However, there are some
21//! patterns that need to work with raw bytes, such as when dealing with CBOR
22//! byte strings or envelope digests. These patterns take "binary regexes".
23//! There are some operational differences between the two types of regexes,
24//! which are summarized in the table below.
25//!
26//! | concern                           | Text Regex                                                                                                                                                                           | Binary Regex                                                                                                                                                                             |
27//! | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
28//! | **Haystack & captures**           | Works on `&str` / `String`; captures are `&str`.                                                                                                                                     | Works on `&[u8]` / `Vec<u8>`; captures are `&[u8]`. That means you can safely search data that is **not valid UTF-8**. ([docs.rs][1])                                                    |
29//! | **Fundamental matching unit**     | By default the engine iterates over **Unicode scalar values** (code-points). `.` matches an entire code-point, even if it takes multiple bytes in UTF-8. ([docs.rs][2])              | When the `u` flag is disabled the engine iterates **byte-by-byte**; `.` then matches exactly one byte. (With `u` on, it behaves like the text engine.) ([docs.rs][2])                    |
30//! | **Turning Unicode off (`(?-u)`)** | Allowed **only** when the resulting pattern still can’t match invalid UTF-8—e.g. `(?-u:\w)` is OK, `(?-u:\xFF)` is *rejected*. This preserves Rust’s `str` invariant. ([docs.rs][2]) | You can disable `u` anywhere, even if that lets the regex match arbitrary byte values such as `\x00` or `\xFF`. This is the big operational freedom “binary” regexes add. ([docs.rs][1]) |
31//! | **Empty-string matches**          | Guaranteed **not** to split a UTF-8 code-point; you’ll see at most one empty match between code-points.                                                                              | May report an empty match **between every byte** (because bytes are the atom). ([docs.rs][2])                                                                                            |
32//! | **Typical use-cases**             | Validating/processing normal text, log files, config files…                                                                                                                          | Packet inspection, parsing binary protocols, scanning blobs that may embed non-UTF-8 data, digging NUL-terminated C strings in memory dumps, etc.                                        |
33//!
34//! ### Example
35//!
36//! A binary regex matching any byte string ending with h'010203':
37//!
38//! ```text
39//! (?s-u).*\x01\x02\x03$
40//! ```
41//!
42//! Note:
43//!
44//! - The `(?s-u)` enables the "dot matches newline" mode, allowing `.` to match
45//!   across newlines, and disables Unicode mode, allowing `.` to match any byte
46//!   value.
47//! - The hexadecimal bytes values must each be prefixed with `\x`.
48//!
49//! ### References
50//!
51//! - <https://docs.rs/regex/latest/regex/bytes/index.html> "regex::bytes - Rust"
52//! - <https://docs.rs/regex/latest/regex/> "regex - Rust"
53
54use std::{
55    cell::RefCell,
56    collections::HashMap,
57    ops::{RangeBounds, RangeInclusive},
58};
59
60use bc_envelope::Envelope;
61use dcbor::prelude::*;
62use known_values::KnownValue;
63
64use super::{
65    Matcher, Path,
66    leaf::{
67        ArrayPattern, BoolPattern, ByteStringPattern, DatePattern,
68        KnownValuePattern, LeafPattern, MapPattern, NullPattern, NumberPattern,
69        TaggedPattern, TextPattern,
70    },
71    meta::{
72        AndPattern, CapturePattern, GroupPattern, MetaPattern, NotPattern,
73        OrPattern, SearchPattern, SequencePattern,
74    },
75    structure::{
76        AssertionsPattern, DigestPattern, NodePattern, ObjectPattern,
77        ObscuredPattern, PredicatePattern, StructurePattern, SubjectPattern,
78        WrappedPattern,
79    },
80    vm,
81};
82use crate::{
83    Quantifier, Reluctance,
84    pattern::{
85        leaf::CBORPattern,
86        meta::{AnyPattern, NonePattern},
87        vm::Instr,
88    },
89};
90
91/// The main pattern type used for matching envelopes.
92#[derive(Debug, Clone, Hash, PartialEq, Eq)]
93pub enum Pattern {
94    /// Leaf patterns for matching CBOR values.
95    Leaf(LeafPattern),
96
97    /// Structure patterns for matching envelope elements.
98    Structure(StructurePattern),
99
100    /// Meta-patterns for combining and modifying other patterns.
101    Meta(MetaPattern),
102}
103
104impl Matcher for Pattern {
105    fn paths(&self, env: &Envelope) -> Vec<Path> {
106        self.paths_with_captures(env).0
107    }
108
109    fn paths_with_captures(
110        &self,
111        env: &Envelope,
112    ) -> (Vec<Path>, HashMap<String, Vec<Path>>) {
113        let results = self.vm_run(env);
114        let mut paths = Vec::new();
115        let mut captures: HashMap<String, Vec<Path>> = HashMap::new();
116        for (p, caps) in results {
117            paths.push(p);
118            for (name, mut vals) in caps {
119                captures.entry(name).or_default().append(&mut vals);
120            }
121        }
122        (paths, captures)
123    }
124
125    fn is_complex(&self) -> bool {
126        match self {
127            Pattern::Leaf(leaf) => leaf.is_complex(),
128            Pattern::Structure(structure) => structure.is_complex(),
129            Pattern::Meta(meta) => meta.is_complex(),
130        }
131    }
132}
133
134// region: Leaf Patterns
135//
136//
137
138impl Pattern {
139    /// Creates a new `Pattern` that matches any leaf.
140    pub fn any_leaf() -> Self { Pattern::Leaf(LeafPattern::Any) }
141}
142
143impl Pattern {
144    /// Creates a new `Pattern` that matches any CBOR value.
145    pub fn any_cbor() -> Self {
146        Pattern::Leaf(LeafPattern::Cbor(CBORPattern::any()))
147    }
148
149    /// Creates a new `Pattern` that matches a specific CBOR value.
150    pub fn cbor(cbor: impl CBOREncodable) -> Self {
151        Pattern::Leaf(LeafPattern::Cbor(CBORPattern::value(cbor)))
152    }
153}
154
155impl Pattern {
156    /// Creates a new `Pattern` that matches any boolean value.
157    pub fn any_bool() -> Self {
158        Pattern::Leaf(LeafPattern::Bool(BoolPattern::any()))
159    }
160
161    /// Creates a new `Pattern` that matches a specific boolean value.
162    pub fn bool(b: bool) -> Self {
163        Pattern::Leaf(LeafPattern::Bool(BoolPattern::value(b)))
164    }
165}
166
167impl Pattern {
168    /// Creates a new `Pattern` that matches any text value.
169    pub fn any_text() -> Self {
170        Pattern::Leaf(LeafPattern::Text(TextPattern::any()))
171    }
172
173    /// Creates a new `Pattern` that matches a specific text value.
174    pub fn text<T: Into<String>>(value: T) -> Self {
175        Pattern::Leaf(LeafPattern::Text(TextPattern::value(value)))
176    }
177
178    /// Creates a new `Pattern` that matches text values that match the given
179    /// regular expression.
180    pub fn text_regex(regex: regex::Regex) -> Self {
181        Pattern::Leaf(LeafPattern::Text(TextPattern::regex(regex)))
182    }
183}
184
185impl Pattern {
186    /// Creates a new `Pattern` that matches any Date (CBOR tag 1) value.
187    pub fn any_date() -> Self {
188        Pattern::Leaf(LeafPattern::Date(DatePattern::any()))
189    }
190
191    /// Creates a new `Pattern` that matches a specific Date (CBOR tag 1) value.
192    pub fn date(date: dcbor::Date) -> Self {
193        Pattern::Leaf(LeafPattern::Date(DatePattern::value(date)))
194    }
195
196    /// Creates a new `Pattern` that matches Date (CBOR tag 1) values within a
197    /// specified range (inclusive).
198    pub fn date_range(range: RangeInclusive<dcbor::Date>) -> Self {
199        Pattern::Leaf(LeafPattern::Date(DatePattern::range(range)))
200    }
201
202    /// Creates a new `Pattern` that matches Date (CBOR tag 1) values that are
203    /// on or after the specified date.
204    pub fn date_earliest(date: dcbor::Date) -> Self {
205        Pattern::Leaf(LeafPattern::Date(DatePattern::earliest(date)))
206    }
207
208    /// Creates a new `Pattern` that matches Date (CBOR tag 1) values that are
209    /// on or before the specified date.
210    pub fn date_latest(date: dcbor::Date) -> Self {
211        Pattern::Leaf(LeafPattern::Date(DatePattern::latest(date)))
212    }
213
214    /// Creates a new `Pattern` that matches Date (CBOR tag 1) values by their
215    /// ISO-8601 string representation.
216    pub fn date_iso8601(iso_string: impl Into<String>) -> Self {
217        Pattern::Leaf(LeafPattern::Date(DatePattern::iso8601(iso_string)))
218    }
219
220    /// Creates a new `Pattern` that matches Date (CBOR tag 1) values whose
221    /// ISO-8601 string representation matches the given regular expression.
222    pub fn date_regex(regex: regex::Regex) -> Self {
223        Pattern::Leaf(LeafPattern::Date(DatePattern::regex(regex)))
224    }
225}
226
227impl Pattern {
228    /// Creates a new `Pattern` that matches any number value.
229    pub fn any_number() -> Self {
230        Pattern::Leaf(LeafPattern::Number(NumberPattern::any()))
231    }
232
233    /// Creates a new `Pattern` that matches a specific number value.
234    pub fn number<T: Into<f64>>(value: T) -> Self {
235        Pattern::Leaf(LeafPattern::Number(NumberPattern::exact(value)))
236    }
237
238    /// Creates a new `Pattern` that matches number values within a specified
239    /// range (inclusive).
240    pub fn number_range<A: Into<f64> + Copy>(range: RangeInclusive<A>) -> Self {
241        Pattern::Leaf(LeafPattern::Number(NumberPattern::range(range)))
242    }
243
244    /// Creates a new `Pattern` that matches number values that are greater than
245    /// the specified value.
246    pub fn number_greater_than<T: Into<f64>>(value: T) -> Self {
247        Pattern::Leaf(LeafPattern::Number(NumberPattern::greater_than(value)))
248    }
249
250    /// Creates a new `Pattern` that matches number values that are greater than
251    /// or equal to the specified value.
252    pub fn number_greater_than_or_equal<T: Into<f64>>(value: T) -> Self {
253        Pattern::Leaf(LeafPattern::Number(
254            NumberPattern::greater_than_or_equal(value),
255        ))
256    }
257
258    /// Creates a new `Pattern` that matches number values that are less than
259    /// the specified value.
260    pub fn number_less_than<T: Into<f64>>(value: T) -> Self {
261        Pattern::Leaf(LeafPattern::Number(NumberPattern::less_than(value)))
262    }
263
264    /// Creates a new `Pattern` that matches number values that are less than or
265    /// equal to the specified value.
266    pub fn number_less_than_or_equal<T: Into<f64>>(value: T) -> Self {
267        Pattern::Leaf(LeafPattern::Number(NumberPattern::less_than_or_equal(
268            value,
269        )))
270    }
271
272    /// Creates a new `Pattern` that matches number values that are NaN (Not a
273    /// Number).
274    pub fn number_nan() -> Self {
275        Pattern::Leaf(LeafPattern::Number(NumberPattern::nan()))
276    }
277}
278
279impl Pattern {
280    /// Creates a new `Pattern` that matches any byte string value.
281    pub fn any_byte_string() -> Self {
282        Pattern::Leaf(LeafPattern::ByteString(ByteStringPattern::any()))
283    }
284
285    /// Creates a new `Pattern` that matches a specific byte string value.
286    pub fn byte_string(value: impl AsRef<[u8]>) -> Self {
287        Pattern::Leaf(LeafPattern::ByteString(ByteStringPattern::value(value)))
288    }
289
290    /// Creates a new `Pattern` that matches byte string values that match the
291    /// given binary regular expression.
292    pub fn byte_string_binary_regex(regex: regex::bytes::Regex) -> Self {
293        Pattern::Leaf(LeafPattern::ByteString(ByteStringPattern::regex(regex)))
294    }
295}
296
297impl Pattern {
298    pub fn any_known_value() -> Self {
299        Pattern::Leaf(LeafPattern::KnownValue(KnownValuePattern::any()))
300    }
301
302    pub fn known_value(value: KnownValue) -> Self {
303        Pattern::Leaf(LeafPattern::KnownValue(KnownValuePattern::value(value)))
304    }
305
306    pub fn known_value_named<T: Into<String>>(name: T) -> Self {
307        Pattern::Leaf(LeafPattern::KnownValue(KnownValuePattern::named(name)))
308    }
309
310    pub fn known_value_regex(regex: regex::Regex) -> Self {
311        Pattern::Leaf(LeafPattern::KnownValue(KnownValuePattern::regex(regex)))
312    }
313
314    pub fn unit() -> Self { Self::known_value(known_values::UNIT) }
315}
316
317impl Pattern {
318    pub fn any_array() -> Self {
319        Pattern::Leaf(LeafPattern::Array(ArrayPattern::any()))
320    }
321
322    pub fn array_with_range(interval: impl RangeBounds<usize>) -> Self {
323        Pattern::Leaf(LeafPattern::Array(ArrayPattern::interval(interval)))
324    }
325
326    pub fn array_with_count(count: usize) -> Self {
327        Pattern::Leaf(LeafPattern::Array(ArrayPattern::interval(count..=count)))
328    }
329}
330
331impl Pattern {
332    pub fn any_map() -> Self {
333        Pattern::Leaf(LeafPattern::Map(MapPattern::any()))
334    }
335
336    pub fn map_with_range(interval: impl RangeBounds<usize>) -> Self {
337        Pattern::Leaf(LeafPattern::Map(MapPattern::interval(interval)))
338    }
339
340    pub fn map_with_count(count: usize) -> Self {
341        Pattern::Leaf(LeafPattern::Map(MapPattern::interval(count..=count)))
342    }
343}
344
345impl Pattern {
346    pub fn null() -> Self {
347        Pattern::Leaf(LeafPattern::Null(NullPattern::new()))
348    }
349}
350
351impl Pattern {
352    pub fn any_tag() -> Self {
353        Pattern::Leaf(LeafPattern::Tag(TaggedPattern::any()))
354    }
355
356    pub fn tagged(tag: dcbor::Tag) -> Self {
357        Pattern::Leaf(LeafPattern::Tag(TaggedPattern::value(tag)))
358    }
359
360    pub fn tagged_with_value(value: u64) -> Self {
361        Pattern::Leaf(LeafPattern::Tag(TaggedPattern::value(value)))
362    }
363
364    pub fn tagged_with_name(name: impl Into<String>) -> Self {
365        Pattern::Leaf(LeafPattern::Tag(TaggedPattern::named(name)))
366    }
367
368    pub fn tagged_with_regex(regex: regex::Regex) -> Self {
369        Pattern::Leaf(LeafPattern::Tag(TaggedPattern::regex(regex)))
370    }
371}
372
373//
374//
375// endregion
376
377// region: Structure Patterns
378//
379//
380
381impl Pattern {
382    pub fn any_assertion() -> Self {
383        Pattern::Structure(StructurePattern::Assertions(
384            AssertionsPattern::any(),
385        ))
386    }
387
388    pub fn assertion_with_predicate(pattern: Pattern) -> Self {
389        Pattern::Structure(StructurePattern::Assertions(
390            AssertionsPattern::with_predicate(pattern),
391        ))
392    }
393
394    pub fn assertion_with_object(pattern: Pattern) -> Self {
395        Pattern::Structure(StructurePattern::Assertions(
396            AssertionsPattern::with_object(pattern),
397        ))
398    }
399}
400
401impl Pattern {
402    pub fn any_subject() -> Self {
403        Pattern::Structure(StructurePattern::Subject(SubjectPattern::any()))
404    }
405
406    pub fn subject(pattern: Pattern) -> Self {
407        Pattern::Structure(StructurePattern::Subject(SubjectPattern::pattern(
408            pattern,
409        )))
410    }
411}
412
413impl Pattern {
414    pub fn any_predicate() -> Self {
415        Pattern::Structure(StructurePattern::Predicate(PredicatePattern::any()))
416    }
417
418    pub fn predicate(pattern: Pattern) -> Self {
419        Pattern::Structure(StructurePattern::Predicate(
420            PredicatePattern::pattern(pattern),
421        ))
422    }
423
424    pub fn any_object() -> Self {
425        Pattern::Structure(StructurePattern::Object(ObjectPattern::any()))
426    }
427
428    pub fn object(pattern: Pattern) -> Self {
429        Pattern::Structure(StructurePattern::Object(ObjectPattern::pattern(
430            pattern,
431        )))
432    }
433}
434
435impl Pattern {
436    pub fn digest(digest: bc_components::Digest) -> Self {
437        Pattern::Structure(StructurePattern::Digest(DigestPattern::digest(
438            digest,
439        )))
440    }
441
442    pub fn digest_prefix(prefix: impl AsRef<[u8]>) -> Self {
443        Pattern::Structure(StructurePattern::Digest(DigestPattern::prefix(
444            prefix,
445        )))
446    }
447
448    pub fn digest_binary_regex(regex: regex::bytes::Regex) -> Self {
449        Pattern::Structure(StructurePattern::Digest(
450            DigestPattern::binary_regex(regex),
451        ))
452    }
453
454    pub fn any_node() -> Self {
455        Pattern::Structure(StructurePattern::Node(NodePattern::any()))
456    }
457
458    pub fn node_with_assertions_range(range: impl RangeBounds<usize>) -> Self {
459        Pattern::Structure(StructurePattern::Node(NodePattern::interval(range)))
460    }
461
462    pub fn node_with_assertions_count(count: usize) -> Self {
463        Pattern::Structure(StructurePattern::Node(NodePattern::interval(
464            count..=count,
465        )))
466    }
467
468    pub fn obscured() -> Self {
469        Pattern::Structure(StructurePattern::Obscured(ObscuredPattern::any()))
470    }
471
472    pub fn elided() -> Self {
473        Pattern::Structure(
474            StructurePattern::Obscured(ObscuredPattern::elided()),
475        )
476    }
477
478    pub fn encrypted() -> Self {
479        Pattern::Structure(StructurePattern::Obscured(
480            ObscuredPattern::encrypted(),
481        ))
482    }
483
484    pub fn compressed() -> Self {
485        Pattern::Structure(StructurePattern::Obscured(
486            ObscuredPattern::compressed(),
487        ))
488    }
489}
490
491//
492//
493// endregion
494
495// region: Meta Patterns
496//
497//
498
499impl Pattern {
500    /// Creates a new `Pattern` that matches any element.
501    pub fn any() -> Self { Pattern::Meta(MetaPattern::Any(AnyPattern::new())) }
502
503    /// Creates a new `Pattern` that never matches any element.
504    pub fn none() -> Self {
505        Pattern::Meta(MetaPattern::None(NonePattern::new()))
506    }
507}
508
509impl Pattern {
510    /// Creates a new `Pattern` that only matches if all specified patterns
511    /// match.
512    pub fn and(patterns: Vec<Pattern>) -> Self {
513        Pattern::Meta(MetaPattern::And(AndPattern::new(patterns)))
514    }
515
516    /// Creates a new `Pattern` that matches if at least one of the specified
517    /// patterns matches.
518    pub fn or(patterns: Vec<Pattern>) -> Self {
519        Pattern::Meta(MetaPattern::Or(OrPattern::new(patterns)))
520    }
521}
522
523impl Pattern {
524    /// Creates a new `Pattern` that matches a sequence of patterns in order.
525    pub fn sequence(patterns: Vec<Pattern>) -> Self {
526        Pattern::Meta(MetaPattern::Sequence(SequencePattern::new(patterns)))
527    }
528}
529
530impl Pattern {
531    /// Creates a new `Pattern` that searches for a specific pattern within the
532    /// envelope. Useful for finding patterns that may not be at the root
533    /// of the envelope.
534    pub fn search(pattern: Pattern) -> Self {
535        Pattern::Meta(MetaPattern::Search(SearchPattern::new(pattern)))
536    }
537}
538
539impl Pattern {
540    /// Creates a new `Pattern` that negates another pattern; matches if the
541    /// specified pattern does not match.
542    pub fn not_matching(pattern: Pattern) -> Self {
543        Pattern::Meta(MetaPattern::Not(NotPattern::new(pattern)))
544    }
545}
546
547impl Pattern {
548    /// Compile self to byte-code (recursive).
549    pub(crate) fn compile(
550        &self,
551        code: &mut Vec<Instr>,
552        lits: &mut Vec<Pattern>,
553        captures: &mut Vec<String>,
554    ) {
555        use Pattern::*;
556        match self {
557            Leaf(leaf_pattern) => leaf_pattern.compile(code, lits, captures),
558            Structure(struct_pattern) => {
559                struct_pattern.compile(code, lits, captures)
560            }
561            Meta(meta_pattern) => meta_pattern.compile(code, lits, captures),
562        }
563    }
564}
565
566impl Pattern {
567    /// Creates a new `Pattern` that will match a pattern repeated a number of
568    /// times according to the specified range and greediness.
569    ///
570    /// In regex terms:
571    ///
572    /// | Range         | Quantifier   |
573    /// | :------------ | :----------- |
574    /// | `..`          | `*`          |
575    /// | `1..`         | `+`          |
576    /// | `0..=1`       | `?`          |
577    /// | `min..=max`   | `{min,max}`  |
578    /// | `min..`       | `{min,}`     |
579    /// | `..=max`      | `{0,max}`    |
580    /// | `n..=n`       | `{n}`        |
581    pub fn repeat(
582        pattern: Pattern,
583        interval: impl RangeBounds<usize>,
584        reluctance: Reluctance,
585    ) -> Self {
586        Pattern::Meta(MetaPattern::Group(GroupPattern::repeat(
587            pattern,
588            Quantifier::new(interval, reluctance),
589        )))
590    }
591
592    pub fn group(pattern: Pattern) -> Self {
593        Pattern::Meta(MetaPattern::Group(GroupPattern::new(pattern)))
594    }
595}
596
597impl Pattern {
598    /// Creates a new `Pattern` that will capture a pattern match with a name.
599    pub fn capture(name: impl AsRef<str>, pattern: Pattern) -> Self {
600        Pattern::Meta(MetaPattern::Capture(CapturePattern::new(name, pattern)))
601    }
602}
603
604//
605//
606// endregion
607
608impl std::fmt::Display for Pattern {
609    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
610        match self {
611            Pattern::Leaf(leaf) => write!(f, "{}", leaf),
612            Pattern::Structure(structure) => write!(f, "{}", structure),
613            Pattern::Meta(meta) => write!(f, "{}", meta),
614        }
615    }
616}
617
618impl Pattern {
619    /// Internal helper that runs the pattern through the VM and returns the
620    /// matching paths.
621    fn vm_run(
622        &self,
623        env: &Envelope,
624    ) -> Vec<(Path, HashMap<String, Vec<Path>>)> {
625        thread_local! {
626            static PROG: RefCell<HashMap<u64, vm::Program>> = RefCell::new(HashMap::new());
627        }
628
629        // cheap structural hash
630        use std::{
631            collections::hash_map::DefaultHasher,
632            hash::{Hash, Hasher},
633        };
634        let mut h = DefaultHasher::new();
635        self.hash(&mut h);
636        let key = h.finish();
637
638        let prog = PROG
639            .with(|cell| cell.borrow().get(&key).cloned())
640            .unwrap_or_else(|| {
641                let mut p = vm::Program {
642                    code: Vec::new(),
643                    literals: Vec::new(),
644                    capture_names: Vec::new(),
645                };
646                self.compile(
647                    &mut p.code,
648                    &mut p.literals,
649                    &mut p.capture_names,
650                );
651                p.code.push(Instr::Accept);
652                PROG.with(|cell| {
653                    cell.borrow_mut().insert(key, p.clone());
654                });
655                p
656            });
657
658        vm::run(&prog, env)
659    }
660
661    #[allow(dead_code)]
662    fn vm_paths(&self, env: &Envelope) -> Vec<Path> {
663        self.vm_run(env).into_iter().map(|(p, _)| p).collect()
664    }
665
666    pub(crate) fn collect_capture_names(&self, out: &mut Vec<String>) {
667        if let Pattern::Meta(meta) = self {
668            meta.collect_capture_names(out)
669        }
670    }
671}
672
673impl Pattern {
674    /// Creates a new `Pattern` that matches any wrapped envelope without
675    /// descending. Renamed from `wrapped()` to break tests so they can be
676    /// fixed.
677    pub fn wrapped() -> Self {
678        Pattern::Structure(StructurePattern::Wrapped(WrappedPattern::new()))
679    }
680
681    /// Creates a new `Pattern` that matches a wrapped envelope and also matches
682    /// on its unwrapped content.
683    pub fn unwrap_matching(pattern: Pattern) -> Self {
684        Pattern::Structure(StructurePattern::Wrapped(
685            WrappedPattern::unwrap_matching(pattern),
686        ))
687    }
688
689    /// Creates a new `Pattern` that matches any wrapped envelope and descends
690    /// into it.
691    pub fn unwrap() -> Self {
692        Pattern::Structure(StructurePattern::Wrapped(WrappedPattern::unwrap()))
693    }
694}