24
24
//! [build]
25
25
//! src = "out"
26
26
//!
27
- //! [other-table.foo ]
27
+ //! [preprocessor.my-preprocessor ]
28
28
//! bar = 123
29
29
//! "#;
30
30
//!
31
31
//! // load the `Config` from a toml string
32
32
//! let mut cfg = Config::from_str(src)?;
33
33
//!
34
34
//! // 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));
37
37
//!
38
38
//! // Set the `output.html.theme` directory
39
- //! assert!(cfg.get("output.html").is_none());
39
+ //! assert!(cfg.get::<Value> ("output.html")? .is_none());
40
40
//! cfg.set("output.html.theme", "./themes");
41
41
//!
42
42
//! // 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")?;
44
44
//! assert_eq!(got, Some(PathBuf::from("./themes")));
45
45
//! # Ok(())
46
46
//! # }
47
47
//! # run().unwrap()
48
48
//! ```
49
49
50
+ use crate :: utils:: TomlExt ;
50
51
use crate :: utils:: log_backtrace;
51
- use crate :: utils:: toml_ext:: TomlExt ;
52
- use anyhow:: { Context , Error , Result , bail} ;
52
+ use anyhow:: { Context , Error , Result } ;
53
53
use log:: { debug, trace, warn} ;
54
54
use serde:: { Deserialize , Deserializer , Serialize , Serializer } ;
55
55
use std:: collections:: HashMap ;
@@ -154,18 +154,28 @@ impl Config {
154
154
}
155
155
}
156
156
157
- /// Fetch an arbitrary item from the `Config` as a `toml::Value` .
157
+ /// Get a value from the configuration .
158
158
///
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 ( )
169
179
}
170
180
171
181
/// Convenience method for getting the html renderer's configuration.
@@ -177,7 +187,7 @@ impl Config {
177
187
#[ doc( hidden) ]
178
188
pub fn html_config ( & self ) -> Option < HtmlConfig > {
179
189
match self
180
- . get_deserialized_opt ( "output.html" )
190
+ . get ( "output.html" )
181
191
. with_context ( || "Parsing configuration [output.html]" )
182
192
{
183
193
Ok ( Some ( config) ) => Some ( config) ,
@@ -189,35 +199,12 @@ impl Config {
189
199
}
190
200
}
191
201
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
-
219
202
/// Set a config key, clobbering any existing values along the way.
220
203
///
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
+ ///
221
208
/// The only way this can fail is if we can't serialize `value` into a
222
209
/// `toml::Value`.
223
210
pub fn set < S : Serialize , I : AsRef < str > > ( & mut self , index : I , value : S ) -> Result < ( ) > {
@@ -230,25 +217,15 @@ impl Config {
230
217
self . book . update_value ( key, value) ;
231
218
} else if let Some ( key) = index. strip_prefix ( "build." ) {
232
219
self . build . update_value ( key, value) ;
220
+ } else if let Some ( key) = index. strip_prefix ( "rust." ) {
221
+ self . rust . update_value ( key, value) ;
233
222
} else {
234
223
self . rest . insert ( index, value) ;
235
224
}
236
225
237
226
Ok ( ( ) )
238
227
}
239
228
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
-
252
229
fn from_legacy ( mut table : Value ) -> Config {
253
230
let mut cfg = Config :: default ( ) ;
254
231
@@ -1019,32 +996,16 @@ mod tests {
1019
996
} ;
1020
997
1021
998
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 ( ) ;
1023
1000
1024
1001
assert_eq ! ( got, should_be) ;
1025
1002
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 ( ) ;
1030
1004
let baz_should_be = vec ! [ true , true , false ] ;
1031
1005
1032
1006
assert_eq ! ( got_baz, baz_should_be) ;
1033
1007
}
1034
1008
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
-
1048
1009
/// The config file format has slightly changed (metadata stuff is now under
1049
1010
/// the `book` table instead of being at the top level) so we're adding a
1050
1011
/// **temporary** compatibility check. You should be able to still load the
@@ -1104,13 +1065,29 @@ mod tests {
1104
1065
let key = "foo.bar.baz" ;
1105
1066
let value = "Something Interesting" ;
1106
1067
1107
- assert ! ( cfg. get( key) . is_none( ) ) ;
1068
+ assert ! ( cfg. get:: < i32 > ( key) . unwrap ( ) . is_none( ) ) ;
1108
1069
cfg. set ( key, value) . unwrap ( ) ;
1109
1070
1110
- let got: String = cfg. get_deserialized_opt ( key) . unwrap ( ) . unwrap ( ) ;
1071
+ let got: String = cfg. get ( key) . unwrap ( ) . unwrap ( ) ;
1111
1072
assert_eq ! ( got, value) ;
1112
1073
}
1113
1074
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
+
1114
1091
#[ test]
1115
1092
fn parse_env_vars ( ) {
1116
1093
let inputs = vec ! [
@@ -1141,18 +1118,15 @@ mod tests {
1141
1118
let key = "foo.bar" ;
1142
1119
let value = "baz" ;
1143
1120
1144
- assert ! ( cfg. get( key) . is_none( ) ) ;
1121
+ assert ! ( cfg. get:: < String > ( key) . unwrap ( ) . is_none( ) ) ;
1145
1122
1146
1123
let encoded_key = encode_env_var ( key) ;
1147
1124
// TODO: This is unsafe, and should be rewritten to use a process.
1148
1125
unsafe { env:: set_var ( encoded_key, value) } ;
1149
1126
1150
1127
cfg. update_from_env ( ) ;
1151
1128
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) ;
1156
1130
}
1157
1131
1158
1132
#[ test]
@@ -1162,20 +1136,15 @@ mod tests {
1162
1136
let value = json ! ( { "array" : [ 1 , 2 , 3 ] , "number" : 13.37 } ) ;
1163
1137
let value_str = serde_json:: to_string ( & value) . unwrap ( ) ;
1164
1138
1165
- assert ! ( cfg. get( key) . is_none( ) ) ;
1139
+ assert ! ( cfg. get:: <serde_json :: Value > ( key) . unwrap ( ) . is_none( ) ) ;
1166
1140
1167
1141
let encoded_key = encode_env_var ( key) ;
1168
1142
// TODO: This is unsafe, and should be rewritten to use a process.
1169
1143
unsafe { env:: set_var ( encoded_key, value_str) } ;
1170
1144
1171
1145
cfg. update_from_env ( ) ;
1172
1146
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) ;
1179
1148
}
1180
1149
1181
1150
#[ test]
0 commit comments