Skip to content

Commit 9490a28

Browse files
authored
feat: allow accessing extra config (#518)
1 parent f562211 commit 9490a28

2 files changed

Lines changed: 62 additions & 1 deletion

File tree

cot/src/config.rs

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use crate::utils::chrono::DateTimeWithOffsetAdapter;
3434
///
3535
/// This is all the project-specific configuration data that can (and makes
3636
/// sense to) be expressed in a TOML configuration file.
37-
#[derive(Debug, Clone, PartialEq, Eq, Builder, Serialize, Deserialize)]
37+
#[derive(Debug, Clone, Builder, Serialize, Deserialize)]
3838
#[builder(build_fn(skip, error = std::convert::Infallible))]
3939
#[serde(default)]
4040
#[non_exhaustive]
@@ -271,6 +271,40 @@ pub struct ProjectConfig {
271271
/// ```
272272
#[cfg(feature = "email")]
273273
pub email: EmailConfig,
274+
/// All the config that was not recognized.
275+
///
276+
/// This is useful for parsing project-specific config that is not part of
277+
/// any of the predefined fields in `ProjectConfig`.
278+
///
279+
/// # Examples
280+
///
281+
/// ```
282+
/// use cot::config::ProjectConfig;
283+
/// use serde::Deserialize;
284+
///
285+
/// let config = ProjectConfig::from_toml(
286+
/// r#"
287+
/// [my_cot_project]
288+
/// foo = "bar"
289+
/// "#,
290+
/// )?;
291+
///
292+
/// #[derive(Deserialize)]
293+
/// struct MyCotProjectConfig {
294+
/// foo: String,
295+
/// }
296+
///
297+
/// let my_config: MyCotProjectConfig = config
298+
/// .extra
299+
/// .get("my_cot_project")
300+
/// .ok_or("could not find the project config")?
301+
/// .clone()
302+
/// .try_into()?;
303+
/// assert_eq!(my_config.foo, "bar");
304+
/// # Ok::<(), Box<dyn std::error::Error>>(())
305+
/// ```
306+
#[serde(flatten)]
307+
pub extra: toml::Table,
274308
}
275309

276310
const fn default_debug() -> bool {
@@ -381,6 +415,7 @@ impl ProjectConfigBuilder {
381415
middlewares: self.middlewares.clone().unwrap_or_default(),
382416
#[cfg(feature = "email")]
383417
email: self.email.clone().unwrap_or_default(),
418+
extra: toml::Table::default(),
384419
}
385420
}
386421
}
@@ -3116,4 +3151,29 @@ mod tests {
31163151
assert_eq!(u1, u2);
31173152
assert_eq!(u1.as_str(), s);
31183153
}
3154+
3155+
#[test]
3156+
fn config_extra_can_be_accessed() {
3157+
#[derive(Deserialize)]
3158+
struct CustomConfig {
3159+
foo: String,
3160+
}
3161+
3162+
let config = ProjectConfig::from_toml(
3163+
r#"
3164+
[custom_config]
3165+
foo = "bar"
3166+
"#,
3167+
)
3168+
.unwrap();
3169+
3170+
let my_config: CustomConfig = config
3171+
.extra
3172+
.get("custom_config")
3173+
.unwrap()
3174+
.clone()
3175+
.try_into()
3176+
.unwrap();
3177+
assert_eq!(my_config.foo, "bar");
3178+
}
31193179
}

cot/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ pub use cot_macros::test;
185185
pub use http;
186186
#[cfg(feature = "openapi")]
187187
pub use schemars;
188+
pub use toml;
188189

189190
pub use crate::__private::askama::{Template, filter_fn};
190191
pub use crate::project::{

0 commit comments

Comments
 (0)