Skip to content

Commit 26e3e2d

Browse files
committed
docs(examples): Better organize examples
1 parent 4e8637c commit 26e3e2d

11 files changed

Lines changed: 153 additions & 201 deletions

File tree

examples/async_source.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! Example below presents sample configuration server and client.
2+
13
use std::{error::Error, fmt::Debug};
24

35
use async_trait::async_trait;
@@ -7,11 +9,6 @@ use config::{
79
use futures::{FutureExt, select};
810
use warp::Filter;
911

10-
// Example below presents sample configuration server and client.
11-
//
12-
// Server serves simple configuration on HTTP endpoint.
13-
// Client consumes it using custom HTTP AsyncSource built on top of reqwest.
14-
1512
#[tokio::main]
1613
async fn main() -> Result<(), Box<dyn Error>> {
1714
select! {
@@ -20,6 +17,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
2017
}
2118
}
2219

20+
/// Serve simple configuration on HTTP endpoint.
2321
async fn run_server() -> Result<(), Box<dyn Error>> {
2422
let service = warp::path("configuration").map(|| r#"{ "value" : 123 }"#);
2523

@@ -30,6 +28,7 @@ async fn run_server() -> Result<(), Box<dyn Error>> {
3028
Ok(())
3129
}
3230

31+
/// Consumes the server's configuration using custom HTTP AsyncSource built on top of reqwest.
3332
async fn run_client() -> Result<(), Box<dyn Error>> {
3433
// Good enough for an example to allow server to start
3534
tokio::time::sleep(tokio::time::Duration::from_secs(3)).await;
@@ -47,8 +46,7 @@ async fn run_client() -> Result<(), Box<dyn Error>> {
4746
Ok(())
4847
}
4948

50-
// Actual implementation of AsyncSource can be found below
51-
49+
/// `AsyncSource` to read configuration from an HTTP server
5250
#[derive(Debug)]
5351
struct HttpSource<F: Format> {
5452
uri: String,

examples/custom_file_format/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ fn main() {
2424

2525
// Deserialize the config object into your Settings struct:
2626
let settings: Settings = settings.try_deserialize().unwrap();
27+
2728
println!("{settings:#?}");
2829
}
2930

@@ -65,8 +66,7 @@ impl Format for PemFile {
6566
}
6667
}
6768

68-
// A slice of extensions associated to this format, when an extension
69-
// is omitted from a file source, these will be tried implicitly:
69+
// When an extension is omitted from a file source, these will be tried implicitly:
7070
impl FileStoredFormat for PemFile {
7171
fn file_extensions(&self) -> &'static [&'static str] {
7272
&["pem"]

examples/custom_str_format.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use config::{Config, File, FileStoredFormat, Format, Map, Value, ValueKind};
22

33
fn main() {
44
let config = Config::builder()
5-
.add_source(File::from_str("bad", MyFormat))
6-
.add_source(File::from_str("good", MyFormat))
5+
.add_source(File::from_str("bad", CustomFormat))
6+
.add_source(File::from_str("good", CustomFormat))
77
.build();
88

99
match config {
@@ -13,9 +13,9 @@ fn main() {
1313
}
1414

1515
#[derive(Debug, Clone)]
16-
pub struct MyFormat;
16+
pub struct CustomFormat;
1717

18-
impl Format for MyFormat {
18+
impl Format for CustomFormat {
1919
fn parse(
2020
&self,
2121
uri: Option<&String>,
@@ -40,11 +40,14 @@ impl Format for MyFormat {
4040
}
4141
}
4242

43-
// As strange as it seems for config sourced from a string, legacy demands its sacrifice
44-
// It is only required for File source, custom sources can use Format without caring for extensions
45-
static MY_FORMAT_EXT: Vec<&'static str> = vec![];
46-
impl FileStoredFormat for MyFormat {
43+
impl FileStoredFormat for CustomFormat {
4744
fn file_extensions(&self) -> &'static [&'static str] {
48-
&MY_FORMAT_EXT
45+
&NO_EXTS
4946
}
5047
}
48+
49+
/// In-memory format doesn't have any file extensions
50+
///
51+
/// It is only required for File source,
52+
/// custom sources can use Format without caring for extensions
53+
static NO_EXTS: Vec<&'static str> = vec![];

examples/glob/main.rs

Lines changed: 8 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,17 @@
1+
//! Gather all conf files from conf.d/ using glob and put in 1 merge call.
2+
13
use std::collections::HashMap;
2-
use std::path::Path;
34

45
use config::{Config, File};
56
use glob::glob;
67

78
fn main() {
8-
// Option 1
9-
// --------
10-
// Gather all conf files from conf/ manually
11-
let settings = Config::builder()
12-
// File::with_name(..) is shorthand for File::from(Path::new(..))
13-
.add_source(File::with_name("examples/glob/conf/00-default.toml"))
14-
.add_source(File::from(Path::new("examples/glob/conf/05-some.yml")))
15-
.add_source(File::from(Path::new("examples/glob/conf/99-extra.json")))
16-
.build()
17-
.unwrap();
18-
19-
// Print out our settings (as a HashMap)
20-
println!(
21-
"\n{:?} \n\n-----------",
22-
settings
23-
.try_deserialize::<HashMap<String, String>>()
24-
.unwrap()
25-
);
26-
27-
// Option 2
28-
// --------
29-
// Gather all conf files from conf/ manually, but put in 1 merge call.
30-
let settings = Config::builder()
31-
.add_source(vec![
32-
File::with_name("examples/glob/conf/00-default.toml"),
33-
File::from(Path::new("examples/glob/conf/05-some.yml")),
34-
File::from(Path::new("examples/glob/conf/99-extra.json")),
35-
])
36-
.build()
37-
.unwrap();
38-
39-
// Print out our settings (as a HashMap)
40-
println!(
41-
"\n{:?} \n\n-----------",
42-
settings
43-
.try_deserialize::<HashMap<String, String>>()
44-
.unwrap()
45-
);
46-
47-
// Option 3
48-
// --------
49-
// Gather all conf files from conf/ using glob and put in 1 merge call.
50-
let settings = Config::builder()
51-
.add_source(
52-
glob("examples/glob/conf/*")
53-
.unwrap()
54-
.map(|path| File::from(path.unwrap()))
55-
.collect::<Vec<_>>(),
56-
)
57-
.build()
58-
.unwrap();
9+
// Glob results are sorted, ensuring user priority is preserved
10+
let files = glob("examples/glob/conf.d/*")
11+
.unwrap()
12+
.map(|path| File::from(path.unwrap()))
13+
.collect::<Vec<_>>();
14+
let settings = Config::builder().add_source(files).build().unwrap();
5915

6016
// Print out our settings (as a HashMap)
6117
println!(

examples/hierarchical-env/main.rs

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,84 @@
1-
mod settings;
1+
use std::env;
22

3-
use settings::Settings;
3+
use config::{Config, ConfigError, Environment, File};
4+
use serde::Deserialize;
45

56
fn main() {
67
let settings = Settings::new();
78

89
// Print out our settings
910
println!("{settings:?}");
1011
}
12+
13+
#[derive(Debug, Deserialize)]
14+
#[allow(unused)]
15+
pub(crate) struct Settings {
16+
debug: bool,
17+
database: Database,
18+
sparkpost: Sparkpost,
19+
twitter: Twitter,
20+
braintree: Braintree,
21+
}
22+
23+
impl Settings {
24+
pub(crate) fn new() -> Result<Self, ConfigError> {
25+
let run_mode = env::var("RUN_MODE").unwrap_or_else(|_| "development".into());
26+
27+
let s = Config::builder()
28+
// Start off by merging in the "default" configuration file
29+
.add_source(File::with_name("examples/hierarchical-env/config/default"))
30+
// Add in the current environment file
31+
// Default to 'development' env
32+
// Note that this file is _optional_
33+
.add_source(
34+
File::with_name(&format!("examples/hierarchical-env/config/{run_mode}"))
35+
.required(false),
36+
)
37+
// Add in a local configuration file
38+
// This file shouldn't be checked in to git
39+
.add_source(File::with_name("examples/hierarchical-env/config/local").required(false))
40+
// Add in settings from the environment (with a prefix of APP)
41+
// Eg.. `APP_DEBUG=1 ./target/app` would set the `debug` key
42+
.add_source(Environment::with_prefix("APP"))
43+
// You may also programmatically change settings
44+
.set_override("database.url", "postgres://")?
45+
.build()?;
46+
47+
// Now that we're done, let's access our configuration
48+
println!("debug: {:?}", s.get_bool("debug"));
49+
println!("database: {:?}", s.get::<String>("database.url"));
50+
51+
// You can deserialize (and thus freeze) the entire configuration as
52+
s.try_deserialize()
53+
}
54+
}
55+
56+
#[derive(Debug, Deserialize)]
57+
#[allow(unused)]
58+
struct Database {
59+
url: String,
60+
}
61+
62+
#[derive(Debug, Deserialize)]
63+
#[allow(unused)]
64+
struct Sparkpost {
65+
key: String,
66+
token: String,
67+
url: String,
68+
version: u8,
69+
}
70+
71+
#[derive(Debug, Deserialize)]
72+
#[allow(unused)]
73+
struct Twitter {
74+
consumer_token: String,
75+
consumer_secret: String,
76+
}
77+
78+
#[derive(Debug, Deserialize)]
79+
#[allow(unused)]
80+
struct Braintree {
81+
merchant_id: String,
82+
public_key: String,
83+
private_key: String,
84+
}

examples/hierarchical-env/settings.rs

Lines changed: 0 additions & 77 deletions
This file was deleted.

examples/static_env.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
1+
//! Use `confg` as a higher-level API over `std::env::var_os`
2+
13
use std::sync::OnceLock;
24

35
use config::Config;
46

7+
fn main() {
8+
println!("{:?}", get::<String>("foo"));
9+
}
10+
11+
/// Get a configuration value from the environment
12+
pub fn get<'a, T: serde::Deserialize<'a>>(path: &str) -> T {
13+
// You shouldn't probably do it like that and actually handle that error that might happen
14+
// here, but for the sake of simplicity, we do it like this here
15+
config().get::<T>(path).unwrap()
16+
}
17+
518
fn config() -> &'static Config {
619
static CONFIG: OnceLock<Config> = OnceLock::new();
720
CONFIG.get_or_init(|| {
821
Config::builder()
9-
.add_source(config::Environment::with_prefix("APP").separator("_"))
22+
.add_source(config::Environment::with_prefix("APP"))
1023
.build()
1124
.unwrap()
1225
})
1326
}
14-
15-
/// Get a configuration value from the static configuration object
16-
pub fn get<'a, T: serde::Deserialize<'a>>(key: &str) -> T {
17-
// You shouldn't probably do it like that and actually handle that error that might happen
18-
// here, but for the sake of simplicity, we do it like this here
19-
config().get::<T>(key).unwrap()
20-
}
21-
22-
fn main() {
23-
println!("{:?}", get::<String>("foo"));
24-
}

0 commit comments

Comments
 (0)