spdlog_internal/pattern_parser/
registry.rs
1use std::{
2 borrow::Cow,
3 collections::{hash_map::Entry, HashMap},
4 fmt::Debug,
5 hash::Hash,
6};
7
8use super::{error::TemplateError, BuiltInFormatter, Error, PatternKind, Result};
9use crate::impossible;
10
11#[derive(Clone, Debug)]
12pub struct PatternRegistry<F> {
13 formatters: HashMap<Cow<'static, str>, PatternKind<F>>,
14}
15
16impl<F> PatternRegistry<F> {
17 pub fn with_builtin() -> Self {
18 let mut registry = Self {
19 formatters: HashMap::new(),
20 };
21
22 BuiltInFormatter::iter().for_each(|formatter| registry.register_builtin(formatter));
23 registry
24 }
25
26 pub fn register_custom(
27 &mut self,
28 placeholder: impl Into<Cow<'static, str>>,
29 factory: F,
30 ) -> Result<()> {
31 let placeholder = placeholder.into();
32
33 let incoming = PatternKind::Custom {
34 placeholder: placeholder.clone(),
35 factory,
36 };
37
38 match self.formatters.entry(placeholder) {
39 Entry::Occupied(entry) => Err(Error::ConflictName {
40 existing: entry.get().to_factory_erased(),
41 incoming: incoming.to_factory_erased(),
42 }),
43 Entry::Vacant(entry) => {
44 entry.insert(incoming);
45 Ok(())
46 }
47 }
48 }
49
50 pub fn find(&self, find_custom: bool, placeholder: impl AsRef<str>) -> Result<&PatternKind<F>> {
51 let placeholder = placeholder.as_ref();
52
53 match self.formatters.get(placeholder) {
54 Some(found) => match (found, find_custom) {
55 (PatternKind::BuiltIn(_), false) => Ok(found),
56 (PatternKind::Custom { .. }, true) => Ok(found),
57 (PatternKind::BuiltIn(_), true) => {
58 Err(Error::Template(TemplateError::WrongPatternKindReference {
59 is_builtin_as_custom: true,
60 placeholder: placeholder.into(),
61 }))
62 }
63 (PatternKind::Custom { .. }, false) => {
64 Err(Error::Template(TemplateError::WrongPatternKindReference {
65 is_builtin_as_custom: false,
66 placeholder: placeholder.into(),
67 }))
68 }
69 },
70 None => Err(Error::Template(TemplateError::UnknownPatternReference {
71 is_custom: find_custom,
72 placeholder: placeholder.into(),
73 })),
74 }
75 }
76}
77
78impl<F> PatternRegistry<F> {
79 pub(crate) fn register_builtin(&mut self, formatter: BuiltInFormatter) {
80 match self
81 .formatters
82 .entry(Cow::Borrowed(formatter.placeholder()))
83 {
84 Entry::Occupied(_) => {
85 impossible!("formatter={:?}", formatter)
86 }
87 Entry::Vacant(entry) => {
88 entry.insert(PatternKind::BuiltIn(formatter));
89 }
90 }
91 }
92}
93
94pub fn check_custom_pattern_names<N, I>(names: I) -> Result<()>
95where
96 N: AsRef<str> + Eq + PartialEq + Hash,
97 I: IntoIterator<Item = N>,
98{
99 let mut seen_names: HashMap<N, usize> = HashMap::new();
100 let mut result = Ok(());
101
102 for name in names {
103 if let Some(existing) = BuiltInFormatter::iter().find(|f| f.placeholder() == name.as_ref())
104 {
105 result = Error::push_err(
106 result,
107 Error::ConflictName {
108 existing: PatternKind::BuiltIn(existing),
109 incoming: PatternKind::Custom {
110 placeholder: Cow::Owned(name.as_ref().into()),
111 factory: (),
112 },
113 },
114 );
115 }
116
117 if let Some(seen_count) = seen_names.get_mut(&name) {
118 *seen_count += 1;
119 if *seen_count == 2 {
120 let conflict_pattern = PatternKind::Custom {
121 placeholder: Cow::Owned(name.as_ref().into()),
122 factory: (),
123 };
124 result = Error::push_err(
125 result,
126 Error::ConflictName {
127 existing: conflict_pattern.clone(),
128 incoming: conflict_pattern,
129 },
130 );
131 }
132 } else {
133 seen_names.insert(name, 1);
134 }
135 }
136
137 debug_assert!(seen_names.iter().all(|(_, seen_count)| *seen_count == 1) || result.is_err());
138
139 result
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145 use crate::pattern_parser::BuiltInFormatterInner;
146
147 #[test]
148 fn custom_pattern_names_checker() {
149 use check_custom_pattern_names as check;
150
151 assert!(check(["a", "b"]).is_ok());
152 assert_eq!(
153 check(["a", "a"]),
154 Err(Error::ConflictName {
155 existing: PatternKind::Custom {
156 placeholder: "a".into(),
157 factory: ()
158 },
159 incoming: PatternKind::Custom {
160 placeholder: "a".into(),
161 factory: ()
162 }
163 })
164 );
165 assert_eq!(
166 check(["a", "b", "a"]),
167 Err(Error::ConflictName {
168 existing: PatternKind::Custom {
169 placeholder: "a".into(),
170 factory: ()
171 },
172 incoming: PatternKind::Custom {
173 placeholder: "a".into(),
174 factory: ()
175 }
176 })
177 );
178 assert_eq!(
179 check(["date"]),
180 Err(Error::ConflictName {
181 existing: PatternKind::BuiltIn(BuiltInFormatter(BuiltInFormatterInner::Date)),
182 incoming: PatternKind::Custom {
183 placeholder: "date".into(),
184 factory: ()
185 }
186 })
187 );
188 assert_eq!(
189 check(["date", "a", "a"]),
190 Err(Error::Multiple(vec![
191 Error::ConflictName {
192 existing: PatternKind::BuiltIn(BuiltInFormatter(BuiltInFormatterInner::Date)),
193 incoming: PatternKind::Custom {
194 placeholder: "date".into(),
195 factory: ()
196 }
197 },
198 Error::ConflictName {
199 existing: PatternKind::Custom {
200 placeholder: "a".into(),
201 factory: ()
202 },
203 incoming: PatternKind::Custom {
204 placeholder: "a".into(),
205 factory: ()
206 }
207 }
208 ]))
209 );
210 assert_eq!(
211 check(["date", "a", "a", "a"]),
212 Err(Error::Multiple(vec![
213 Error::ConflictName {
214 existing: PatternKind::BuiltIn(BuiltInFormatter(BuiltInFormatterInner::Date)),
215 incoming: PatternKind::Custom {
216 placeholder: "date".into(),
217 factory: ()
218 }
219 },
220 Error::ConflictName {
221 existing: PatternKind::Custom {
222 placeholder: "a".into(),
223 factory: ()
224 },
225 incoming: PatternKind::Custom {
226 placeholder: "a".into(),
227 factory: ()
228 }
229 }
230 ]))
231 );
232 assert_eq!(
233 check(["b", "date", "a", "b", "a", "a"]),
234 Err(Error::Multiple(vec![
235 Error::ConflictName {
236 existing: PatternKind::BuiltIn(BuiltInFormatter(BuiltInFormatterInner::Date)),
237 incoming: PatternKind::Custom {
238 placeholder: "date".into(),
239 factory: ()
240 }
241 },
242 Error::ConflictName {
243 existing: PatternKind::Custom {
244 placeholder: "b".into(),
245 factory: ()
246 },
247 incoming: PatternKind::Custom {
248 placeholder: "b".into(),
249 factory: ()
250 }
251 },
252 Error::ConflictName {
253 existing: PatternKind::Custom {
254 placeholder: "a".into(),
255 factory: ()
256 },
257 incoming: PatternKind::Custom {
258 placeholder: "a".into(),
259 factory: ()
260 }
261 }
262 ]))
263 );
264 }
265}