From 395a9ff5342f59199a92da1498e7bb513d5d4643 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 17 Mar 2026 07:59:53 -0500 Subject: [PATCH 1/5] docs(examples): Flatten examples --- examples/{async_source/main.rs => async_source.rs} | 0 .../{custom_str_format/main.rs => custom_str_format.rs} | 0 examples/{env-list/main.rs => env_list.rs} | 0 examples/{simple/Settings.toml => settings.toml} | 0 examples/{simple/main.rs => simple.rs} | 4 ++-- examples/{watch/main.rs => watch.rs} | 6 +++--- examples/watch/Settings.toml | 3 --- src/lib.rs | 2 +- 8 files changed, 6 insertions(+), 9 deletions(-) rename examples/{async_source/main.rs => async_source.rs} (100%) rename examples/{custom_str_format/main.rs => custom_str_format.rs} (100%) rename examples/{env-list/main.rs => env_list.rs} (100%) rename examples/{simple/Settings.toml => settings.toml} (100%) rename examples/{simple/main.rs => simple.rs} (82%) rename examples/{watch/main.rs => watch.rs} (92%) delete mode 100644 examples/watch/Settings.toml diff --git a/examples/async_source/main.rs b/examples/async_source.rs similarity index 100% rename from examples/async_source/main.rs rename to examples/async_source.rs diff --git a/examples/custom_str_format/main.rs b/examples/custom_str_format.rs similarity index 100% rename from examples/custom_str_format/main.rs rename to examples/custom_str_format.rs diff --git a/examples/env-list/main.rs b/examples/env_list.rs similarity index 100% rename from examples/env-list/main.rs rename to examples/env_list.rs diff --git a/examples/simple/Settings.toml b/examples/settings.toml similarity index 100% rename from examples/simple/Settings.toml rename to examples/settings.toml diff --git a/examples/simple/main.rs b/examples/simple.rs similarity index 82% rename from examples/simple/main.rs rename to examples/simple.rs index f3fec111..ca0d2f2a 100644 --- a/examples/simple/main.rs +++ b/examples/simple.rs @@ -4,8 +4,8 @@ use config::Config; fn main() { let settings = Config::builder() - // Add in `./Settings.toml` - .add_source(config::File::with_name("examples/simple/Settings")) + // Add in `./settings.toml` + .add_source(config::File::with_name("examples/settings")) // Add in settings from the environment (with a prefix of APP) // Eg.. `APP_DEBUG=1 ./target/app` would set the `debug` key .add_source(config::Environment::with_prefix("APP")) diff --git a/examples/watch/main.rs b/examples/watch.rs similarity index 92% rename from examples/watch/main.rs rename to examples/watch.rs index 6b2cce33..9894dfe1 100644 --- a/examples/watch/main.rs +++ b/examples/watch.rs @@ -23,7 +23,7 @@ fn refresh() { fn load() -> Config { Config::builder() - .add_source(File::with_name("examples/watch/Settings.toml")) + .add_source(File::with_name("examples/settings.toml")) .build() .unwrap() } @@ -56,7 +56,7 @@ fn watch() -> ! { // below will be monitored for changes. watcher .watch( - Path::new("examples/watch/Settings.toml"), + Path::new("examples/settings.toml"), RecursiveMode::NonRecursive, ) .unwrap(); @@ -69,7 +69,7 @@ fn watch() -> ! { kind: notify::event::EventKind::Modify(_), .. })) => { - println!(" * Settings.toml written; refreshing configuration ..."); + println!(" * settings.toml written; refreshing configuration ..."); refresh(); show(); } diff --git a/examples/watch/Settings.toml b/examples/watch/Settings.toml deleted file mode 100644 index 1518068c..00000000 --- a/examples/watch/Settings.toml +++ /dev/null @@ -1,3 +0,0 @@ -debug = false -port = 3223 -host = "0.0.0.0" diff --git a/src/lib.rs b/src/lib.rs index 72114540..33061916 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,7 @@ //! //! ```rust //! # #[cfg(feature = "toml")] { -#![doc = include_str!("../examples/simple/main.rs")] +#![doc = include_str!("../examples/simple.rs")] //! # } //! ``` //! From 4e8637c23939316679c5c84c6f836d94c21f9f58 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 17 Mar 2026 08:12:08 -0500 Subject: [PATCH 2/5] docs(examples): Be consistent in env prefix --- examples/hierarchical-env/settings.rs | 2 +- examples/static_env.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/hierarchical-env/settings.rs b/examples/hierarchical-env/settings.rs index 6e6c859f..679fc673 100644 --- a/examples/hierarchical-env/settings.rs +++ b/examples/hierarchical-env/settings.rs @@ -62,7 +62,7 @@ impl Settings { .add_source(File::with_name("examples/hierarchical-env/config/local").required(false)) // Add in settings from the environment (with a prefix of APP) // Eg.. `APP_DEBUG=1 ./target/app` would set the `debug` key - .add_source(Environment::with_prefix("app")) + .add_source(Environment::with_prefix("APP")) // You may also programmatically change settings .set_override("database.url", "postgres://")? .build()?; diff --git a/examples/static_env.rs b/examples/static_env.rs index e95cd532..563d7255 100644 --- a/examples/static_env.rs +++ b/examples/static_env.rs @@ -6,7 +6,7 @@ fn config() -> &'static Config { static CONFIG: OnceLock = OnceLock::new(); CONFIG.get_or_init(|| { Config::builder() - .add_source(config::Environment::with_prefix("APP_NAME").separator("_")) + .add_source(config::Environment::with_prefix("APP").separator("_")) .build() .unwrap() }) From fcc5cd8ea7c9014b0eb10527235418fa0951a20e Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 17 Mar 2026 08:16:01 -0500 Subject: [PATCH 3/5] docs(examples): Better organize examples --- examples/async_source.rs | 12 ++- examples/custom_file_format/main.rs | 4 +- examples/custom_str_format.rs | 21 ++--- .../glob/{conf => conf.d}/00-default.toml | 0 examples/glob/{conf => conf.d}/05-some.yml | 0 examples/glob/{conf => conf.d}/99-extra.json | 0 examples/glob/main.rs | 60 ++------------ examples/hierarchical-env/main.rs | 78 ++++++++++++++++++- examples/hierarchical-env/settings.rs | 77 ------------------ examples/static_env.rs | 26 ++++--- examples/watch.rs | 76 +++++++++--------- 11 files changed, 153 insertions(+), 201 deletions(-) rename examples/glob/{conf => conf.d}/00-default.toml (100%) rename examples/glob/{conf => conf.d}/05-some.yml (100%) rename examples/glob/{conf => conf.d}/99-extra.json (100%) delete mode 100644 examples/hierarchical-env/settings.rs diff --git a/examples/async_source.rs b/examples/async_source.rs index 9964b730..d8657ab2 100644 --- a/examples/async_source.rs +++ b/examples/async_source.rs @@ -1,3 +1,5 @@ +//! Example below presents sample configuration server and client. + use std::{error::Error, fmt::Debug}; use async_trait::async_trait; @@ -7,11 +9,6 @@ use config::{ use futures::{FutureExt, select}; use warp::Filter; -// Example below presents sample configuration server and client. -// -// Server serves simple configuration on HTTP endpoint. -// Client consumes it using custom HTTP AsyncSource built on top of reqwest. - #[tokio::main] async fn main() -> Result<(), Box> { select! { @@ -20,6 +17,7 @@ async fn main() -> Result<(), Box> { } } +/// Serve simple configuration on HTTP endpoint. async fn run_server() -> Result<(), Box> { let service = warp::path("configuration").map(|| r#"{ "value" : 123 }"#); @@ -30,6 +28,7 @@ async fn run_server() -> Result<(), Box> { Ok(()) } +/// Consumes the server's configuration using custom HTTP `AsyncSource` built on top of reqwest. async fn run_client() -> Result<(), Box> { // Good enough for an example to allow server to start tokio::time::sleep(tokio::time::Duration::from_secs(3)).await; @@ -47,8 +46,7 @@ async fn run_client() -> Result<(), Box> { Ok(()) } -// Actual implementation of AsyncSource can be found below - +/// `AsyncSource` to read configuration from an HTTP server #[derive(Debug)] struct HttpSource { uri: String, diff --git a/examples/custom_file_format/main.rs b/examples/custom_file_format/main.rs index 2650664b..e022416b 100644 --- a/examples/custom_file_format/main.rs +++ b/examples/custom_file_format/main.rs @@ -24,6 +24,7 @@ fn main() { // Deserialize the config object into your Settings struct: let settings: Settings = settings.try_deserialize().unwrap(); + println!("{settings:#?}"); } @@ -65,8 +66,7 @@ impl Format for PemFile { } } -// A slice of extensions associated to this format, when an extension -// is omitted from a file source, these will be tried implicitly: +// When an extension is omitted from a file source, these will be tried implicitly: impl FileStoredFormat for PemFile { fn file_extensions(&self) -> &'static [&'static str] { &["pem"] diff --git a/examples/custom_str_format.rs b/examples/custom_str_format.rs index e78f2a9e..ccce440b 100644 --- a/examples/custom_str_format.rs +++ b/examples/custom_str_format.rs @@ -2,8 +2,8 @@ use config::{Config, File, FileStoredFormat, Format, Map, Value, ValueKind}; fn main() { let config = Config::builder() - .add_source(File::from_str("bad", MyFormat)) - .add_source(File::from_str("good", MyFormat)) + .add_source(File::from_str("bad", CustomFormat)) + .add_source(File::from_str("good", CustomFormat)) .build(); match config { @@ -13,9 +13,9 @@ fn main() { } #[derive(Debug, Clone)] -pub struct MyFormat; +pub struct CustomFormat; -impl Format for MyFormat { +impl Format for CustomFormat { fn parse( &self, uri: Option<&String>, @@ -40,11 +40,14 @@ impl Format for MyFormat { } } -// As strange as it seems for config sourced from a string, legacy demands its sacrifice -// It is only required for File source, custom sources can use Format without caring for extensions -static MY_FORMAT_EXT: Vec<&'static str> = vec![]; -impl FileStoredFormat for MyFormat { +impl FileStoredFormat for CustomFormat { fn file_extensions(&self) -> &'static [&'static str] { - &MY_FORMAT_EXT + &NO_EXTS } } + +/// In-memory format doesn't have any file extensions +/// +/// It is only required for File source, +/// custom sources can use Format without caring for extensions +static NO_EXTS: Vec<&'static str> = vec![]; diff --git a/examples/glob/conf/00-default.toml b/examples/glob/conf.d/00-default.toml similarity index 100% rename from examples/glob/conf/00-default.toml rename to examples/glob/conf.d/00-default.toml diff --git a/examples/glob/conf/05-some.yml b/examples/glob/conf.d/05-some.yml similarity index 100% rename from examples/glob/conf/05-some.yml rename to examples/glob/conf.d/05-some.yml diff --git a/examples/glob/conf/99-extra.json b/examples/glob/conf.d/99-extra.json similarity index 100% rename from examples/glob/conf/99-extra.json rename to examples/glob/conf.d/99-extra.json diff --git a/examples/glob/main.rs b/examples/glob/main.rs index 75780c8f..7a865dbf 100644 --- a/examples/glob/main.rs +++ b/examples/glob/main.rs @@ -1,61 +1,17 @@ +//! Gather all conf files from conf.d/ using glob and put in 1 merge call. + use std::collections::HashMap; -use std::path::Path; use config::{Config, File}; use glob::glob; fn main() { - // Option 1 - // -------- - // Gather all conf files from conf/ manually - let settings = Config::builder() - // File::with_name(..) is shorthand for File::from(Path::new(..)) - .add_source(File::with_name("examples/glob/conf/00-default.toml")) - .add_source(File::from(Path::new("examples/glob/conf/05-some.yml"))) - .add_source(File::from(Path::new("examples/glob/conf/99-extra.json"))) - .build() - .unwrap(); - - // Print out our settings (as a HashMap) - println!( - "\n{:?} \n\n-----------", - settings - .try_deserialize::>() - .unwrap() - ); - - // Option 2 - // -------- - // Gather all conf files from conf/ manually, but put in 1 merge call. - let settings = Config::builder() - .add_source(vec![ - File::with_name("examples/glob/conf/00-default.toml"), - File::from(Path::new("examples/glob/conf/05-some.yml")), - File::from(Path::new("examples/glob/conf/99-extra.json")), - ]) - .build() - .unwrap(); - - // Print out our settings (as a HashMap) - println!( - "\n{:?} \n\n-----------", - settings - .try_deserialize::>() - .unwrap() - ); - - // Option 3 - // -------- - // Gather all conf files from conf/ using glob and put in 1 merge call. - let settings = Config::builder() - .add_source( - glob("examples/glob/conf/*") - .unwrap() - .map(|path| File::from(path.unwrap())) - .collect::>(), - ) - .build() - .unwrap(); + // Glob results are sorted, ensuring user priority is preserved + let files = glob("examples/glob/conf.d/*") + .unwrap() + .map(|path| File::from(path.unwrap())) + .collect::>(); + let settings = Config::builder().add_source(files).build().unwrap(); // Print out our settings (as a HashMap) println!( diff --git a/examples/hierarchical-env/main.rs b/examples/hierarchical-env/main.rs index 08409494..43421152 100644 --- a/examples/hierarchical-env/main.rs +++ b/examples/hierarchical-env/main.rs @@ -1,6 +1,7 @@ -mod settings; +use std::env; -use settings::Settings; +use config::{Config, ConfigError, Environment, File}; +use serde::Deserialize; fn main() { let settings = Settings::new(); @@ -8,3 +9,76 @@ fn main() { // Print out our settings println!("{settings:?}"); } + +#[derive(Debug, Deserialize)] +#[allow(unused)] +pub(crate) struct Settings { + debug: bool, + database: Database, + sparkpost: Sparkpost, + twitter: Twitter, + braintree: Braintree, +} + +impl Settings { + pub(crate) fn new() -> Result { + let run_mode = env::var("RUN_MODE").unwrap_or_else(|_| "development".into()); + + let s = Config::builder() + // Start off by merging in the "default" configuration file + .add_source(File::with_name("examples/hierarchical-env/config/default")) + // Add in the current environment file + // Default to 'development' env + // Note that this file is _optional_ + .add_source( + File::with_name(&format!("examples/hierarchical-env/config/{run_mode}")) + .required(false), + ) + // Add in a local configuration file + // This file shouldn't be checked in to git + .add_source(File::with_name("examples/hierarchical-env/config/local").required(false)) + // Add in settings from the environment (with a prefix of APP) + // Eg.. `APP_DEBUG=1 ./target/app` would set the `debug` key + .add_source(Environment::with_prefix("APP")) + // You may also programmatically change settings + .set_override("database.url", "postgres://")? + .build()?; + + // Now that we're done, let's access our configuration + println!("debug: {:?}", s.get_bool("debug")); + println!("database: {:?}", s.get::("database.url")); + + // You can deserialize (and thus freeze) the entire configuration as + s.try_deserialize() + } +} + +#[derive(Debug, Deserialize)] +#[allow(unused)] +struct Database { + url: String, +} + +#[derive(Debug, Deserialize)] +#[allow(unused)] +struct Sparkpost { + key: String, + token: String, + url: String, + version: u8, +} + +#[derive(Debug, Deserialize)] +#[allow(unused)] +struct Twitter { + consumer_token: String, + consumer_secret: String, +} + +#[derive(Debug, Deserialize)] +#[allow(unused)] +struct Braintree { + merchant_id: String, + public_key: String, + private_key: String, +} diff --git a/examples/hierarchical-env/settings.rs b/examples/hierarchical-env/settings.rs deleted file mode 100644 index 679fc673..00000000 --- a/examples/hierarchical-env/settings.rs +++ /dev/null @@ -1,77 +0,0 @@ -use std::env; - -use config::{Config, ConfigError, Environment, File}; -use serde::Deserialize; - -#[derive(Debug, Deserialize)] -#[allow(unused)] -struct Database { - url: String, -} - -#[derive(Debug, Deserialize)] -#[allow(unused)] -struct Sparkpost { - key: String, - token: String, - url: String, - version: u8, -} - -#[derive(Debug, Deserialize)] -#[allow(unused)] -struct Twitter { - consumer_token: String, - consumer_secret: String, -} - -#[derive(Debug, Deserialize)] -#[allow(unused)] -struct Braintree { - merchant_id: String, - public_key: String, - private_key: String, -} - -#[derive(Debug, Deserialize)] -#[allow(unused)] -pub(crate) struct Settings { - debug: bool, - database: Database, - sparkpost: Sparkpost, - twitter: Twitter, - braintree: Braintree, -} - -impl Settings { - pub(crate) fn new() -> Result { - let run_mode = env::var("RUN_MODE").unwrap_or_else(|_| "development".into()); - - let s = Config::builder() - // Start off by merging in the "default" configuration file - .add_source(File::with_name("examples/hierarchical-env/config/default")) - // Add in the current environment file - // Default to 'development' env - // Note that this file is _optional_ - .add_source( - File::with_name(&format!("examples/hierarchical-env/config/{run_mode}")) - .required(false), - ) - // Add in a local configuration file - // This file shouldn't be checked in to git - .add_source(File::with_name("examples/hierarchical-env/config/local").required(false)) - // Add in settings from the environment (with a prefix of APP) - // Eg.. `APP_DEBUG=1 ./target/app` would set the `debug` key - .add_source(Environment::with_prefix("APP")) - // You may also programmatically change settings - .set_override("database.url", "postgres://")? - .build()?; - - // Now that we're done, let's access our configuration - println!("debug: {:?}", s.get_bool("debug")); - println!("database: {:?}", s.get::("database.url")); - - // You can deserialize (and thus freeze) the entire configuration as - s.try_deserialize() - } -} diff --git a/examples/static_env.rs b/examples/static_env.rs index 563d7255..2af837b3 100644 --- a/examples/static_env.rs +++ b/examples/static_env.rs @@ -1,24 +1,26 @@ +//! Use `config` as a higher-level API over `std::env::var_os` + use std::sync::OnceLock; use config::Config; +fn main() { + println!("{:?}", get::("foo")); +} + +/// Get a configuration value from the environment +pub fn get<'a, T: serde::Deserialize<'a>>(path: &str) -> T { + // You shouldn't probably do it like that and actually handle that error that might happen + // here, but for the sake of simplicity, we do it like this here + config().get::(path).unwrap() +} + fn config() -> &'static Config { static CONFIG: OnceLock = OnceLock::new(); CONFIG.get_or_init(|| { Config::builder() - .add_source(config::Environment::with_prefix("APP").separator("_")) + .add_source(config::Environment::with_prefix("APP")) .build() .unwrap() }) } - -/// Get a configuration value from the static configuration object -pub fn get<'a, T: serde::Deserialize<'a>>(key: &str) -> T { - // You shouldn't probably do it like that and actually handle that error that might happen - // here, but for the sake of simplicity, we do it like this here - config().get::(key).unwrap() -} - -fn main() { - println!("{:?}", get::("foo")); -} diff --git a/examples/watch.rs b/examples/watch.rs index 9894dfe1..f59c026f 100644 --- a/examples/watch.rs +++ b/examples/watch.rs @@ -8,36 +8,8 @@ use std::time::Duration; use config::{Config, File}; use notify::{Event, RecommendedWatcher, RecursiveMode, Watcher}; -fn settings() -> &'static RwLock { - static CONFIG: OnceLock> = OnceLock::new(); - CONFIG.get_or_init(|| { - let settings = load(); - - RwLock::new(settings) - }) -} - -fn refresh() { - *settings().write().unwrap() = load(); -} - -fn load() -> Config { - Config::builder() - .add_source(File::with_name("examples/settings.toml")) - .build() - .unwrap() -} - -fn show() { - println!( - " * Settings :: \n\x1b[31m{:?}\x1b[0m", - settings() - .read() - .unwrap() - .clone() - .try_deserialize::>() - .unwrap() - ); +fn main() { + watch(); } fn watch() -> ! { @@ -55,12 +27,11 @@ fn watch() -> ! { // Add a path to be watched. All files and directories at that path and // below will be monitored for changes. watcher - .watch( - Path::new("examples/settings.toml"), - RecursiveMode::NonRecursive, - ) + .watch(Path::new(SETTINGS_PATH), RecursiveMode::NonRecursive) .unwrap(); + show(); + // This is a simple loop, but you may want to use more complex logic here, // for example to handle I/O. loop { @@ -83,11 +54,36 @@ fn watch() -> ! { } } -fn main() { - // This is just an example of what could be done, today - // We do want this to be built-in to config-rs at some point - // Feel free to take a crack at a PR +fn show() { + println!( + " * Settings :: \n\x1b[31m{:?}\x1b[0m", + settings() + .read() + .unwrap() + .clone() + .try_deserialize::>() + .unwrap() + ); +} - show(); - watch(); +pub fn settings() -> &'static RwLock { + static CONFIG: OnceLock> = OnceLock::new(); + CONFIG.get_or_init(|| { + let settings = load(); + + RwLock::new(settings) + }) +} + +pub fn refresh() { + *settings().write().unwrap() = load(); } + +fn load() -> Config { + Config::builder() + .add_source(File::with_name(SETTINGS_PATH)) + .build() + .unwrap() +} + +static SETTINGS_PATH: &str = "examples/settings.toml"; From 5aa9638bdd2e8038a085ee9a895a0257794627af Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 17 Mar 2026 08:38:40 -0500 Subject: [PATCH 4/5] docs(examples): Clarify intent --- examples/{hierarchical-env => modal}/config/default.toml | 0 examples/{hierarchical-env => modal}/config/development.toml | 0 examples/{hierarchical-env => modal}/config/production.toml | 0 examples/{hierarchical-env => modal}/main.rs | 0 examples/{glob => priority}/conf.d/00-default.toml | 0 examples/{glob => priority}/conf.d/05-some.yml | 0 examples/{glob => priority}/conf.d/99-extra.json | 0 examples/{glob => priority}/main.rs | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename examples/{hierarchical-env => modal}/config/default.toml (100%) rename examples/{hierarchical-env => modal}/config/development.toml (100%) rename examples/{hierarchical-env => modal}/config/production.toml (100%) rename examples/{hierarchical-env => modal}/main.rs (100%) rename examples/{glob => priority}/conf.d/00-default.toml (100%) rename examples/{glob => priority}/conf.d/05-some.yml (100%) rename examples/{glob => priority}/conf.d/99-extra.json (100%) rename examples/{glob => priority}/main.rs (100%) diff --git a/examples/hierarchical-env/config/default.toml b/examples/modal/config/default.toml similarity index 100% rename from examples/hierarchical-env/config/default.toml rename to examples/modal/config/default.toml diff --git a/examples/hierarchical-env/config/development.toml b/examples/modal/config/development.toml similarity index 100% rename from examples/hierarchical-env/config/development.toml rename to examples/modal/config/development.toml diff --git a/examples/hierarchical-env/config/production.toml b/examples/modal/config/production.toml similarity index 100% rename from examples/hierarchical-env/config/production.toml rename to examples/modal/config/production.toml diff --git a/examples/hierarchical-env/main.rs b/examples/modal/main.rs similarity index 100% rename from examples/hierarchical-env/main.rs rename to examples/modal/main.rs diff --git a/examples/glob/conf.d/00-default.toml b/examples/priority/conf.d/00-default.toml similarity index 100% rename from examples/glob/conf.d/00-default.toml rename to examples/priority/conf.d/00-default.toml diff --git a/examples/glob/conf.d/05-some.yml b/examples/priority/conf.d/05-some.yml similarity index 100% rename from examples/glob/conf.d/05-some.yml rename to examples/priority/conf.d/05-some.yml diff --git a/examples/glob/conf.d/99-extra.json b/examples/priority/conf.d/99-extra.json similarity index 100% rename from examples/glob/conf.d/99-extra.json rename to examples/priority/conf.d/99-extra.json diff --git a/examples/glob/main.rs b/examples/priority/main.rs similarity index 100% rename from examples/glob/main.rs rename to examples/priority/main.rs From c7b1b10e19d19e3bc9f691f03ecd227ea2a2af1a Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 17 Mar 2026 08:48:01 -0500 Subject: [PATCH 5/5] docs(examples): Consoldate env examples --- examples/env_list.rs | 24 ------------------------ examples/static_env.rs | 17 +++++++++++------ 2 files changed, 11 insertions(+), 30 deletions(-) delete mode 100644 examples/env_list.rs diff --git a/examples/env_list.rs b/examples/env_list.rs deleted file mode 100644 index e7968ca2..00000000 --- a/examples/env_list.rs +++ /dev/null @@ -1,24 +0,0 @@ -use config::Config; - -#[derive(Debug, Default, serde::Deserialize, PartialEq, Eq)] -struct AppConfig { - list: Vec, -} - -fn main() { - // e.g. set `APP_LIST="Hello World" - - let config = Config::builder() - .add_source( - config::Environment::with_prefix("APP") - .try_parsing(true) - .separator("_") - .list_separator(" "), - ) - .build() - .unwrap(); - - let app: AppConfig = config.try_deserialize().unwrap(); - - assert_eq!(app.list, vec![String::from("Hello"), String::from("World")]); -} diff --git a/examples/static_env.rs b/examples/static_env.rs index 2af837b3..942741e9 100644 --- a/examples/static_env.rs +++ b/examples/static_env.rs @@ -5,21 +5,26 @@ use std::sync::OnceLock; use config::Config; fn main() { - println!("{:?}", get::("foo")); + println!("APP_STRING={:?}", get::("string")); + println!("APP_INT={:?}", get::("int")); + println!("APP_STRLIST={:?}", get::>("strlist")); } /// Get a configuration value from the environment -pub fn get<'a, T: serde::Deserialize<'a>>(path: &str) -> T { - // You shouldn't probably do it like that and actually handle that error that might happen - // here, but for the sake of simplicity, we do it like this here - config().get::(path).unwrap() +pub fn get<'a, T: serde::Deserialize<'a>>(path: &str) -> Option { + config().get::(path).ok() } fn config() -> &'static Config { static CONFIG: OnceLock = OnceLock::new(); CONFIG.get_or_init(|| { Config::builder() - .add_source(config::Environment::with_prefix("APP")) + .add_source( + config::Environment::with_prefix("APP") + .try_parsing(true) + .separator("_") + .list_separator(","), + ) .build() .unwrap() })