dcbor_pattern/pattern/meta/
capture_pattern.rs

1use dcbor::prelude::*;
2
3use crate::pattern::{Matcher, Path, Pattern, vm::Instr};
4
5/// A pattern that captures matches.
6///
7/// Capture patterns wrap another pattern and assign a name to the paths
8/// that match. The captured paths can be retrieved when pattern matching
9/// is performed.
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct CapturePattern {
12    name: String,
13    pattern: Box<Pattern>,
14}
15
16impl CapturePattern {
17    /// Creates a new `CapturePattern` with the given name and pattern.
18    pub fn new(name: impl AsRef<str>, pattern: Pattern) -> Self {
19        CapturePattern {
20            name: name.as_ref().to_string(),
21            pattern: Box::new(pattern),
22        }
23    }
24
25    /// Returns the name of the capture.
26    pub fn name(&self) -> &str { &self.name }
27
28    /// Returns the inner pattern.
29    pub fn pattern(&self) -> &Pattern { &self.pattern }
30}
31
32impl Matcher for CapturePattern {
33    fn paths(&self, haystack: &CBOR) -> Vec<Path> {
34        // For the basic paths() method, we just return the paths from the inner
35        // pattern The capture functionality is handled by the VM during
36        // compilation/execution
37        self.pattern.paths(haystack)
38    }
39
40    fn compile(
41        &self,
42        code: &mut Vec<Instr>,
43        literals: &mut Vec<Pattern>,
44        captures: &mut Vec<String>,
45    ) {
46        // Register this capture name and get its index
47        let capture_idx = captures.len();
48        captures.push(self.name.clone());
49
50        // Emit capture start instruction
51        code.push(Instr::CaptureStart(capture_idx));
52
53        // Compile the inner pattern
54        self.pattern.compile(code, literals, captures);
55
56        // Emit capture end instruction
57        code.push(Instr::CaptureEnd(capture_idx));
58    }
59
60    fn collect_capture_names(&self, names: &mut Vec<String>) {
61        // Add this capture's name
62        names.push(self.name.clone());
63
64        // Recursively collect from the inner pattern
65        self.pattern.collect_capture_names(names);
66    }
67
68    fn is_complex(&self) -> bool {
69        // A capture pattern is complex if its inner pattern is complex
70        self.pattern.is_complex()
71    }
72
73    fn paths_with_captures(
74        &self,
75        haystack: &CBOR,
76    ) -> (Vec<Path>, std::collections::HashMap<String, Vec<Path>>) {
77        // Get paths from the inner pattern
78        let (paths, mut captures) = self.pattern.paths_with_captures(haystack);
79
80        // For all paths that match, add them as captures for this capture name
81        if !paths.is_empty() {
82            captures.insert(self.name.clone(), paths.clone());
83        }
84
85        (paths, captures)
86    }
87}
88
89impl std::fmt::Display for CapturePattern {
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        write!(f, "@{}({})", self.name, self.pattern)
92    }
93}