chiark / gitweb /
config, wip parsing
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 24 Jul 2021 12:14:35 +0000 (13:14 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 24 Jul 2021 12:14:35 +0000 (13:14 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
src/config.rs

index 7a1f518d040c24b43a6269a017a57d0c30d0ecf3..b06b25d51a311dffe75e2603ff68283252e83118 100644 (file)
@@ -40,7 +40,7 @@ pub struct InstanceConfig {
 
   // Ordinary settings:
   pub addrs:                        Vec<IpAddr>,
-  pub vnetwork:                     Vec<CidrString>,
+//xxx  pub vnetwork:                     Vec<CidrString>,
   pub vaddr:                        Vec<IpAddr>,
   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<CidrString>,
+//xxx  #[client]  pub vroutes:                      Vec<CidrString>,
 }
 
 #[derive(Debug,Clone,Hash,Eq,PartialEq)]
@@ -267,36 +267,49 @@ struct ResolveContext<'c> {
 }
 
 trait Parseable: Sized {
-  fn parse(s: &Option<String>) -> Result<Self, AE>;
+  fn parse(s: Option<&str>) -> Result<Self, AE>;
+  fn default() -> Result<Self, AE> {
+    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<String>) -> 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<String>) -> $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<T:Parseable> Parseable for Vec<T> {
   #[throws(AE)]
-  fn parse(s: &Option<String>) -> Vec<T> {
+  fn parse(s: Option<&str>) -> Vec<T> {
     let s = s.as_ref().ok_or_else(|| anyhow!("value needed"))?;
     s.split_ascii_whitespace()
-      .map(|s| s.parse())
-      .collect::<Result<Vec<_>>>()?
+      .map(|s| Parseable::parse(Some(s)))
+      .collect::<Result<Vec<_>,_>>()?
   }
 }
 
@@ -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 "{}""#, &section))
           .dcontext(&raw.loc)?
@@ -369,15 +382,17 @@ impl<'c> ResolveContext<'c> {
 
   #[throws(AE)]
   pub fn ordinary<T>(&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<T>(&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<T>(&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<T>(&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)?,
     }
   }