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