@@ -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
276310const 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}
0 commit comments