dcbor_pattern/pattern/value/
known_value_pattern.rs

1use dcbor::prelude::*;
2use known_values::{KNOWN_VALUES, KnownValue};
3
4use crate::pattern::{Matcher, Path, Pattern, vm::Instr};
5
6// Known value tag is 40000 as defined in BCR-2020-006
7const KNOWN_VALUE_TAG: Tag = Tag::with_value(40000);
8
9/// Pattern for matching known values.
10#[derive(Debug, Clone)]
11pub enum KnownValuePattern {
12    /// Matches any known value.
13    Any,
14    /// Matches the specific known value.
15    Value(KnownValue),
16    /// Matches the name of a known value.
17    Name(String),
18    /// Matches the regex for a known value name.
19    Regex(regex::Regex),
20}
21
22impl PartialEq for KnownValuePattern {
23    fn eq(&self, other: &Self) -> bool {
24        match (self, other) {
25            (KnownValuePattern::Any, KnownValuePattern::Any) => true,
26            (KnownValuePattern::Value(a), KnownValuePattern::Value(b)) => {
27                a == b
28            }
29            (KnownValuePattern::Name(a), KnownValuePattern::Name(b)) => {
30                a == b
31            }
32            (KnownValuePattern::Regex(a), KnownValuePattern::Regex(b)) => {
33                a.as_str() == b.as_str()
34            }
35            _ => false,
36        }
37    }
38}
39
40impl Eq for KnownValuePattern {}
41
42impl std::hash::Hash for KnownValuePattern {
43    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
44        match self {
45            KnownValuePattern::Any => {
46                0u8.hash(state);
47            }
48            KnownValuePattern::Value(s) => {
49                1u8.hash(state);
50                s.hash(state);
51            }
52            KnownValuePattern::Name(name) => {
53                2u8.hash(state);
54                name.hash(state);
55            }
56            KnownValuePattern::Regex(regex) => {
57                3u8.hash(state);
58                // Regex does not implement Hash, so we hash its pattern string.
59                regex.as_str().hash(state);
60            }
61        }
62    }
63}
64
65impl KnownValuePattern {
66    /// Creates a new `KnownValuePattern` that matches any known value.
67    pub fn any() -> Self { KnownValuePattern::Any }
68
69    /// Creates a new `KnownValuePattern` that matches a specific known value.
70    pub fn value(value: KnownValue) -> Self { KnownValuePattern::Value(value) }
71
72    /// Creates a new `KnownValuePattern` that matches a known value by name.
73    pub fn named(name: impl Into<String>) -> Self {
74        KnownValuePattern::Name(name.into())
75    }
76
77    /// Creates a new `KnownValuePattern` that matches the regex for a known
78    /// value name.
79    pub fn regex(regex: regex::Regex) -> Self {
80        KnownValuePattern::Regex(regex)
81    }
82}
83
84impl Matcher for KnownValuePattern {
85    fn paths(&self, haystack: &CBOR) -> Vec<Path> {
86        // Known values are represented as tagged values with tag 40000(u64)
87        if let CBORCase::Tagged(tag, content) = haystack.as_case() {
88            if *tag == KNOWN_VALUE_TAG {
89                if let CBORCase::Unsigned(value) = content.as_case() {
90                    let known_value = KnownValue::new(*value);
91                    match self {
92                        KnownValuePattern::Any => vec![vec![haystack.clone()]],
93                        KnownValuePattern::Value(expected) => {
94                            if known_value == *expected {
95                                vec![vec![haystack.clone()]]
96                            } else {
97                                vec![]
98                            }
99                        }
100                        KnownValuePattern::Name(name) => {
101                            // Look up the known value by name in the global
102                            // registry
103                            let binding = KNOWN_VALUES.get();
104                            if let Some(known_values_store) = binding.as_ref() {
105                                if let Some(expected_value) =
106                                    known_values_store.known_value_named(name)
107                                {
108                                    if known_value == *expected_value {
109                                        vec![vec![haystack.clone()]]
110                                    } else {
111                                        vec![]
112                                    }
113                                } else {
114                                    // Name not found in registry, no match
115                                    vec![]
116                                }
117                            } else {
118                                // Registry not initialized, no match
119                                vec![]
120                            }
121                        }
122                        KnownValuePattern::Regex(regex) => {
123                            // Check if the known value's name matches the regex
124                            // Use the global registry to get the proper name
125                            let name = {
126                                let binding = KNOWN_VALUES.get();
127                                if let Some(known_values_store) =
128                                    binding.as_ref()
129                                {
130                                    known_values_store.name(known_value.clone())
131                                } else {
132                                    known_value.name()
133                                }
134                            };
135
136                            if regex.is_match(&name) {
137                                vec![vec![haystack.clone()]]
138                            } else {
139                                vec![]
140                            }
141                        }
142                    }
143                } else {
144                    vec![]
145                }
146            } else {
147                vec![]
148            }
149        } else {
150            vec![]
151        }
152    }
153
154    fn compile(
155        &self,
156        code: &mut Vec<Instr>,
157        literals: &mut Vec<Pattern>,
158        _captures: &mut Vec<String>,
159    ) {
160        let idx = literals.len();
161        literals.push(Pattern::Value(
162            crate::pattern::ValuePattern::KnownValue(self.clone()),
163        ));
164        code.push(Instr::MatchPredicate(idx));
165    }
166}
167
168impl std::fmt::Display for KnownValuePattern {
169    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
170        match self {
171            KnownValuePattern::Any => write!(f, "known"),
172            KnownValuePattern::Value(value) => {
173                write!(f, "'{}'", value.name())
174            }
175            KnownValuePattern::Name(name) => write!(f, "'{}'", name),
176            KnownValuePattern::Regex(regex) => {
177                write!(f, "'/{}/'", regex.as_str())
178            }
179        }
180    }
181}