@@ -8,6 +8,9 @@ use core::str::FromStr;
8
8
use crate :: prelude:: * ;
9
9
use crate :: { errstr, Error , MAX_RECURSION_DEPTH } ;
10
10
11
+ /// Allowed characters are descriptor strings.
12
+ pub const INPUT_CHARSET : & str = "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\" \\ " ;
13
+
11
14
#[ derive( Debug ) ]
12
15
/// A token of the form `x(...)` or `x`
13
16
pub struct Tree < ' a > {
@@ -166,13 +169,7 @@ impl<'a> Tree<'a> {
166
169
/// Parses a tree from a string
167
170
#[ allow( clippy:: should_implement_trait) ] // Cannot use std::str::FromStr because of lifetimes.
168
171
pub fn from_str ( s : & ' a str ) -> Result < Tree < ' a > , Error > {
169
- // Filter out non-ASCII because we byte-index strings all over the
170
- // place and Rust gets very upset when you splinch a string.
171
- for ch in s. bytes ( ) {
172
- if !ch. is_ascii ( ) {
173
- return Err ( Error :: Unprintable ( ch) ) ;
174
- }
175
- }
172
+ check_valid_chars ( s) ?;
176
173
177
174
let ( top, rem) = Tree :: from_slice ( s) ?;
178
175
if rem. is_empty ( ) {
@@ -183,6 +180,21 @@ impl<'a> Tree<'a> {
183
180
}
184
181
}
185
182
183
+ /// Filter out non-ASCII because we byte-index strings all over the
184
+ /// place and Rust gets very upset when you splinch a string.
185
+ pub fn check_valid_chars ( s : & str ) -> Result < ( ) , Error > {
186
+ for ch in s. bytes ( ) {
187
+ if !ch. is_ascii ( ) {
188
+ return Err ( Error :: Unprintable ( ch) ) ;
189
+ }
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) ) ?;
194
+ }
195
+ Ok ( ( ) )
196
+ }
197
+
186
198
/// Parse a string as a u32, for timelocks or thresholds
187
199
pub fn parse_num ( s : & str ) -> Result < u32 , Error > {
188
200
if s. len ( ) > 1 {
0 commit comments