Skip to content

Commit 4d4aaec

Browse files
committed
Add a global_module example for a singleton configuration module deserialized to a predefined structures
1 parent e3c1d0b commit 4d4aaec

File tree

4 files changed

+132
-0
lines changed

4 files changed

+132
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
verbose=1
2+
3+
[cred]
4+
user="robert"
5+
key="123456789"

examples/global_module/cred.rs

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use super::settings::Settings;
2+
3+
pub fn list_cred() {
4+
match Settings::user() {
5+
Ok(u) => println!("My name is: {u}"),
6+
Err(e) => println!("{e}")
7+
}
8+
9+
match Settings::key() {
10+
Ok(k) => println!("My key is: {k}"),
11+
Err(e) => println!("{e}")
12+
}
13+
}

examples/global_module/main.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
mod settings;
2+
mod cred;
3+
4+
use crate::settings::Settings;
5+
use crate::cred::list_cred;
6+
7+
fn main() {
8+
// init the config module
9+
Settings::init(Some("examples/global_module/config/default.toml"));
10+
11+
// now your config may be used anywhere in the code where you are able to
12+
// use "crate::settings" or "super::settings".
13+
let verbosity = Settings::verbosity();
14+
15+
if verbosity > 0 {
16+
println!("Hello world");
17+
}
18+
19+
list_cred();
20+
21+
return;
22+
}

examples/global_module/settings.rs

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
use config::{Config, File};
2+
use serde_derive::Deserialize;
3+
use std::sync::OnceLock;
4+
use std::sync::RwLock;
5+
6+
7+
#[derive(Default, Clone, Deserialize)]
8+
struct Cred {
9+
user: String,
10+
key: String,
11+
}
12+
13+
#[derive(Default, Clone, Deserialize)]
14+
pub struct Settings {
15+
verbose: Option<u8>,
16+
cred: Option<Cred>,
17+
}
18+
19+
20+
// This function defines the static settings storage.
21+
fn settings() -> &'static RwLock<Settings> {
22+
static SETTINGS: OnceLock<RwLock<Settings>> = OnceLock::new();
23+
SETTINGS.get_or_init(|| RwLock::new(Settings::default()))
24+
}
25+
26+
fn build_config(file: &str) -> Settings {
27+
let s = Config::builder()
28+
// Configuration file
29+
.add_source(File::with_name(file).required(false))
30+
.build()
31+
.expect("Config build failed");
32+
33+
// Deserialize (and thus freeze) the entire configuration
34+
s.try_deserialize().unwrap()
35+
}
36+
37+
impl Settings {
38+
// This associated function replaces previous settings values with a newly
39+
// loaded ones.
40+
//
41+
// It is mainly intended for loading the values from config file to replace
42+
// the plain default used for static allocation. Thus running it once at
43+
// the beginning of the program execution when the config files are known.
44+
//
45+
// But a subsequent call to this function may be used to update the settings,
46+
// for example when the config file change during the execution and you want
47+
// to sync with it (signal/notify/whatever based reload).
48+
pub fn init(cfgfile: Option<&str>) {
49+
let file = match cfgfile {
50+
Some(x) => x,
51+
None => "config.toml"
52+
};
53+
54+
let mut new_settings = settings().write().unwrap();
55+
*new_settings = build_config(file);
56+
}
57+
58+
// Following associated functions are just getters, when you want to keep
59+
// the Settings structure members private.
60+
pub fn user() -> Result<String, String> {
61+
match &settings().read().unwrap().cred {
62+
Some(c) => Ok(c.user.clone()),
63+
None => Err(format!("Credential config is missing"))
64+
}
65+
}
66+
67+
pub fn key() -> Result<String, String> {
68+
match &settings().read().unwrap().cred {
69+
Some(c) => Ok(c.key.clone()),
70+
None => Err(format!("Credential config is missing"))
71+
}
72+
}
73+
74+
pub fn verbosity() -> u8 {
75+
match settings().read().unwrap().verbose {
76+
Some(v) => v,
77+
None => 0
78+
}
79+
}
80+
81+
// It is not a problem to make all the Settings structure members public and
82+
// then only create here one function, that will return a read reference
83+
// to the Settings. This may be useful if you want to omit the getters and
84+
// the settings contains just plain values, that doesn't need any error
85+
// handling.
86+
//
87+
// Example:
88+
// pub fn new() -> Self {
89+
// settings().read().unwrap()
90+
// }
91+
}
92+

0 commit comments

Comments
 (0)