dcbor_pattern/pattern/structure/
map_pattern.rs1use std::ops::RangeBounds;
2
3use dcbor::prelude::*;
4
5use crate::{
6 Interval,
7 pattern::{Matcher, Path, Pattern, vm::Instr},
8};
9
10#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum MapPattern {
13 Any,
15 Constraints(Vec<(Pattern, Pattern)>),
18 Length(Interval),
20}
21
22impl MapPattern {
23 pub fn any() -> Self { MapPattern::Any }
25
26 pub fn with_key_value_constraints(
29 constraints: Vec<(Pattern, Pattern)>,
30 ) -> Self {
31 MapPattern::Constraints(constraints)
32 }
33
34 pub fn with_length(length: usize) -> Self {
37 MapPattern::Length(Interval::new(length..=length))
38 }
39
40 pub fn with_length_range<R: RangeBounds<usize>>(range: R) -> Self {
43 MapPattern::Length(Interval::new(range))
44 }
45
46 pub fn with_length_interval(interval: Interval) -> Self {
49 MapPattern::Length(interval)
50 }
51}
52
53impl Matcher for MapPattern {
54 fn paths(&self, haystack: &CBOR) -> Vec<Path> {
55 match haystack.as_case() {
57 CBORCase::Map(map) => {
58 match self {
59 MapPattern::Any => {
60 vec![vec![haystack.clone()]]
62 }
63 MapPattern::Constraints(constraints) => {
64 for (key_pattern, value_pattern) in constraints {
66 let mut found_match = false;
67 for (key, value) in map.iter() {
68 if key_pattern.matches(key)
69 && value_pattern.matches(value)
70 {
71 found_match = true;
72 break;
73 }
74 }
75 if !found_match {
76 return vec![];
77 }
78 }
79 vec![vec![haystack.clone()]]
80 }
81 MapPattern::Length(interval) => {
82 if interval.contains(map.len()) {
83 vec![vec![haystack.clone()]]
84 } else {
85 vec![]
86 }
87 }
88 }
89 }
90 _ => {
91 vec![]
93 }
94 }
95 }
96
97 fn compile(
98 &self,
99 code: &mut Vec<Instr>,
100 literals: &mut Vec<Pattern>,
101 captures: &mut Vec<String>,
102 ) {
103 self.collect_capture_names(captures);
105
106 let idx = literals.len();
107 literals.push(Pattern::Structure(
108 crate::pattern::StructurePattern::Map(self.clone()),
109 ));
110 code.push(Instr::MatchStructure(idx));
111 }
112
113 fn collect_capture_names(&self, names: &mut Vec<String>) {
114 match self {
115 MapPattern::Any => {
116 }
118 MapPattern::Constraints(constraints) => {
119 for (key_pattern, value_pattern) in constraints {
121 key_pattern.collect_capture_names(names);
122 value_pattern.collect_capture_names(names);
123 }
124 }
125 MapPattern::Length(_) => {
126 }
128 }
129 }
130
131 fn paths_with_captures(
132 &self,
133 haystack: &CBOR,
134 ) -> (Vec<Path>, std::collections::HashMap<String, Vec<Path>>) {
135 let CBORCase::Map(map) = haystack.as_case() else {
137 return (vec![], std::collections::HashMap::new());
138 };
139
140 match self {
141 MapPattern::Any => {
142 (
144 vec![vec![haystack.clone()]],
145 std::collections::HashMap::new(),
146 )
147 }
148 MapPattern::Constraints(constraints) => {
149 let mut all_captures = std::collections::HashMap::new();
151 let mut all_constraints_satisfied = true;
152
153 for (key_pattern, value_pattern) in constraints {
154 let mut constraint_satisfied = false;
155
156 for (key, value) in map.iter() {
157 let (key_paths, key_captures) =
158 key_pattern.paths_with_captures(key);
159 let (value_paths, value_captures) =
160 value_pattern.paths_with_captures(value);
161
162 if !key_paths.is_empty() && !value_paths.is_empty() {
163 constraint_satisfied = true;
164
165 for (name, capture_paths) in key_captures {
167 let updated_paths: Vec<Path> = capture_paths
168 .iter()
169 .map(|_capture_path| {
170 vec![haystack.clone(), key.clone()]
171 })
172 .collect();
173 all_captures
174 .entry(name)
175 .or_insert_with(Vec::new)
176 .extend(updated_paths);
177 }
178
179 for (name, capture_paths) in value_captures {
181 let updated_paths: Vec<Path> = capture_paths
182 .iter()
183 .map(|_capture_path| {
184 vec![haystack.clone(), value.clone()]
185 })
186 .collect();
187 all_captures
188 .entry(name)
189 .or_insert_with(Vec::new)
190 .extend(updated_paths);
191 }
192 break; }
194 }
195
196 if !constraint_satisfied {
197 all_constraints_satisfied = false;
198 break;
199 }
200 }
201
202 if all_constraints_satisfied {
203 (vec![vec![haystack.clone()]], all_captures)
204 } else {
205 (vec![], all_captures)
206 }
207 }
208 _ => {
209 (self.paths(haystack), std::collections::HashMap::new())
211 }
212 }
213 }
214}
215
216impl std::fmt::Display for MapPattern {
217 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
218 match self {
219 MapPattern::Any => write!(f, "map"),
220 MapPattern::Constraints(constraints) => {
221 write!(f, "{{")?;
222 for (i, (key_pattern, value_pattern)) in
223 constraints.iter().enumerate()
224 {
225 if i > 0 {
226 write!(f, ", ")?;
227 }
228 write!(f, "{}: {}", key_pattern, value_pattern)?;
229 }
230 write!(f, "}}")
231 }
232 MapPattern::Length(interval) => {
233 write!(f, "{{{}}}", interval)
234 }
235 }
236 }
237}