@@ -18,71 +18,110 @@ const fn backslash<const N: usize>(a: ascii::Char) -> ([ascii::Char; N], Range<u
18
18
( output, 0 ..2 )
19
19
}
20
20
21
+ #[ inline]
22
+ const fn hex_escape < const N : usize > ( byte : u8 ) -> ( [ ascii:: Char ; N ] , Range < u8 > ) {
23
+ const { assert ! ( N >= 4 ) } ;
24
+
25
+ let mut output = [ ascii:: Char :: Null ; N ] ;
26
+
27
+ let hi = HEX_DIGITS [ ( byte >> 4 ) as usize ] ;
28
+ let lo = HEX_DIGITS [ ( byte & 0xf ) as usize ] ;
29
+
30
+ output[ 0 ] = ascii:: Char :: ReverseSolidus ;
31
+ output[ 1 ] = ascii:: Char :: SmallX ;
32
+ output[ 2 ] = hi;
33
+ output[ 3 ] = lo;
34
+
35
+ ( output, 0 ..4 )
36
+ }
37
+
38
+ #[ inline]
39
+ const fn verbatim < const N : usize > ( a : ascii:: Char ) -> ( [ ascii:: Char ; N ] , Range < u8 > ) {
40
+ const { assert ! ( N >= 1 ) } ;
41
+
42
+ let mut output = [ ascii:: Char :: Null ; N ] ;
43
+
44
+ output[ 0 ] = a;
45
+
46
+ ( output, 0 ..1 )
47
+ }
48
+
21
49
/// Escapes an ASCII character.
22
50
///
23
51
/// Returns a buffer and the length of the escaped representation.
24
52
const fn escape_ascii < const N : usize > ( byte : u8 ) -> ( [ ascii:: Char ; N ] , Range < u8 > ) {
25
53
const { assert ! ( N >= 4 ) } ;
26
54
27
- /// Lookup table helps us determine how to display character.
28
- ///
29
- /// Since ASCII characters will always be 7 bits, we can exploit this to store the 8th bit to
30
- /// indicate whether the result is escaped or unescaped.
31
- ///
32
- /// We additionally use 0x80 (escaped NUL character) to indicate hex-escaped bytes, since
33
- /// escaped NUL will not occur.
34
- const LOOKUP : [ u8 ; 256 ] = {
35
- let mut arr = [ 0 ; 256 ] ;
36
- let mut idx = 0 ;
37
- loop {
38
- arr[ idx as usize ] = match idx {
39
- // use 8th bit to indicate escaped
40
- b'\t' => 0x80 | b't' ,
41
- b'\r' => 0x80 | b'r' ,
42
- b'\n' => 0x80 | b'n' ,
43
- b'\\' => 0x80 | b'\\' ,
44
- b'\'' => 0x80 | b'\'' ,
45
- b'"' => 0x80 | b'"' ,
46
-
47
- // use NUL to indicate hex-escaped
48
- 0x00 ..=0x1F | 0x7F ..=0xFF => 0x80 | b'\0' ,
49
-
50
- _ => idx,
51
- } ;
52
- if idx == 255 {
53
- break ;
54
- }
55
- idx += 1 ;
55
+ #[ cfg( feature = "optimize_for_size" ) ]
56
+ {
57
+ match byte {
58
+ b'\t' => backslash ( ascii:: Char :: SmallT ) ,
59
+ b'\r' => backslash ( ascii:: Char :: SmallR ) ,
60
+ b'\n' => backslash ( ascii:: Char :: SmallN ) ,
61
+ b'\\' => backslash ( ascii:: Char :: ReverseSolidus ) ,
62
+ b'\'' => backslash ( ascii:: Char :: Apostrophe ) ,
63
+ b'\"' => backslash ( ascii:: Char :: QuotationMark ) ,
64
+ 0x00 ..=0x1F => hex_escape ( byte) ,
65
+ _ => match ascii:: Char :: from_u8 ( byte) {
66
+ Some ( a) => verbatim ( a) ,
67
+ None => hex_escape ( byte) ,
68
+ } ,
56
69
}
57
- arr
58
- } ;
70
+ }
59
71
60
- let mut output = [ ascii:: Char :: Null ; N ] ;
61
- let lookup = LOOKUP [ byte as usize ] ;
62
-
63
- // 8th bit indicates escape
64
- if lookup & 0x80 != 0 {
65
- output[ 0 ] = ascii:: Char :: ReverseSolidus ;
66
-
67
- // SAFETY: We explicitly mask out the eighth bit.
68
- let lookup = unsafe { ascii:: Char :: from_u8_unchecked ( lookup & 0x7F ) } ;
69
-
70
- // NUL indicates hex-escaped
71
- if matches ! ( lookup, ascii:: Char :: Null ) {
72
- let hi = HEX_DIGITS [ ( byte >> 4 ) as usize ] ;
73
- let lo = HEX_DIGITS [ ( byte & 0xF ) as usize ] ;
74
- output[ 1 ] = ascii:: Char :: SmallX ;
75
- output[ 2 ] = hi;
76
- output[ 3 ] = lo;
77
- ( output, 0 ..4 )
72
+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
73
+ {
74
+ /// Lookup table helps us determine how to display character.
75
+ ///
76
+ /// Since ASCII characters will always be 7 bits, we can exploit this to store the 8th bit to
77
+ /// indicate whether the result is escaped or unescaped.
78
+ ///
79
+ /// We additionally use 0x80 (escaped NUL character) to indicate hex-escaped bytes, since
80
+ /// escaped NUL will not occur.
81
+ const LOOKUP : [ u8 ; 256 ] = {
82
+ let mut arr = [ 0 ; 256 ] ;
83
+ let mut idx = 0 ;
84
+ loop {
85
+ arr[ idx as usize ] = match idx {
86
+ // use 8th bit to indicate escaped
87
+ b'\t' => 0x80 | b't' ,
88
+ b'\r' => 0x80 | b'r' ,
89
+ b'\n' => 0x80 | b'n' ,
90
+ b'\\' => 0x80 | b'\\' ,
91
+ b'\'' => 0x80 | b'\'' ,
92
+ b'"' => 0x80 | b'"' ,
93
+
94
+ // use NUL to indicate hex-escaped
95
+ 0x00 ..=0x1F | 0x7F ..=0xFF => 0x80 | b'\0' ,
96
+
97
+ _ => idx,
98
+ } ;
99
+ if idx == 255 {
100
+ break ;
101
+ }
102
+ idx += 1 ;
103
+ }
104
+ arr
105
+ } ;
106
+
107
+ let lookup = LOOKUP [ byte as usize ] ;
108
+
109
+ // 8th bit indicates escape
110
+ let lookup_escaped = lookup & 0x80 != 0 ;
111
+
112
+ // SAFETY: We explicitly mask out the eighth bit to get a 7-bit ASCII character.
113
+ let lookup_ascii = unsafe { ascii:: Char :: from_u8_unchecked ( lookup & 0x7F ) } ;
114
+
115
+ if lookup_escaped {
116
+ // NUL indicates hex-escaped
117
+ if matches ! ( lookup_ascii, ascii:: Char :: Null ) {
118
+ hex_escape ( byte)
119
+ } else {
120
+ backslash ( lookup_ascii)
121
+ }
78
122
} else {
79
- output[ 1 ] = lookup;
80
- ( output, 0 ..2 )
123
+ verbatim ( lookup_ascii)
81
124
}
82
- } else {
83
- // SAFETY: We explicitly checked for the eighth bit.
84
- output[ 0 ] = unsafe { ascii:: Char :: from_u8_unchecked ( lookup) } ;
85
- ( output, 0 ..1 )
86
125
}
87
126
}
88
127
0 commit comments