From: Ian Jackson Date: Sat, 24 Jul 2021 12:14:35 +0000 (+0100) Subject: config, wip parsing X-Git-Tag: hippotat/1.0.0~487 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ian/git?a=commitdiff_plain;h=1d401a589e50e1adf880379857afb1cbd5441137;p=hippotat.git config, wip parsing Signed-off-by: Ian Jackson --- diff --git a/src/config.rs b/src/config.rs index 7a1f518..b06b25d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -40,7 +40,7 @@ pub struct InstanceConfig { // Ordinary settings: pub addrs: Vec, - pub vnetwork: Vec, +//xxx pub vnetwork: Vec, pub vaddr: Vec, pub vrelay: IpAddr, pub port: u16, @@ -57,7 +57,7 @@ pub struct InstanceConfig { #[client] pub max_batch_up: u32, #[client] pub http_retry: Duration, #[client] pub url: Uri, - #[client] pub vroutes: Vec, +//xxx #[client] pub vroutes: Vec, } #[derive(Debug,Clone,Hash,Eq,PartialEq)] @@ -267,36 +267,49 @@ struct ResolveContext<'c> { } trait Parseable: Sized { - fn parse(s: &Option) -> Result; + fn parse(s: Option<&str>) -> Result; + fn default() -> Result { + Err(anyhow!("setting must be specified")) + } + #[throws(AE)] + fn default_for_key(key: &str) -> Self { + Self::default().with_context(|| key.to_string())? + } } impl Parseable for Duration { #[throws(AE)] - fn parse(s: &Option) -> Duration { + fn parse(s: Option<&str>) -> Duration { let s = s.as_ref().ok_or_else(|| anyhow!("value needed"))?; if let Ok(u64) = s.parse() { return Duration::from_secs(u64) } throw!(anyhow!("xxx parse with humantime")) } } -macro_rules! parseable_from_str { ($t:ty) => { +macro_rules! parseable_from_str { ($t:ty $(, $def:expr)? ) => { impl Parseable for $t { #[throws(AE)] - fn parse(s: &Option) -> $t { + fn parse(s: Option<&str>) -> $t { let s = s.as_ref().ok_or_else(|| anyhow!("value needed"))?; s.parse()? } + $( + #[throws(AE)] fn default() -> Self { $def } + )? } } } -parseable_from_str!{u32} -parseable_from_str!{IpAddr} +parseable_from_str!{u16, default() } +parseable_from_str!{u32, default() } +parseable_from_str!{String, default() } +parseable_from_str!{IpAddr, Ipv4Addr::UNSPECIFIED.into() } +parseable_from_str!{Uri, default() } impl Parseable for Vec { #[throws(AE)] - fn parse(s: &Option) -> Vec { + fn parse(s: Option<&str>) -> Vec { let s = s.as_ref().ok_or_else(|| anyhow!("value needed"))?; s.split_ascii_whitespace() - .map(|s| s.parse()) - .collect::>>()? + .map(|s| Parseable::parse(Some(s))) + .collect::,_>>()? } } @@ -359,7 +372,7 @@ impl<'c> ResolveContext<'c> { match self.first_of_raw(key, sections) { None => None, Some(raw) => Some({ - Parseable::parse(&raw.val) + Parseable::parse(raw.val.as_deref()) .context(key) // .with_context(|| format!(r#"in section "{}""#, §ion)) .dcontext(&raw.loc)? @@ -369,15 +382,17 @@ impl<'c> ResolveContext<'c> { #[throws(AE)] pub fn ordinary(&self, key: &'static str) -> T - where T: Parseable + Default + where T: Parseable { - self.first_of(key, SKL::Ordinary)? - .unwrap_or_default() + match self.first_of(key, SKL::Ordinary)? { + Some(y) => y, + None => Parseable::default_for_key(key)?, + } } #[throws(AE)] pub fn limited(&self, key: &'static str) -> T - where T: Parseable + Default + Ord + where T: Parseable + Ord { let val = self.ordinary(key)?; if let Some(limit) = self.first_of(key, SKL::Limits)? { @@ -389,18 +404,18 @@ impl<'c> ResolveContext<'c> { #[throws(AE)] pub fn client(&self, key: &'static str) -> T - where T: Parseable + Default { + where T: Parseable { match self.end { LinkEnd::Client => self.ordinary(key)?, - LinkEnd::Server => default(), + LinkEnd::Server => Parseable::default_for_key(key)?, } } #[throws(AE)] pub fn server(&self, key: &'static str) -> T - where T: Parseable + Default { + where T: Parseable { match self.end { LinkEnd::Server => self.ordinary(key)?, - LinkEnd::Client => default(), + LinkEnd::Client => Parseable::default_for_key(key)?, } }