use std::sync::Arc;
#[derive(serde::Deserialize)]
struct SeedSourceTypes {
source_types: Vec<String>,
}
fn parse_seed_source_types(raw: &str) -> Result<Vec<String>, String> {
toml::from_str::<SeedSourceTypes>(raw)
.map(|parsed| parsed.source_types)
.map_err(|error| error.to_string())
}
pub(crate) fn seed_source_types_leaked() -> Vec<&'static str> {
static LEAKED_SEEDS: std::sync::LazyLock<Vec<&'static str>> = std::sync::LazyLock::new(|| {
SEED_SOURCE_TYPES
.iter()
.map(|s| Box::leak(s.clone().into_boxed_str()) as &'static str)
.collect()
});
LEAKED_SEEDS.clone()
}
pub(crate) static SEED_SOURCE_TYPES: std::sync::LazyLock<Vec<String>> =
std::sync::LazyLock::new(|| {
match parse_seed_source_types(include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/rules/seed-source-types.toml"
))) {
Ok(source_types) => source_types,
Err(error) => panic!(
"rules/seed-source-types.toml is invalid: {error}. \
Fix the bundled Tier-B metadata file list."
),
}
});
#[derive(Default)]
pub(crate) struct StaticInterner {
arena: Vec<Arc<str>>,
index: std::collections::HashMap<Arc<str>, u32, ahash::RandomState>,
}
impl StaticInterner {
pub(crate) fn from_detector_strings<I, S>(detector_strings: I) -> Self
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
let mut all: std::collections::BTreeSet<String> = std::collections::BTreeSet::new();
for s in detector_strings {
all.insert(s.as_ref().to_owned());
}
for s in &*SEED_SOURCE_TYPES {
all.insert(s.clone());
}
if all.is_empty() {
return Self::default();
}
let arena: Vec<Arc<str>> = all.iter().map(|s| Arc::from(s.as_str())).collect();
let mut index: std::collections::HashMap<Arc<str>, u32, ahash::RandomState> =
std::collections::HashMap::with_capacity_and_hasher(
arena.len(),
ahash::RandomState::new(),
);
for (i, arc) in arena.iter().enumerate() {
index.insert(Arc::clone(arc), i as u32);
}
Self { arena, index }
}
#[inline]
pub(crate) fn lookup(&self, s: &str) -> Option<Arc<str>> {
let &idx = self.index.get(s)?;
self.arena.get(idx as usize).cloned()
}
#[cfg(test)]
pub(crate) fn len(&self) -> usize {
self.arena.len()
}
}
#[cfg(test)]
pub(crate) fn seed_source_type_count() -> usize {
SEED_SOURCE_TYPES.len()
}