use std::{borrow::Cow, path::PathBuf, str::FromStr}; use confindent::Confindent; use crate::{ Scurvy, formula::{Formula, PathFormula}, }; impl Scurvy { pub fn with_confindent(self, confindent: Confindent) -> ConfigurationPair { ConfigurationPair::new(self, confindent) } pub fn with_configuration_key>( self, key: &str, default_conf: P, ) -> ConfigurationPair { let path = self.parse_or(key, PathFormula::new(), default_conf.into()); match Confindent::from_file(&path) { Err(_) => { eprintln!( "Unable to find configuration file at path '{}'", path.to_string_lossy() ); std::process::exit(-1) } Ok(confindent) => ConfigurationPair { scurvy: self, confindent, }, } } } pub struct ConfigurationPair { scurvy: Scurvy, confindent: Confindent, } impl ConfigurationPair { pub(crate) fn new(scurvy: Scurvy, confindent: Confindent) -> Self { Self { scurvy, confindent } } } impl ConfigurationPair { pub fn has>>(&self, key: K) -> bool { self.get(key).is_some() } pub fn get>>(&self, key: K) -> Option<&str> { let key = key.into(); self.scurvy .get(&key.scurvy()) .or_else(|| self.confindent.get(&key.confindent())) } pub fn get_req>>(&self, key: K) -> &str { let key = key.into(); match self.get(key) { None => { let pair = self.scurvy.get_pair(&key.scurvy()).unwrap(); self.scurvy.print_missing_and_die(pair.key.preferred_key()); } Some(s) => s, } } pub fn parse(&self, key: K, formula: F) -> Option where T: FromStr, F: Into>, K: Into>, { let key = key.into(); let formula = formula.into(); let maybe_scurvy = self.scurvy.get(&key.scurvy()); let maybe_confindent = self.confindent.get(&key.confindent()); maybe_scurvy .or(maybe_confindent) .map(|got| self.scurvy.check_formula(&key.scurvy(), got, formula)) .flatten() } pub fn parse_req(&self, key: K, formula: F) -> T where T: FromStr, F: Into>, K: Into>, { let key = key.into(); let formula = formula.into(); let missing = formula.missing.clone(); match self.parse(key, formula) { None => self.scurvy.handle_missing(&key.scurvy(), missing), Some(o) => o, } } } #[derive(Copy, Clone, Debug)] pub enum ConfigurationKey<'s> { Scurvy(&'s str), Both(&'s str, &'s str), } impl<'s> ConfigurationKey<'s> { pub fn scurvy(&self) -> Cow<'s, str> { match self { Self::Scurvy(s) => Cow::Borrowed(s), Self::Both(s, _) => Cow::Borrowed(s), } } pub fn confindent(&self) -> Cow<'s, str> { match self { Self::Scurvy(s) => { let mut c = s.chars(); match c.next() { None => Cow::Borrowed(""), Some(f) => Cow::Owned(f.to_uppercase().chain(c).collect()), } } Self::Both(_, c) => Cow::Borrowed(c), } } } impl<'s> From<&'s str> for ConfigurationKey<'s> { fn from(value: &'s str) -> Self { Self::Scurvy(value) } } impl<'s> From<[&'s str; 2]> for ConfigurationKey<'s> { fn from(value: [&'s str; 2]) -> Self { Self::Both(value[0], value[1]) } }