use rocket::request::FromParam; use serde::Deserialize; use std::{ collections::{HashMap, HashSet}, sync::LazyLock, }; pub static KNOWN_SOFTWARE: LazyLock = LazyLock::new(|| serde_json::from_str(include_str!("../known-software.json")).unwrap()); pub static KNOWN_SOFTWARE_NAMES: LazyLock> = LazyLock::new(|| KNOWN_SOFTWARE.get_name_map()); #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct Software { name: String, aliases: HashSet, groups: HashSet, fork_of: Option, } #[derive(Deserialize)] pub struct Group { name: String, aliases: HashSet, } #[derive(Deserialize)] pub struct KnownSoftware { software: HashMap, groups: HashMap, } impl KnownSoftware { fn get_name_map(&self) -> HashMap { let mut map = HashMap::new(); self.software.iter().for_each(|(name, software)| { software.aliases.iter().for_each(|alias| { assert_eq!(map.insert(alias.to_owned(), name.to_owned()), None); }); }); self.groups.iter().for_each(|(name, group)| { group.aliases.iter().for_each(|alias: &String| { assert_eq!(map.insert(alias.to_owned(), name.to_owned()), None); }); }); map } } pub struct KnownInstanceSoftware<'r> { pub requested: &'r str, pub resolved: &'static String, } impl<'r> FromParam<'r> for KnownInstanceSoftware<'r> { type Error = &'r str; fn from_param(param: &'r str) -> Result { if let Some(resolved) = KNOWN_SOFTWARE_NAMES.get(param) { Ok(KnownInstanceSoftware { requested: param, resolved, }) } else { Err(param) } } }