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 {
25 MapPattern::Any
26 }
27
28 pub fn with_key_value_constraints(
31 constraints: Vec<(Pattern, Pattern)>,
32 ) -> Self {
33 MapPattern::Constraints(constraints)
34 }
35
36 pub fn with_length(length: usize) -> Self {
39 MapPattern::Length(Interval::new(length..=length))
40 }
41
42 pub fn with_length_range<R: RangeBounds<usize>>(range: R) -> Self {
45 MapPattern::Length(Interval::new(range))
46 }
47
48 pub fn with_length_interval(interval: Interval) -> Self {
51 MapPattern::Length(interval)
52 }
53}
54
55impl Matcher for MapPattern {
56 fn paths(&self, haystack: &CBOR) -> Vec<Path> {
57 match haystack.as_case() {
59 CBORCase::Map(map) => {
60 match self {
61 MapPattern::Any => {
62 vec![vec![haystack.clone()]]
64 }
65 MapPattern::Constraints(constraints) => {
66 for (key_pattern, value_pattern) in constraints {
68 let mut found_match = false;
69 for (key, value) in map.iter() {
70 if key_pattern.matches(key)
71 && value_pattern.matches(value)
72 {
73 found_match = true;
74 break;
75 }
76 }
77 if !found_match {
78 return vec![];
79 }
80 }
81 vec![vec![haystack.clone()]]
82 }
83 MapPattern::Length(interval) => {
84 if interval.contains(map.len()) {
85 vec![vec![haystack.clone()]]
86 } else {
87 vec![]
88 }
89 }
90 }
91 }
92 _ => {
93 vec![]
95 }
96 }
97 }
98
99 fn compile(
100 &self,
101 code: &mut Vec<Instr>,
102 literals: &mut Vec<Pattern>,
103 captures: &mut Vec<String>,
104 ) {
105 self.collect_capture_names(captures);
107
108 let idx = literals.len();
109 literals.push(Pattern::Structure(
110 crate::pattern::StructurePattern::Map(self.clone()),
111 ));
112 code.push(Instr::MatchStructure(idx));
113 }
114
115 fn collect_capture_names(&self, names: &mut Vec<String>) {
116 match self {
117 MapPattern::Any => {
118 }
120 MapPattern::Constraints(constraints) => {
121 for (key_pattern, value_pattern) in constraints {
123 key_pattern.collect_capture_names(names);
124 value_pattern.collect_capture_names(names);
125 }
126 }
127 MapPattern::Length(_) => {
128 }
130 }
131 }
132
133 fn paths_with_captures(
134 &self,
135 haystack: &CBOR,
136 ) -> (Vec<Path>, std::collections::HashMap<String, Vec<Path>>) {
137 let CBORCase::Map(map) = haystack.as_case() else {
139 return (vec![], std::collections::HashMap::new());
140 };
141
142 match self {
143 MapPattern::Any => {
144 (vec![vec![haystack.clone()]], std::collections::HashMap::new())
146 }
147 MapPattern::Constraints(constraints) => {
148 let mut all_captures = std::collections::HashMap::new();
150 let mut all_constraints_satisfied = true;
151
152 for (key_pattern, value_pattern) in constraints {
153 let mut constraint_satisfied = false;
154
155 for (key, value) in map.iter() {
156 let (key_paths, key_captures) =
157 key_pattern.paths_with_captures(key);
158 let (value_paths, value_captures) =
159 value_pattern.paths_with_captures(value);
160
161 if !key_paths.is_empty() && !value_paths.is_empty() {
162 constraint_satisfied = true;
163
164 for (name, capture_paths) in key_captures {
166 let updated_paths: Vec<Path> = capture_paths
167 .iter()
168 .map(|_capture_path| {
169 vec![haystack.clone(), key.clone()]
170 })
171 .collect();
172 all_captures
173 .entry(name)
174 .or_insert_with(Vec::new)
175 .extend(updated_paths);
176 }
177
178 for (name, capture_paths) in value_captures {
180 let updated_paths: Vec<Path> = capture_paths
181 .iter()
182 .map(|_capture_path| {
183 vec![haystack.clone(), value.clone()]
184 })
185 .collect();
186 all_captures
187 .entry(name)
188 .or_insert_with(Vec::new)
189 .extend(updated_paths);
190 }
191 break; }
193 }
194
195 if !constraint_satisfied {
196 all_constraints_satisfied = false;
197 break;
198 }
199 }
200
201 if all_constraints_satisfied {
202 (vec![vec![haystack.clone()]], all_captures)
203 } else {
204 (vec![], all_captures)
205 }
206 }
207 _ => {
208 (self.paths(haystack), std::collections::HashMap::new())
210 }
211 }
212 }
213}
214
215impl std::fmt::Display for MapPattern {
216 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
217 match self {
218 MapPattern::Any => write!(f, "map"),
219 MapPattern::Constraints(constraints) => {
220 write!(f, "{{")?;
221 for (i, (key_pattern, value_pattern)) in
222 constraints.iter().enumerate()
223 {
224 if i > 0 {
225 write!(f, ", ")?;
226 }
227 write!(f, "{}: {}", key_pattern, value_pattern)?;
228 }
229 write!(f, "}}")
230 }
231 MapPattern::Length(interval) => {
232 write!(f, "{{{}}}", interval)
233 }
234 }
235 }
236}