@@ -11,6 +11,26 @@ use crate::{errstr, Error, MAX_RECURSION_DEPTH};
11
11
/// Allowed characters are descriptor strings.
12
12
pub const INPUT_CHARSET : & str = "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\" \\ " ;
13
13
14
+ /// Map of valid characters in descriptor strings.
15
+ #[ rustfmt:: skip]
16
+ pub const VALID_CHARS : [ Option < u8 > ; 128 ] = [
17
+ None , None , None , None , None , None , None , None , None , None , None , None , None ,
18
+ None , None , None , None , None , None , None , None , None , None , None , None , None ,
19
+ None , None , None , None , None , None , Some ( 94 ) , Some ( 59 ) , Some ( 92 ) , Some ( 91 ) ,
20
+ Some ( 28 ) , Some ( 29 ) , Some ( 50 ) , Some ( 15 ) , Some ( 10 ) , Some ( 11 ) , Some ( 17 ) , Some ( 51 ) ,
21
+ Some ( 14 ) , Some ( 52 ) , Some ( 53 ) , Some ( 16 ) , Some ( 0 ) , Some ( 1 ) , Some ( 2 ) , Some ( 3 ) ,
22
+ Some ( 4 ) , Some ( 5 ) , Some ( 6 ) , Some ( 7 ) , Some ( 8 ) , Some ( 9 ) , Some ( 27 ) , Some ( 54 ) ,
23
+ Some ( 55 ) , Some ( 56 ) , Some ( 57 ) , Some ( 58 ) , Some ( 26 ) , Some ( 82 ) , Some ( 83 ) ,
24
+ Some ( 84 ) , Some ( 85 ) , Some ( 86 ) , Some ( 87 ) , Some ( 88 ) , Some ( 89 ) , Some ( 32 ) , Some ( 33 ) ,
25
+ Some ( 34 ) , Some ( 35 ) , Some ( 36 ) , Some ( 37 ) , Some ( 38 ) , Some ( 39 ) , Some ( 40 ) , Some ( 41 ) ,
26
+ Some ( 42 ) , Some ( 43 ) , Some ( 44 ) , Some ( 45 ) , Some ( 46 ) , Some ( 47 ) , Some ( 48 ) , Some ( 49 ) ,
27
+ Some ( 12 ) , Some ( 93 ) , Some ( 13 ) , Some ( 60 ) , Some ( 61 ) , Some ( 90 ) , Some ( 18 ) , Some ( 19 ) ,
28
+ Some ( 20 ) , Some ( 21 ) , Some ( 22 ) , Some ( 23 ) , Some ( 24 ) , Some ( 25 ) , Some ( 64 ) , Some ( 65 ) ,
29
+ Some ( 66 ) , Some ( 67 ) , Some ( 68 ) , Some ( 69 ) , Some ( 70 ) , Some ( 71 ) , Some ( 72 ) , Some ( 73 ) ,
30
+ Some ( 74 ) , Some ( 75 ) , Some ( 76 ) , Some ( 77 ) , Some ( 78 ) , Some ( 79 ) , Some ( 80 ) , Some ( 81 ) ,
31
+ Some ( 30 ) , Some ( 62 ) , Some ( 31 ) , Some ( 63 ) , None ,
32
+ ] ;
33
+
14
34
#[ derive( Debug ) ]
15
35
/// A token of the form `x(...)` or `x`
16
36
pub struct Tree < ' a > {
@@ -187,10 +207,12 @@ pub fn check_valid_chars(s: &str) -> Result<(), Error> {
187
207
if !ch. is_ascii ( ) {
188
208
return Err ( Error :: Unprintable ( ch) ) ;
189
209
}
190
- // TODO: Avoid linear search overhead by using OnceCell to cache this in a BTreeMap.
191
- INPUT_CHARSET
192
- . find ( char:: from ( ch) )
193
- . ok_or_else ( || Error :: Unprintable ( ch) ) ?;
210
+ // Index bounds: We know that ch is ASCII, so it is <= 127.
211
+ if VALID_CHARS [ ch as usize ] . is_none ( ) {
212
+ return Err ( Error :: Unexpected (
213
+ "Only characters in INPUT_CHARSET are allowed" . to_string ( ) ,
214
+ ) ) ;
215
+ }
194
216
}
195
217
Ok ( ( ) )
196
218
}
@@ -265,4 +287,13 @@ mod tests {
265
287
assert ! ( parse_num( "+6" ) . is_err( ) ) ;
266
288
assert ! ( parse_num( "-6" ) . is_err( ) ) ;
267
289
}
290
+
291
+ #[ test]
292
+ fn test_valid_char_map ( ) {
293
+ let mut valid_chars = [ None ; 128 ] ;
294
+ for ( i, ch) in super :: INPUT_CHARSET . chars ( ) . enumerate ( ) {
295
+ valid_chars[ ch as usize ] = Some ( i as u8 ) ;
296
+ }
297
+ assert_eq ! ( valid_chars, super :: VALID_CHARS ) ;
298
+ }
268
299
}
0 commit comments