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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
//! Simple, efficient configuration loading for Rust.
//!
//! `confy-rs` loads configuration from multiple file formats, merges layered
//! sources and deserializes the result into your own types via `serde`. With
//! the `watch` feature it also hot-reloads the configuration when source
//! files change on disk.
//!
//! # Highlights
//!
//! - **Multi-format**: TOML / YAML / JSON, detected from the file extension
//! - **Layered**: defaults + any number of files, deep-merged in order
//! - **Hot reload**: debounced cross-platform file watching; readers are
//! lock-free and the previous config is kept when a reload fails
//! - **Lean**: format parsers and the watcher are feature-gated
//!
//! # Quick start
//!
//! ```
//! use serde::Deserialize;
//!
//! #[derive(Debug, Deserialize)]
//! struct AppConfig {
//! name: String,
//! port: u16,
//! }
//!
//! # fn main() -> confy_rs::Result<()> {
//! let config: AppConfig = confy_rs::load_str(
//! r#"
//! name = "demo"
//! port = 8080
//! "#,
//! confy_rs::Format::Toml,
//! )?;
//! assert_eq!(config.port, 8080);
//! # Ok(())
//! # }
//! ```
//!
//! Loading from files works the same way — the format is detected from the
//! extension, and later sources override earlier ones:
//!
//! ```no_run
//! # use serde::Deserialize;
//! # #[derive(Deserialize)]
//! # struct AppConfig { port: u16 }
//! # fn main() -> confy_rs::Result<()> {
//! // One-liner for the common case
//! let config: AppConfig = confy_rs::load("config.toml")?;
//!
//! // Layered loading
//! let config: AppConfig = confy_rs::builder()
//! .file("config/default.toml")
//! .file_optional("config/local.json")
//! .build()?;
//! # Ok(())
//! # }
//! ```
//!
//! # Hot reloading
//!
//! ```no_run
//! # use serde::Deserialize;
//! # #[derive(Deserialize)]
//! # struct AppConfig { port: u16 }
//! # fn main() -> confy_rs::Result<()> {
//! let watcher = confy_rs::builder()
//! .file("config.toml")
//! .watch::<AppConfig>()?;
//!
//! watcher.on_change(|config| println!("port is now {}", config.port));
//! let current = watcher.get(); // lock-free snapshot, callable anywhere
//! # Ok(())
//! # }
//! ```
//!
//! Reloads are debounced, editors that save via atomic rename are handled,
//! and when a reload fails the previous configuration stays active while the
//! error is reported through [`ConfigWatcher::on_error`].
//!
//! # Cargo features
//!
//! | Feature | Default | Effect |
//! |---------|---------|--------|
//! | `toml` | yes | TOML support via the `toml` crate |
//! | `yaml` | no | YAML support via `serde_yaml_ng` |
//! | `watch` | yes | hot reloading via `notify` + `arc-swap` |
//!
//! JSON support is always built in.
use Path;
use DeserializeOwned;
pub use crateConfigBuilder;
pub use crateError;
pub use crateFormat;
pub use crateConfigWatcher;
/// Convenience alias for `std::result::Result<T, confy_rs::Error>`.
pub type Result<T> = Result;
/// Creates a new empty [`ConfigBuilder`].
/// Loads a single configuration file and deserializes it into `T`.
///
/// The format is detected from the file extension. This is shorthand for
/// `confy_rs::builder().file(path).build()`.
///
/// # Errors
///
/// Returns an error if the file is missing or unreadable, its format is
/// unknown or disabled, its content is invalid, or the parsed tree does not
/// match `T`.
///
/// # Example
///
/// ```no_run
/// # fn main() -> confy_rs::Result<()> {
/// let config: serde_json::Value = confy_rs::load("config.toml")?;
/// # Ok(())
/// # }
/// ```
/// Parses configuration from an in-memory string in the given format.
///
/// Handy for tests and for configuration that is embedded or fetched from
/// somewhere other than the file system.
///
/// # Errors
///
/// Returns an error if the format is disabled, the content is invalid, or
/// the parsed tree does not match `T`.