|
21 | 21 | use crate::error::GwsError; |
22 | 22 | use std::path::{Path, PathBuf}; |
23 | 23 |
|
24 | | -/// Dangerous Unicode characters not caught by ASCII-range or `is_control()` checks: |
25 | | -/// zero-width chars, bidi overrides, Unicode line/paragraph separators. |
26 | | -const REJECTED_UNICODE_CHARS: &[char] = &[ |
27 | | - '\u{200B}', '\u{200C}', '\u{200D}', '\u{FEFF}', // zero-width |
28 | | - '\u{202A}', '\u{202B}', '\u{202C}', '\u{202D}', '\u{202E}', // bidi |
29 | | - '\u{2028}', '\u{2029}', // line/para separators |
30 | | - '\u{2066}', '\u{2067}', '\u{2068}', '\u{2069}', // directional isolates |
31 | | -]; |
| 24 | +/// Returns `true` for Unicode characters that are dangerous but not caught by |
| 25 | +/// ASCII-range byte checks or `char::is_control()`: zero-width chars, bidi |
| 26 | +/// overrides, Unicode line/paragraph separators, and directional isolates. |
| 27 | +/// |
| 28 | +/// Using `matches!` with char ranges gives O(1) per character instead of the |
| 29 | +/// O(M) linear scan that a slice `.contains()` would require. |
| 30 | +fn is_rejected_unicode(c: char) -> bool { |
| 31 | + matches!(c, |
| 32 | + // zero-width: ZWSP, ZWNJ, ZWJ, BOM/ZWNBSP |
| 33 | + '\u{200B}'..='\u{200D}' | '\u{FEFF}' | |
| 34 | + // bidi: LRE, RLE, PDF, LRO, RLO |
| 35 | + '\u{202A}'..='\u{202E}' | |
| 36 | + // line / paragraph separators |
| 37 | + '\u{2028}'..='\u{2029}' | |
| 38 | + // directional isolates: LRI, RLI, FSI, PDI |
| 39 | + '\u{2066}'..='\u{2069}' |
| 40 | + ) |
| 41 | +} |
32 | 42 |
|
33 | 43 | /// Validates that `dir` is a safe output directory. |
34 | 44 | /// |
@@ -136,7 +146,7 @@ fn reject_control_chars(value: &str, flag_name: &str) -> Result<(), GwsError> { |
136 | 146 | "{flag_name} contains invalid control characters" |
137 | 147 | ))); |
138 | 148 | } |
139 | | - if value.chars().any(|c| REJECTED_UNICODE_CHARS.contains(&c)) { |
| 149 | + if value.chars().any(is_rejected_unicode) { |
140 | 150 | return Err(GwsError::Validation(format!( |
141 | 151 | "{flag_name} contains invalid Unicode characters" |
142 | 152 | ))); |
@@ -221,7 +231,7 @@ pub fn validate_resource_name(s: &str) -> Result<&str, GwsError> { |
221 | 231 | "Resource name contains invalid characters: {s}" |
222 | 232 | ))); |
223 | 233 | } |
224 | | - if s.chars().any(|c| REJECTED_UNICODE_CHARS.contains(&c)) { |
| 234 | + if s.chars().any(is_rejected_unicode) { |
225 | 235 | return Err(GwsError::Validation(format!( |
226 | 236 | "Resource name contains invalid Unicode characters: {s}" |
227 | 237 | ))); |
|
0 commit comments