From 1d53d59d1d7cddc3c15d1370b8e2f27ce2706812 Mon Sep 17 00:00:00 2001 From: Troy Benson Date: Sat, 8 Jul 2023 03:26:13 +0000 Subject: [PATCH] feat: fix --- common/src/config.rs | 8 +++-- config/config/Cargo.toml | 2 +- config/config/example/derive.rs | 9 ++---- config/config/src/key.rs | 14 ++++++--- config/config/src/lib.rs | 26 ++++++++-------- config/config/src/primitives.rs | 35 +++++++++++---------- config/config/src/sources/cli.rs | 24 +++++++-------- config/config/src/sources/env.rs | 44 ++++++++++++++++++--------- config/config/src/sources/file/mod.rs | 17 +++++------ config/config_derive/src/lib.rs | 2 +- video/edge/src/config.rs | 2 -- 11 files changed, 100 insertions(+), 83 deletions(-) diff --git a/common/src/config.rs b/common/src/config.rs index e51c68bf..de768967 100644 --- a/common/src/config.rs +++ b/common/src/config.rs @@ -1,7 +1,6 @@ use anyhow::Result; use crate::logging; -use config::KeyGraph; #[derive(Debug, Clone, Default, PartialEq, config::Config, serde::Deserialize)] #[serde(default)] @@ -27,10 +26,15 @@ pub struct LoggingConfig { pub level: String, /// What logging mode we should use - #[config(tree = "KeyTree::String")] pub mode: logging::Mode, } +impl ::config::Config for logging::Mode { + fn graph() -> &'static ::config::KeyGraph { + &::config::KeyGraph::String + } +} + impl Default for LoggingConfig { fn default() -> Self { Self { diff --git a/config/config/Cargo.toml b/config/config/Cargo.toml index f9dd2bd1..8143c097 100644 --- a/config/config/Cargo.toml +++ b/config/config/Cargo.toml @@ -14,7 +14,7 @@ serde_yaml = "0" toml = "0" clap = { version = "4", features = ["cargo", "string"] } convert_case = "0" -serde = { version = "1", features = ["derive"] } +serde = { version = "1", features = ["derive", "rc"] } tracing = { version = "0" } serde_ignored = "0" serde-value = "0" diff --git a/config/config/example/derive.rs b/config/config/example/derive.rs index 50103d67..00fd3d0b 100644 --- a/config/config/example/derive.rs +++ b/config/config/example/derive.rs @@ -1,8 +1,6 @@ //! Run with: `cargo run --example derive` //! Look at the generated code with: `cargo expand --example derive` -use std::collections::HashMap; - use config::{sources, ConfigBuilder, ConfigError}; type TypeAlias = bool; @@ -12,9 +10,6 @@ type TypeAlias = bool; struct AppConfig { enabled: TypeAlias, logging: LoggingConfig, - optional: Option, - #[config(cli(skip), env(skip))] - map: HashMap, } #[derive(config::Config, Debug, PartialEq, serde::Deserialize)] @@ -22,7 +17,7 @@ struct AppConfig { struct LoggingConfig { level: String, json: bool, - #[config(cli(skip), env(skip))] + #[config(cli(skip), env())] cycle: Option>, } @@ -48,7 +43,7 @@ fn parse() -> Result { builder.add_source(sources::CliSource::new()?); builder.add_source(sources::EnvSource::with_prefix("TEST")?); builder.add_source(sources::FileSource::json( - br#" + br#" { "enabled": "on", "optional": null, diff --git a/config/config/src/key.rs b/config/config/src/key.rs index 64d04384..278d2aa8 100644 --- a/config/config/src/key.rs +++ b/config/config/src/key.rs @@ -1,4 +1,9 @@ -use std::{collections::{BTreeMap, btree_map::Entry}, fmt::Display, cell::RefCell, ptr::NonNull}; +use std::{ + cell::RefCell, + collections::{btree_map::Entry, BTreeMap}, + fmt::Display, + ptr::NonNull, +}; #[derive(Debug, Default, Clone, PartialEq, Eq, Hash)] pub struct KeyPath(Vec); @@ -70,7 +75,7 @@ impl From<&str> for KeyPath { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone)] pub enum KeyType { String, I8, @@ -90,6 +95,7 @@ pub enum KeyType { Struct(BTreeMap), Map(Box, Box), Seq(Box), + CyclicReference, } thread_local! { @@ -190,7 +196,7 @@ impl std::fmt::Debug for KeyGraph { Self::Struct(map) => write!(f, "Struct({:?})", map), Self::Map(key, value) => write!(f, "Map({:?}, {:?})", key, value), Self::Seq(key) => write!(f, "Seq({:?})", key), - Self::Ref(_) => write!(f, "Ref()"), + Self::Ref(_) => write!(f, "Ref(...)"), } } } @@ -220,7 +226,7 @@ impl KeyGraph { KeyType::Map(Box::new(key.key_type()), Box::new(value.key_type())) } Self::Seq(key) => KeyType::Seq(Box::new(key.key_type())), - Self::Ref(_) => todo!("somehow work with keytypes"), + Self::Ref(_) => KeyType::CyclicReference, } } diff --git a/config/config/src/lib.rs b/config/config/src/lib.rs index 0b710936..b3e8b881 100644 --- a/config/config/src/lib.rs +++ b/config/config/src/lib.rs @@ -303,7 +303,7 @@ pub fn validate_from_graph(tree: &KeyGraph, value: Value) -> Result { } else { validate_from_graph(tree, value) } - }, + } KeyGraph::Seq(tree) => { if let Value::Seq(seq) = value { let mut result = Vec::new(); @@ -317,9 +317,10 @@ pub fn validate_from_graph(tree: &KeyGraph, value: Value) -> Result { Err(ConfigErrorEnum::ValidationError(format!( "expected sequence, found {:?}", value - )).into()) + )) + .into()) } - }, + } KeyGraph::Map(key_tree, value_tree) => { if let Value::Map(map) = value { let mut result = BTreeMap::new(); @@ -331,10 +332,10 @@ pub fn validate_from_graph(tree: &KeyGraph, value: Value) -> Result { Ok(Value::Map(result)) } else { - Err(ConfigErrorEnum::ValidationError(format!( - "expected map, found {:?}", - value - )).into()) + Err( + ConfigErrorEnum::ValidationError(format!("expected map, found {:?}", value)) + .into(), + ) } } KeyGraph::Struct(tree) => { @@ -348,7 +349,8 @@ pub fn validate_from_graph(tree: &KeyGraph, value: Value) -> Result { return Err(ConfigErrorEnum::ValidationError(format!( "expected string, found {:?}", key - )).into()); + )) + .into()); }; let key_tree = if let Some(key_tree) = tree.get(&key_str) { @@ -365,10 +367,10 @@ pub fn validate_from_graph(tree: &KeyGraph, value: Value) -> Result { Ok(Value::Map(result)) } else { - Err(ConfigErrorEnum::ValidationError(format!( - "expected map, found {:?}", - value - )).into()) + Err( + ConfigErrorEnum::ValidationError(format!("expected map, found {:?}", value)) + .into(), + ) } } KeyGraph::Ref(tree) => validate_from_graph(tree, value), diff --git a/config/config/src/primitives.rs b/config/config/src/primitives.rs index 84a2ffc4..d9238af4 100644 --- a/config/config/src/primitives.rs +++ b/config/config/src/primitives.rs @@ -1,9 +1,9 @@ use std::{ cell::{Cell, RefCell}, - collections::{BTreeSet, BinaryHeap, HashSet, LinkedList, VecDeque, BTreeMap, HashMap}, + collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}, marker::PhantomData, net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, - path::{PathBuf}, + path::PathBuf, rc::Rc, sync::{Arc, Mutex, RwLock}, time::{Duration, SystemTime}, @@ -415,7 +415,11 @@ impl Config for BinaryHeap { } } -impl Config for HashSet { +impl< + C: Config + std::hash::Hash + std::cmp::Eq, + S: std::hash::BuildHasher + std::default::Default + 'static, + > Config for HashSet +{ fn graph() -> &'static KeyGraph { if let Some(graph) = KeyGraph::get::() { return graph; @@ -573,10 +577,7 @@ impl Config for BTreeMap { return graph; } - KeyGraph::store::(KeyGraph::Map( - K::graph(), - V::graph(), - )) + KeyGraph::store::(KeyGraph::Map(K::graph(), V::graph())) } fn validate(value: Value) -> Result { @@ -602,16 +603,18 @@ impl Config for BTreeMap { } } -impl Config for HashMap { +impl< + K: Config + std::hash::Hash + std::cmp::Eq, + V: Config, + S: std::hash::BuildHasher + std::default::Default + 'static, + > Config for HashMap +{ fn graph() -> &'static KeyGraph { if let Some(graph) = KeyGraph::get::() { return graph; } - KeyGraph::store::(KeyGraph::Map( - K::graph(), - V::graph(), - )) + KeyGraph::store::(KeyGraph::Map(K::graph(), V::graph())) } fn validate(value: Value) -> Result { @@ -909,10 +912,6 @@ macro_rules! impl_slice { } impl_slice!( - 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32 ); diff --git a/config/config/src/sources/cli.rs b/config/config/src/sources/cli.rs index 2b339664..b4a966ab 100644 --- a/config/config/src/sources/cli.rs +++ b/config/config/src/sources/cli.rs @@ -4,7 +4,7 @@ use clap::{command, Arg, ArgAction, ArgMatches, Command}; use convert_case::{Case, Casing}; use crate::{ - Config, ConfigError, ConfigErrorEnum, ErrorSource, KeyPath, KeyGraph, Result, Source, Value, + Config, ConfigError, ConfigErrorEnum, ErrorSource, KeyGraph, KeyPath, Result, Source, Value, }; use super::utils; @@ -177,13 +177,13 @@ fn extend_cmd( ConfigError::new(ConfigErrorEnum::UnsupportedType(tree.key_type())) .with_path(path.clone()), ) - }, + } KeyGraph::Ref(_) => { return Err( ConfigError::new(ConfigErrorEnum::UnsupportedType(tree.key_type())) .with_path(path.clone()), ) - }, + } }) } @@ -237,7 +237,13 @@ pub fn generate_command() -> Result { } }; - let (arg, mut command) = extend_cmd(command, &KeyGraph::Struct(map.clone()), None, &KeyPath::new(), false)?; + let (arg, mut command) = extend_cmd( + command, + &KeyGraph::Struct(map.clone()), + None, + &KeyPath::new(), + false, + )?; if let Some(arg) = arg { command = command.arg(arg); @@ -483,16 +489,10 @@ fn matches_to_value( } } KeyGraph::Map(_, _) => { - Err( - ConfigError::new(ConfigErrorEnum::UnsupportedType(tree.key_type())) - .with_path(path), - ) + Err(ConfigError::new(ConfigErrorEnum::UnsupportedType(tree.key_type())).with_path(path)) } KeyGraph::Ref(_) => { - Err( - ConfigError::new(ConfigErrorEnum::UnsupportedType(tree.key_type())) - .with_path(path), - ) + Err(ConfigError::new(ConfigErrorEnum::UnsupportedType(tree.key_type())).with_path(path)) } } } diff --git a/config/config/src/sources/env.rs b/config/config/src/sources/env.rs index 11b98cea..231726fe 100644 --- a/config/config/src/sources/env.rs +++ b/config/config/src/sources/env.rs @@ -1,7 +1,7 @@ use std::{collections::BTreeMap, marker::PhantomData}; use crate::{ - Config, ConfigError, ConfigErrorEnum, ErrorSource, KeyPath, KeyGraph, KeyType, Result, Source, + Config, ConfigError, ConfigErrorEnum, ErrorSource, KeyGraph, KeyPath, KeyType, Result, Source, Value, }; @@ -34,7 +34,18 @@ impl EnvSource { false, false, ) - .map_err(|e| e.with_source(ErrorSource::Env))? + .map_err(|e| { + let e = e.with_source(ErrorSource::Env); + if prefix.is_some() { + if let Some(path) = e.path().cloned() { + e.with_path(path.drop_root()) + } else { + e + } + } else { + e + } + })? .unwrap_or(Value::Option(None)), }) } @@ -96,15 +107,17 @@ fn extract_keys( return None; } - Some(extract_keys( - key.tree(), - prefix, - path.push_child(child_path), - joiner, - false, - false, + Some( + extract_keys( + key.tree(), + prefix, + path.push_child(child_path), + joiner, + false, + false, + ) + .map(|value| value.map(|value| (Value::String(child_path.clone()), value))), ) - .map(|value| value.map(|value| (Value::String(child_path.clone()), value)))) }) .collect::>>()? .into_iter() @@ -136,12 +149,13 @@ fn extract_keys( } extract_keys(tree, prefix, path, joiner, true, false) - }, + } KeyGraph::Map(_, _) => { - Err(ConfigError::new(ConfigErrorEnum::UnsupportedType(tree.key_type())) - .with_path(path)) + Err(ConfigError::new(ConfigErrorEnum::UnsupportedType(tree.key_type())).with_path(path)) + } + KeyGraph::Ref(_) => { + Err(ConfigError::new(ConfigErrorEnum::UnsupportedType(tree.key_type())).with_path(path)) } - KeyGraph::Ref(_) => Err(ConfigError::new(ConfigErrorEnum::UnsupportedType(tree.key_type())).with_path(path)), } } @@ -168,6 +182,6 @@ fn parse_to_value(key_type: KeyType, s: &str) -> Result { impl Source for EnvSource { fn get_key(&self, path: &KeyPath) -> Result> { - utils::get_key(&self.value, path).map_err(|e| e.with_source(ErrorSource::Cli)) + utils::get_key(&self.value, path).map_err(|e| e.with_source(ErrorSource::Env)) } } diff --git a/config/config/src/sources/file/mod.rs b/config/config/src/sources/file/mod.rs index 18511332..4415b49c 100644 --- a/config/config/src/sources/file/mod.rs +++ b/config/config/src/sources/file/mod.rs @@ -70,9 +70,8 @@ impl FileSource { ConfigError::new(ConfigErrorEnum::Json(e)).with_source(ErrorSource::File) })?; Ok(Self { - content: C::validate(json::convert_value(content)).map_err(|e| { - e.with_source(ErrorSource::File) - })?, + content: C::validate(json::convert_value(content)) + .map_err(|e| e.with_source(ErrorSource::File))?, _phantom: PhantomData, path: None, }) @@ -85,9 +84,8 @@ impl FileSource { ConfigError::new(ConfigErrorEnum::Toml(e)).with_source(ErrorSource::File) })?; Ok(Self { - content: C::validate(toml::convert_value(value)).map_err(|e| { - e.with_source(ErrorSource::File) - })?, + content: C::validate(toml::convert_value(value)) + .map_err(|e| e.with_source(ErrorSource::File))?, _phantom: PhantomData, path: None, }) @@ -98,9 +96,10 @@ impl FileSource { ConfigError::new(ConfigErrorEnum::Yaml(e)).with_source(ErrorSource::File) })?; Ok(Self { - content: C::validate(yaml::convert_value(content).unwrap_or_else(|| Value::Map(Default::default()))).map_err(|e| { - e.with_source(ErrorSource::File) - })?, + content: C::validate( + yaml::convert_value(content).unwrap_or_else(|| Value::Map(Default::default())), + ) + .map_err(|e| e.with_source(ErrorSource::File))?, _phantom: PhantomData, path: None, }) diff --git a/config/config_derive/src/lib.rs b/config/config_derive/src/lib.rs index 0c33e43f..050139b9 100644 --- a/config/config_derive/src/lib.rs +++ b/config/config_derive/src/lib.rs @@ -185,7 +185,7 @@ fn get_attributes(attrs: &[syn::Attribute]) -> syn::Result> { syn::punctuated::Punctuated::::parse_terminated, )?; - let mut skip = true; + let mut skip = false; for m in meta { match m { diff --git a/video/edge/src/config.rs b/video/edge/src/config.rs index 750b8bc4..21ef6134 100644 --- a/video/edge/src/config.rs +++ b/video/edge/src/config.rs @@ -2,13 +2,11 @@ use std::net::SocketAddr; use anyhow::Result; use common::config::{LoggingConfig, RedisConfig, TlsConfig}; -use config::KeyGraph; #[derive(Debug, Clone, PartialEq, config::Config, serde::Deserialize)] #[serde(default)] pub struct EdgeConfig { /// Bind Address - #[config(tree = "KeyTree::String")] pub bind_address: SocketAddr, /// If we should use TLS