@@ -11,6 +11,26 @@ use crate::{errstr, Error, MAX_RECURSION_DEPTH};
1111/// Allowed characters are descriptor strings.
1212pub const INPUT_CHARSET : & str = "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\" \\ " ;
1313
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+
1434#[ derive( Debug ) ]
1535/// A token of the form `x(...)` or `x`
1636pub struct Tree < ' a > {
@@ -187,10 +207,12 @@ pub fn check_valid_chars(s: &str) -> Result<(), Error> {
187207 if !ch. is_ascii ( ) {
188208 return Err ( Error :: Unprintable ( ch) ) ;
189209 }
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+ }
194216 }
195217 Ok ( ( ) )
196218}
@@ -265,4 +287,13 @@ mod tests {
265287 assert ! ( parse_num( "+6" ) . is_err( ) ) ;
266288 assert ! ( parse_num( "-6" ) . is_err( ) ) ;
267289 }
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+ }
268299}
0 commit comments