cloudiful_config/lib.rs
1mod env;
2mod file;
3mod paths;
4
5use std::io;
6
7#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
8pub struct ReadOptions<'a> {
9 pub env_prefix: Option<&'a str>,
10}
11
12impl<'a> ReadOptions<'a> {
13 pub const fn with_env_prefix(env_prefix: &'a str) -> Self {
14 Self {
15 env_prefix: Some(env_prefix),
16 }
17 }
18}
19
20/// Save config to the platform-default `config.toml` for `app_name`.
21///
22/// On macOS, `stock` resolves to
23/// `~/Library/Application Support/stock/config.toml`.
24///
25/// ```rust,no_run
26/// use cloudiful_config::save;
27/// use serde::Serialize;
28///
29/// #[derive(Serialize)]
30/// struct AppConfig {
31/// port: u16,
32/// }
33///
34/// save("stock", AppConfig { port: 8080 }).unwrap();
35/// ```
36pub fn save<T>(app_name: &str, config: T) -> io::Result<()>
37where
38 T: serde::Serialize,
39{
40 let path = paths::default_config_path(app_name)?;
41 file::write_config(&path, &config, file::FileType::TOML)
42}
43
44/// Read config from the platform-default `config.toml` for `app_name`,
45/// creating the file from `T::default()` when it does not already exist.
46///
47/// Use [`ReadOptions`] to apply environment variable overrides after the file
48/// is loaded.
49///
50/// ```rust,no_run
51/// use cloudiful_config::{ReadOptions, read};
52/// use serde::{Deserialize, Serialize};
53///
54/// #[derive(Default, Deserialize, Serialize)]
55/// struct AppConfig {
56/// port: u16,
57/// }
58///
59/// let _config: AppConfig = read("stock", Some(ReadOptions::with_env_prefix("STOCK_"))).unwrap();
60/// ```
61pub fn read<T>(app_name: &str, options: Option<ReadOptions<'_>>) -> Result<T, io::Error>
62where
63 T: serde::de::DeserializeOwned + Default + serde::Serialize,
64{
65 let path = paths::default_config_path(app_name)?;
66 let config = if !path.is_file() {
67 let default_config = T::default();
68 file::write_config(&path, &default_config, file::FileType::TOML)?;
69 default_config
70 } else {
71 file::read_config(&path)?
72 };
73
74 match options.and_then(|options| options.env_prefix) {
75 Some(prefix) => env::apply_env_overrides(config, prefix),
76 None => Ok(config),
77 }
78}
79
80#[cfg(test)]
81mod tests;