@@ -124,6 +124,16 @@ fn always_valid<T>(_: &T) -> bool {
124
124
true
125
125
}
126
126
127
+ /// Error when setting an option by option name and option value as strings.
128
+ enum SetOptionByStringError {
129
+ /// The option name does not exist.
130
+ InvalidKey ,
131
+ /// Error when converting the value from string.
132
+ ValueParseError ,
133
+ /// The value failed validation.
134
+ ValueValidationError ,
135
+ }
136
+
127
137
/// An MMTk option of a given type.
128
138
/// This type allows us to store some metadata for the option. To get the value of an option,
129
139
/// you can simply dereference it (for example, *options.threads).
@@ -192,20 +202,21 @@ macro_rules! options {
192
202
193
203
impl Options {
194
204
/// Set an option and run its validator for its value.
195
- fn set_by_string_inner( & mut self , s: & str , val: & str ) -> bool {
205
+ fn set_by_string_inner( & mut self , s: & str , val: & str ) -> Result < ( ) , SetOptionByStringError > {
196
206
match s {
197
207
// Parse the given value from str (by env vars or by calling process()) to the right type
198
- $( stringify!( $name) => if let Ok ( typed_val) = val. parse:: <$type>( ) {
199
- let is_set = self . $name. set( typed_val) ;
200
- if !is_set {
201
- eprintln!( "Warn: unable to set {}={:?}. Invalid value. Default value will be used." , s, val) ;
208
+ $( stringify!( $name) => {
209
+ let Ok ( typed_val) = val. parse:: <$type>( ) else {
210
+ return Err ( SetOptionByStringError :: ValueParseError ) ;
211
+ } ;
212
+
213
+ if !self . $name. set( typed_val) {
214
+ return Err ( SetOptionByStringError :: ValueValidationError ) ;
202
215
}
203
- is_set
204
- } else {
205
- eprintln!( "Warn: unable to set {}={:?}. Can't parse value. Default value will be used." , s, val) ;
206
- false
216
+
217
+ Ok ( ( ) )
207
218
} ) *
208
- _ => panic! ( "Invalid Options key: {}" , s )
219
+ _ => Err ( SetOptionByStringError :: InvalidKey )
209
220
}
210
221
}
211
222
@@ -250,31 +261,42 @@ impl Options {
250
261
/// * `s`: The name of the option, same as the field name.
251
262
/// * `val`: The value of the option, as a string. It will be parsed by `FromStr::from_str`.
252
263
pub fn set_by_string ( & mut self , s : & str , val : & str ) -> bool {
253
- self . set_by_string_inner ( s, val)
264
+ self . set_by_string_inner ( s, val) . is_ok ( )
254
265
}
255
266
256
267
/// Set options in bulk by names and values as strings.
257
268
///
258
269
/// Returns true if all the options are set successfully.
259
270
///
260
- /// This method returns false if the option string is invalid, or if it includes any invalid
261
- /// option. If error happens, some options in `self` may have been modified while others are
262
- /// not .
271
+ /// Panics if the `options` argument contains any unrecognized keys. Returns false if any
272
+ /// option given in the ` options` argument cannot be set due to parsing errors or validation
273
+ /// errors .
263
274
///
264
275
/// Arguments:
265
276
/// * `options`: a string that is key value pairs separated by white spaces or commas, e.g.
266
277
/// `threads=1 stress_factor=4096`, or `threads=1,stress_factor=4096`. Each key-value pair
267
278
/// will be set via [`Options::set_by_string`].
268
279
pub fn bulk_set_by_string ( & mut self , options : & str ) -> bool {
269
- for opt in options. replace ( "," , " " ) . split_ascii_whitespace ( ) {
280
+ for opt in options. replace ( ',' , " " ) . split_ascii_whitespace ( ) {
270
281
let kv_pair: Vec < & str > = opt. split ( '=' ) . collect ( ) ;
271
282
if kv_pair. len ( ) != 2 {
272
283
return false ;
273
284
}
274
285
275
286
let key = kv_pair[ 0 ] ;
276
287
let val = kv_pair[ 1 ] ;
277
- if !self . set_by_string ( key, val) {
288
+ if let Err ( e) = self . set_by_string_inner ( key, val) {
289
+ match e {
290
+ SetOptionByStringError :: InvalidKey => {
291
+ panic ! ( "Invalid Options key: {}" , key) ;
292
+ }
293
+ SetOptionByStringError :: ValueParseError => {
294
+ eprintln ! ( "Warn: unable to set {}={:?}. Can't parse value. Default value will be used." , key, val) ;
295
+ }
296
+ SetOptionByStringError :: ValueValidationError => {
297
+ eprintln ! ( "Warn: unable to set {}={:?}. Invalid value. Default value will be used." , key, val) ;
298
+ }
299
+ }
278
300
return false ;
279
301
}
280
302
}
@@ -292,7 +314,19 @@ impl Options {
292
314
// strip the prefix, and get the lower case string
293
315
if let Some ( rest_of_key) = key. strip_prefix ( PREFIX ) {
294
316
let lowercase: & str = & rest_of_key. to_lowercase ( ) ;
295
- self . set_by_string ( lowercase, & val) ;
317
+ if let Err ( e) = self . set_by_string_inner ( lowercase, & val) {
318
+ match e {
319
+ SetOptionByStringError :: InvalidKey => {
320
+ /* Silently skip unrecognized keys. */
321
+ }
322
+ SetOptionByStringError :: ValueParseError => {
323
+ eprintln ! ( "Warn: unable to set {}={:?}. Can't parse value. Default value will be used." , key, val) ;
324
+ }
325
+ SetOptionByStringError :: ValueValidationError => {
326
+ eprintln ! ( "Warn: unable to set {}={:?}. Invalid value. Default value will be used." , key, val) ;
327
+ }
328
+ }
329
+ }
296
330
}
297
331
}
298
332
}
0 commit comments