2424//! [build]
2525//! src = "out"
2626//!
27- //! [other-table.foo ]
27+ //! [preprocessor.my-preprocessor ]
2828//! bar = 123
2929//! "#;
3030//!
3131//! // load the `Config` from a toml string
3232//! let mut cfg = Config::from_str(src)?;
3333//!
3434//! // retrieve a nested value
35- //! let bar = cfg.get("other-table.foo. bar").cloned() ;
36- //! assert_eq!(bar, Some(Value::Integer( 123) ));
35+ //! let bar = cfg.get::<i32>("preprocessor.my-preprocessor. bar")? ;
36+ //! assert_eq!(bar, Some(123));
3737//!
3838//! // Set the `output.html.theme` directory
39- //! assert!(cfg.get("output.html").is_none());
39+ //! assert!(cfg.get::<Value> ("output.html")? .is_none());
4040//! cfg.set("output.html.theme", "./themes");
4141//!
4242//! // then load it again, automatically deserializing to a `PathBuf`.
43- //! let got: Option<PathBuf> = cfg.get_deserialized_opt ("output.html.theme")?;
43+ //! let got = cfg.get ("output.html.theme")?;
4444//! assert_eq!(got, Some(PathBuf::from("./themes")));
4545//! # Ok(())
4646//! # }
4747//! # run().unwrap()
4848//! ```
4949
50+ use crate :: utils:: TomlExt ;
5051use crate :: utils:: log_backtrace;
51- use crate :: utils:: toml_ext:: TomlExt ;
52- use anyhow:: { Context , Error , Result , bail} ;
52+ use anyhow:: { Context , Error , Result } ;
5353use log:: { debug, trace, warn} ;
5454use serde:: { Deserialize , Deserializer , Serialize , Serializer } ;
5555use std:: collections:: HashMap ;
@@ -154,18 +154,28 @@ impl Config {
154154 }
155155 }
156156
157- /// Fetch an arbitrary item from the `Config` as a `toml::Value` .
157+ /// Get a value from the configuration .
158158 ///
159- /// You can use dotted indices to access nested items (e.g.
160- /// `output.html.playground` will fetch the "playground" out of the html output
161- /// table).
162- pub fn get ( & self , key : & str ) -> Option < & Value > {
163- self . rest . read ( key)
164- }
165-
166- /// Fetch a value from the `Config` so you can mutate it.
167- pub fn get_mut ( & mut self , key : & str ) -> Option < & mut Value > {
168- self . rest . read_mut ( key)
159+ /// This fetches a value from the book configuration. The key can have
160+ /// dotted indices to access nested items (e.g. `output.html.playground`
161+ /// will fetch the "playground" out of the html output table).
162+ ///
163+ /// This does not have access to the [`Config::book`], [`Config::build`],
164+ /// or [`Config::rust`] fields.
165+ ///
166+ /// Returns `Ok(None)` if the field is not set.
167+ ///
168+ /// Returns `Err` if it fails to deserialize.
169+ pub fn get < ' de , T : Deserialize < ' de > > ( & self , name : & str ) -> Result < Option < T > > {
170+ self . rest
171+ . read ( name)
172+ . map ( |value| {
173+ value
174+ . clone ( )
175+ . try_into ( )
176+ . with_context ( || "Couldn't deserialize the value" )
177+ } )
178+ . transpose ( )
169179 }
170180
171181 /// Convenience method for getting the html renderer's configuration.
@@ -177,7 +187,7 @@ impl Config {
177187 #[ doc( hidden) ]
178188 pub fn html_config ( & self ) -> Option < HtmlConfig > {
179189 match self
180- . get_deserialized_opt ( "output.html" )
190+ . get ( "output.html" )
181191 . with_context ( || "Parsing configuration [output.html]" )
182192 {
183193 Ok ( Some ( config) ) => Some ( config) ,
@@ -189,35 +199,12 @@ impl Config {
189199 }
190200 }
191201
192- /// Deprecated, use get_deserialized_opt instead.
193- #[ deprecated = "use get_deserialized_opt instead" ]
194- pub fn get_deserialized < ' de , T : Deserialize < ' de > , S : AsRef < str > > ( & self , name : S ) -> Result < T > {
195- let name = name. as_ref ( ) ;
196- match self . get_deserialized_opt ( name) ? {
197- Some ( value) => Ok ( value) ,
198- None => bail ! ( "Key not found, {:?}" , name) ,
199- }
200- }
201-
202- /// Convenience function to fetch a value from the config and deserialize it
203- /// into some arbitrary type.
204- pub fn get_deserialized_opt < ' de , T : Deserialize < ' de > , S : AsRef < str > > (
205- & self ,
206- name : S ,
207- ) -> Result < Option < T > > {
208- let name = name. as_ref ( ) ;
209- self . get ( name)
210- . map ( |value| {
211- value
212- . clone ( )
213- . try_into ( )
214- . with_context ( || "Couldn't deserialize the value" )
215- } )
216- . transpose ( )
217- }
218-
219202 /// Set a config key, clobbering any existing values along the way.
220203 ///
204+ /// The key can have dotted indices for nested items (e.g.
205+ /// `output.html.playground` will set the "playground" in the html output
206+ /// table).
207+ ///
221208 /// The only way this can fail is if we can't serialize `value` into a
222209 /// `toml::Value`.
223210 pub fn set < S : Serialize , I : AsRef < str > > ( & mut self , index : I , value : S ) -> Result < ( ) > {
@@ -230,25 +217,15 @@ impl Config {
230217 self . book . update_value ( key, value) ;
231218 } else if let Some ( key) = index. strip_prefix ( "build." ) {
232219 self . build . update_value ( key, value) ;
220+ } else if let Some ( key) = index. strip_prefix ( "rust." ) {
221+ self . rust . update_value ( key, value) ;
233222 } else {
234223 self . rest . insert ( index, value) ;
235224 }
236225
237226 Ok ( ( ) )
238227 }
239228
240- /// Get the table associated with a particular renderer.
241- pub fn get_renderer < I : AsRef < str > > ( & self , index : I ) -> Option < & Table > {
242- let key = format ! ( "output.{}" , index. as_ref( ) ) ;
243- self . get ( & key) . and_then ( Value :: as_table)
244- }
245-
246- /// Get the table associated with a particular preprocessor.
247- pub fn get_preprocessor < I : AsRef < str > > ( & self , index : I ) -> Option < & Table > {
248- let key = format ! ( "preprocessor.{}" , index. as_ref( ) ) ;
249- self . get ( & key) . and_then ( Value :: as_table)
250- }
251-
252229 fn from_legacy ( mut table : Value ) -> Config {
253230 let mut cfg = Config :: default ( ) ;
254231
@@ -1019,32 +996,16 @@ mod tests {
1019996 } ;
1020997
1021998 let cfg = Config :: from_str ( src) . unwrap ( ) ;
1022- let got: RandomOutput = cfg. get_deserialized_opt ( "output.random" ) . unwrap ( ) . unwrap ( ) ;
999+ let got: RandomOutput = cfg. get ( "output.random" ) . unwrap ( ) . unwrap ( ) ;
10231000
10241001 assert_eq ! ( got, should_be) ;
10251002
1026- let got_baz: Vec < bool > = cfg
1027- . get_deserialized_opt ( "output.random.baz" )
1028- . unwrap ( )
1029- . unwrap ( ) ;
1003+ let got_baz: Vec < bool > = cfg. get ( "output.random.baz" ) . unwrap ( ) . unwrap ( ) ;
10301004 let baz_should_be = vec ! [ true , true , false ] ;
10311005
10321006 assert_eq ! ( got_baz, baz_should_be) ;
10331007 }
10341008
1035- #[ test]
1036- fn mutate_some_stuff ( ) {
1037- // really this is just a sanity check to make sure the borrow checker
1038- // is happy...
1039- let src = COMPLEX_CONFIG ;
1040- let mut config = Config :: from_str ( src) . unwrap ( ) ;
1041- let key = "output.html.playground.editable" ;
1042-
1043- assert_eq ! ( config. get( key) . unwrap( ) , & Value :: Boolean ( true ) ) ;
1044- * config. get_mut ( key) . unwrap ( ) = Value :: Boolean ( false ) ;
1045- assert_eq ! ( config. get( key) . unwrap( ) , & Value :: Boolean ( false ) ) ;
1046- }
1047-
10481009 /// The config file format has slightly changed (metadata stuff is now under
10491010 /// the `book` table instead of being at the top level) so we're adding a
10501011 /// **temporary** compatibility check. You should be able to still load the
@@ -1104,13 +1065,29 @@ mod tests {
11041065 let key = "foo.bar.baz" ;
11051066 let value = "Something Interesting" ;
11061067
1107- assert ! ( cfg. get( key) . is_none( ) ) ;
1068+ assert ! ( cfg. get:: < i32 > ( key) . unwrap ( ) . is_none( ) ) ;
11081069 cfg. set ( key, value) . unwrap ( ) ;
11091070
1110- let got: String = cfg. get_deserialized_opt ( key) . unwrap ( ) . unwrap ( ) ;
1071+ let got: String = cfg. get ( key) . unwrap ( ) . unwrap ( ) ;
11111072 assert_eq ! ( got, value) ;
11121073 }
11131074
1075+ #[ test]
1076+ fn set_special_tables ( ) {
1077+ let mut cfg = Config :: default ( ) ;
1078+ assert_eq ! ( cfg. book. title, None ) ;
1079+ cfg. set ( "book.title" , "my title" ) . unwrap ( ) ;
1080+ assert_eq ! ( cfg. book. title, Some ( "my title" . to_string( ) ) ) ;
1081+
1082+ assert_eq ! ( & cfg. build. build_dir, Path :: new( "book" ) ) ;
1083+ cfg. set ( "build.build-dir" , "some-directory" ) . unwrap ( ) ;
1084+ assert_eq ! ( & cfg. build. build_dir, Path :: new( "some-directory" ) ) ;
1085+
1086+ assert_eq ! ( cfg. rust. edition, None ) ;
1087+ cfg. set ( "rust.edition" , "2024" ) . unwrap ( ) ;
1088+ assert_eq ! ( cfg. rust. edition, Some ( RustEdition :: E2024 ) ) ;
1089+ }
1090+
11141091 #[ test]
11151092 fn parse_env_vars ( ) {
11161093 let inputs = vec ! [
@@ -1141,18 +1118,15 @@ mod tests {
11411118 let key = "foo.bar" ;
11421119 let value = "baz" ;
11431120
1144- assert ! ( cfg. get( key) . is_none( ) ) ;
1121+ assert ! ( cfg. get:: < String > ( key) . unwrap ( ) . is_none( ) ) ;
11451122
11461123 let encoded_key = encode_env_var ( key) ;
11471124 // TODO: This is unsafe, and should be rewritten to use a process.
11481125 unsafe { env:: set_var ( encoded_key, value) } ;
11491126
11501127 cfg. update_from_env ( ) ;
11511128
1152- assert_eq ! (
1153- cfg. get_deserialized_opt:: <String , _>( key) . unwrap( ) . unwrap( ) ,
1154- value
1155- ) ;
1129+ assert_eq ! ( cfg. get:: <String >( key) . unwrap( ) . unwrap( ) , value) ;
11561130 }
11571131
11581132 #[ test]
@@ -1162,20 +1136,15 @@ mod tests {
11621136 let value = json ! ( { "array" : [ 1 , 2 , 3 ] , "number" : 13.37 } ) ;
11631137 let value_str = serde_json:: to_string ( & value) . unwrap ( ) ;
11641138
1165- assert ! ( cfg. get( key) . is_none( ) ) ;
1139+ assert ! ( cfg. get:: <serde_json :: Value > ( key) . unwrap ( ) . is_none( ) ) ;
11661140
11671141 let encoded_key = encode_env_var ( key) ;
11681142 // TODO: This is unsafe, and should be rewritten to use a process.
11691143 unsafe { env:: set_var ( encoded_key, value_str) } ;
11701144
11711145 cfg. update_from_env ( ) ;
11721146
1173- assert_eq ! (
1174- cfg. get_deserialized_opt:: <serde_json:: Value , _>( key)
1175- . unwrap( )
1176- . unwrap( ) ,
1177- value
1178- ) ;
1147+ assert_eq ! ( cfg. get:: <serde_json:: Value >( key) . unwrap( ) . unwrap( ) , value) ;
11791148 }
11801149
11811150 #[ test]
0 commit comments