use std::{borrow::Cow, io::Read}; use flate2::read::GzDecoder; use itertools::Itertools; use once_cell::sync::Lazy; use rustc_hash::FxHashMap; use serde::Deserialize; #[derive(Debug, PartialEq, Eq, Clone, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Database<'a> { #[serde(rename = "components", borrow)] packages: Vec>, #[serde(borrow)] metadata: Vec>, #[serde(skip)] lookup_packages: FxHashMap<&'a str, usize>, #[serde(skip)] lookup_metadata: FxHashMap<&'a str, usize>, #[serde(skip)] lookup_kernel: usize, } #[derive(Debug, PartialEq, Eq, Clone, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Package<'a> { #[serde(borrow)] pub file_names: Vec<&'a str>, #[serde(borrow)] pub references: Vec<&'a str>, #[serde(borrow)] pub commands: Vec>, #[serde(borrow)] pub environments: Vec<&'a str>, } #[derive(Debug, PartialEq, Eq, Clone, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Command<'a> { pub name: Cow<'a, str>, #[serde(borrow)] pub image: Option<&'a str>, #[serde(borrow)] pub glyph: Option>, #[serde(borrow)] pub parameters: Vec>, } #[derive(Debug, PartialEq, Eq, Clone, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Parameter<'a>(#[serde(borrow)] pub Vec>); #[derive(Debug, PartialEq, Eq, Clone, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Argument<'a> { pub name: &'a str, #[serde(borrow)] pub image: Option<&'a str>, } #[derive(Debug, PartialEq, Eq, Clone, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Metadata<'a> { pub name: &'a str, #[serde(borrow)] pub caption: Option>, #[serde(borrow)] pub description: Option>, } impl<'a> Database<'a> { pub fn iter(&self) -> impl Iterator + '_ { self.packages.iter() } pub fn find(&self, name: &str) -> Option<&Package> { self.lookup_packages .get(name) .map(|index| &self.packages[*index]) } pub fn meta(&self, name: &str) -> Option<&Metadata> { self.lookup_metadata .get(name) .map(|index| &self.metadata[*index]) } pub fn kernel(&self) -> &Package { &self.packages[self.lookup_kernel] } } const JSON_GZ: &[u8] = include_bytes!("../data/completion.json.gz"); pub static DATABASE: Lazy> = Lazy::new(|| { let mut decoder = GzDecoder::new(JSON_GZ); let json = Box::leak(Box::default()); decoder.read_to_string(json).unwrap(); let mut db: Database = serde_json::from_str(json).unwrap(); db.lookup_packages = db .packages .iter() .enumerate() .flat_map(|(i, pkg)| pkg.file_names.iter().map(move |name| (*name, i))) .collect(); db.lookup_metadata = db .metadata .iter() .enumerate() .unique_by(|(_, meta)| meta.name) .map(|(i, meta)| (meta.name, i)) .collect(); db.lookup_kernel = db .packages .iter() .position(|package| package.file_names.is_empty()) .unwrap(); db });