36
36
//! ```
37
37
38
38
use crate :: Token ;
39
- use alloc:: string:: String ;
39
+ use alloc:: { string:: String , vec :: Vec } ;
40
40
use core:: { fmt, num:: ParseIntError , str:: FromStr } ;
41
41
42
42
/// Represents an abstract index into an array.
@@ -166,7 +166,21 @@ impl FromStr for Index {
166
166
} else if s. starts_with ( '0' ) && s != "0" {
167
167
Err ( ParseIndexError :: LeadingZeros )
168
168
} else {
169
- Ok ( s. parse :: < usize > ( ) . map ( Index :: Num ) ?)
169
+ let idx = s. parse :: < usize > ( ) . map ( Index :: Num ) ?;
170
+ if s. chars ( ) . all ( |c| c. is_ascii_digit ( ) ) {
171
+ Ok ( idx)
172
+ } else {
173
+ // this comes up with the `+` sign which is valid for
174
+ // representing a `usize` but not allowed in RFC 6901 array
175
+ // indices
176
+ let mut invalid: Vec < _ > = s. chars ( ) . filter ( |c| !c. is_ascii_digit ( ) ) . collect ( ) ;
177
+ // remove duplicate characters
178
+ invalid. sort_unstable ( ) ;
179
+ invalid. dedup ( ) ;
180
+ Err ( ParseIndexError :: InvalidCharacters (
181
+ invalid. into_iter ( ) . collect ( ) ,
182
+ ) )
183
+ }
170
184
}
171
185
}
172
186
}
@@ -267,6 +281,8 @@ pub enum ParseIndexError {
267
281
InvalidInteger ( ParseIntError ) ,
268
282
/// The Token contains leading zeros.
269
283
LeadingZeros ,
284
+ /// The Token contains non-digit characters.
285
+ InvalidCharacters ( String ) ,
270
286
}
271
287
272
288
impl From < ParseIntError > for ParseIndexError {
@@ -285,6 +301,11 @@ impl fmt::Display for ParseIndexError {
285
301
f,
286
302
"token contained leading zeros, which are disallowed by RFC 6901"
287
303
) ,
304
+ ParseIndexError :: InvalidCharacters ( chars) => write ! (
305
+ f,
306
+ "token contains non-digit character(s) '{chars}', \
307
+ which are disallowed by RFC 6901",
308
+ ) ,
288
309
}
289
310
}
290
311
}
@@ -294,7 +315,7 @@ impl std::error::Error for ParseIndexError {
294
315
fn source ( & self ) -> Option < & ( dyn std:: error:: Error + ' static ) > {
295
316
match self {
296
317
ParseIndexError :: InvalidInteger ( source) => Some ( source) ,
297
- ParseIndexError :: LeadingZeros => None ,
318
+ ParseIndexError :: LeadingZeros | ParseIndexError :: InvalidCharacters ( _ ) => None ,
298
319
}
299
320
}
300
321
}
@@ -413,6 +434,11 @@ mod tests {
413
434
ParseIndexError :: LeadingZeros . to_string( ) ,
414
435
"token contained leading zeros, which are disallowed by RFC 6901"
415
436
) ;
437
+ assert_eq ! (
438
+ ParseIndexError :: InvalidCharacters ( "+@" . into( ) ) . to_string( ) ,
439
+ "token contains non-digit character(s) '+@', \
440
+ which are disallowed by RFC 6901"
441
+ ) ;
416
442
}
417
443
418
444
#[ test]
0 commit comments