use crate::registry;
pub fn is_pattern(selector: &str) -> bool {
selector.contains('*')
}
pub fn matches(pattern: &str, key: &str) -> bool {
let mut pattern_segments = pattern.split('*');
let first_pattern_segment = pattern_segments
.next()
.expect("`split` always yields at least one part");
let Some(mut key_after_prefix) = key.strip_prefix(first_pattern_segment) else {
return false;
};
let Some(last_pattern_segment) = pattern_segments.next_back() else {
return key_after_prefix.is_empty();
};
for mid_pattern_segment in pattern_segments {
match key_after_prefix.find(mid_pattern_segment) {
Some(at) => key_after_prefix = &key_after_prefix[at + mid_pattern_segment.len()..],
None => return false,
}
}
key_after_prefix.ends_with(last_pattern_segment)
}
#[derive(Debug, Clone, Default)]
pub struct Selection {
pub keys: Vec<&'static str>,
pub unmatched_patterns: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct UnknownKeys {
pub keys: Vec<String>,
}
impl std::fmt::Display for UnknownKeys {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "unknown #[traceable] key(s): {}", self.keys.join(", "))
}
}
impl std::error::Error for UnknownKeys {}
pub fn resolve<S: AsRef<str>>(selectors: &[S]) -> Result<Selection, UnknownKeys> {
let keys = registry::keys();
let mut matched: Vec<&'static str> = Vec::new();
let mut unknown: Vec<String> = Vec::new();
let mut unmatched_patterns: Vec<String> = Vec::new();
for selector in selectors {
let selector = selector.as_ref().trim();
if selector.is_empty() {
continue;
}
if is_pattern(selector) {
let before = matched.len();
matched.extend(keys.iter().copied().filter(|key| matches(selector, key)));
if matched.len() == before {
unmatched_patterns.push(selector.to_string());
}
} else {
match keys.binary_search_by(|candidate| (**candidate).cmp(selector)) {
Ok(at) => matched.push(keys[at]),
Err(_) => unknown.push(selector.to_string()),
}
}
}
if !unknown.is_empty() {
return Err(UnknownKeys { keys: unknown });
}
matched.sort_unstable();
matched.dedup();
Ok(Selection {
keys: matched,
unmatched_patterns,
})
}