@@ -6,56 +6,79 @@ use crate::ops::Range;
6
6
7
7
const HEX_DIGITS : [ ascii:: Char ; 16 ] = * b"0123456789abcdef" . as_ascii ( ) . unwrap ( ) ;
8
8
9
- /// Escapes a byte into provided buffer; returns length of escaped
10
- /// representation.
11
- pub ( crate ) fn escape_ascii_into ( output : & mut [ ascii:: Char ; 4 ] , byte : u8 ) -> Range < u8 > {
12
- #[ inline]
13
- fn backslash ( a : ascii:: Char ) -> ( [ ascii:: Char ; 4 ] , u8 ) {
14
- ( [ ascii:: Char :: ReverseSolidus , a, ascii:: Char :: Null , ascii:: Char :: Null ] , 2 )
15
- }
9
+ #[ inline]
10
+ const fn backslash < const N : usize > ( a : ascii:: Char ) -> ( [ ascii:: Char ; N ] , Range < u8 > ) {
11
+ const { assert ! ( N >= 2 ) } ;
12
+
13
+ let mut output = [ ascii:: Char :: Null ; N ] ;
14
+
15
+ output[ 0 ] = ascii:: Char :: ReverseSolidus ;
16
+ output[ 1 ] = a;
17
+
18
+ ( output, 0 ..2 )
19
+ }
16
20
17
- let ( data, len) = match byte {
21
+ /// Escapes an ASCII character.
22
+ ///
23
+ /// Returns a buffer and the length of the escaped representation.
24
+ const fn escape_ascii < const N : usize > ( byte : u8 ) -> ( [ ascii:: Char ; N ] , Range < u8 > ) {
25
+ const { assert ! ( N >= 4 ) } ;
26
+
27
+ match byte {
18
28
b'\t' => backslash ( ascii:: Char :: SmallT ) ,
19
29
b'\r' => backslash ( ascii:: Char :: SmallR ) ,
20
30
b'\n' => backslash ( ascii:: Char :: SmallN ) ,
21
31
b'\\' => backslash ( ascii:: Char :: ReverseSolidus ) ,
22
32
b'\'' => backslash ( ascii:: Char :: Apostrophe ) ,
23
33
b'\"' => backslash ( ascii:: Char :: QuotationMark ) ,
24
- _ => {
25
- if let Some ( a) = byte. as_ascii ( )
34
+ byte => {
35
+ let mut output = [ ascii:: Char :: Null ; N ] ;
36
+
37
+ if let Some ( c) = byte. as_ascii ( )
26
38
&& !byte. is_ascii_control ( )
27
39
{
28
- ( [ a, ascii:: Char :: Null , ascii:: Char :: Null , ascii:: Char :: Null ] , 1 )
40
+ output[ 0 ] = c;
41
+ ( output, 0 ..1 )
29
42
} else {
30
- let hi = HEX_DIGITS [ usize:: from ( byte >> 4 ) ] ;
31
- let lo = HEX_DIGITS [ usize:: from ( byte & 0xf ) ] ;
32
- ( [ ascii:: Char :: ReverseSolidus , ascii:: Char :: SmallX , hi, lo] , 4 )
43
+ let hi = HEX_DIGITS [ ( byte >> 4 ) as usize ] ;
44
+ let lo = HEX_DIGITS [ ( byte & 0xf ) as usize ] ;
45
+
46
+ output[ 0 ] = ascii:: Char :: ReverseSolidus ;
47
+ output[ 1 ] = ascii:: Char :: SmallX ;
48
+ output[ 2 ] = hi;
49
+ output[ 3 ] = lo;
50
+
51
+ ( output, 0 ..4 )
33
52
}
34
53
}
35
- } ;
36
- * output = data;
37
- 0 ..len
54
+ }
38
55
}
39
56
40
- /// Escapes a character into provided buffer using `\u{NNNN}` representation.
41
- pub ( crate ) fn escape_unicode_into ( output : & mut [ ascii:: Char ; 10 ] , ch : char ) -> Range < u8 > {
57
+ /// Escapes a character `\u{NNNN}` representation.
58
+ ///
59
+ /// Returns a buffer and the length of the escaped representation.
60
+ const fn escape_unicode < const N : usize > ( c : char ) -> ( [ ascii:: Char ; N ] , Range < u8 > ) {
61
+ const { assert ! ( N >= 10 && N < u8 :: MAX as usize ) } ;
62
+
63
+ let c = u32:: from ( c) ;
64
+
65
+ // OR-ing `1` ensures that for `c == 0` the code computes that
66
+ // one digit should be printed.
67
+ let start = ( c | 1 ) . leading_zeros ( ) as usize / 4 - 2 ;
68
+
69
+ let mut output = [ ascii:: Char :: Null ; N ] ;
70
+ output[ 3 ] = HEX_DIGITS [ ( ( c >> 20 ) & 15 ) as usize ] ;
71
+ output[ 4 ] = HEX_DIGITS [ ( ( c >> 16 ) & 15 ) as usize ] ;
72
+ output[ 5 ] = HEX_DIGITS [ ( ( c >> 12 ) & 15 ) as usize ] ;
73
+ output[ 6 ] = HEX_DIGITS [ ( ( c >> 8 ) & 15 ) as usize ] ;
74
+ output[ 7 ] = HEX_DIGITS [ ( ( c >> 4 ) & 15 ) as usize ] ;
75
+ output[ 8 ] = HEX_DIGITS [ ( ( c >> 0 ) & 15 ) as usize ] ;
42
76
output[ 9 ] = ascii:: Char :: RightCurlyBracket ;
77
+ output[ start + 0 ] = ascii:: Char :: ReverseSolidus ;
78
+ output[ start + 1 ] = ascii:: Char :: SmallU ;
79
+ output[ start + 2 ] = ascii:: Char :: LeftCurlyBracket ;
43
80
44
- let ch = ch as u32 ;
45
- output[ 3 ] = HEX_DIGITS [ ( ( ch >> 20 ) & 15 ) as usize ] ;
46
- output[ 4 ] = HEX_DIGITS [ ( ( ch >> 16 ) & 15 ) as usize ] ;
47
- output[ 5 ] = HEX_DIGITS [ ( ( ch >> 12 ) & 15 ) as usize ] ;
48
- output[ 6 ] = HEX_DIGITS [ ( ( ch >> 8 ) & 15 ) as usize ] ;
49
- output[ 7 ] = HEX_DIGITS [ ( ( ch >> 4 ) & 15 ) as usize ] ;
50
- output[ 8 ] = HEX_DIGITS [ ( ( ch >> 0 ) & 15 ) as usize ] ;
51
-
52
- // or-ing 1 ensures that for ch==0 the code computes that one digit should
53
- // be printed.
54
- let start = ( ch | 1 ) . leading_zeros ( ) as usize / 4 - 2 ;
55
- const UNICODE_ESCAPE_PREFIX : & [ ascii:: Char ; 3 ] = b"\\ u{" . as_ascii ( ) . unwrap ( ) ;
56
- output[ start..] [ ..3 ] . copy_from_slice ( UNICODE_ESCAPE_PREFIX ) ;
57
-
58
- ( start as u8 ) ..10
81
+ ( output, ( start as u8 ) ..( N as u8 ) )
59
82
}
60
83
61
84
/// An iterator over an fixed-size array.
@@ -65,45 +88,63 @@ pub(crate) fn escape_unicode_into(output: &mut [ascii::Char; 10], ch: char) -> R
65
88
#[ derive( Clone , Debug ) ]
66
89
pub ( crate ) struct EscapeIterInner < const N : usize > {
67
90
// The element type ensures this is always ASCII, and thus also valid UTF-8.
68
- pub ( crate ) data : [ ascii:: Char ; N ] ,
91
+ data : [ ascii:: Char ; N ] ,
69
92
70
- // Invariant: alive.start <= alive.end <= N.
71
- pub ( crate ) alive : Range < u8 > ,
93
+ // Invariant: ` alive.start <= alive.end <= N`
94
+ alive : Range < u8 > ,
72
95
}
73
96
74
97
impl < const N : usize > EscapeIterInner < N > {
75
- pub fn new ( data : [ ascii:: Char ; N ] , alive : Range < u8 > ) -> Self {
76
- const { assert ! ( N < 256 ) } ;
77
- debug_assert ! ( alive. start <= alive. end && usize :: from( alive. end) <= N , "{alive:?}" ) ;
78
- Self { data, alive }
98
+ pub const fn backslash ( c : ascii:: Char ) -> Self {
99
+ let ( data, range) = backslash ( c) ;
100
+ Self { data, alive : range }
101
+ }
102
+
103
+ pub const fn ascii ( c : u8 ) -> Self {
104
+ let ( data, range) = escape_ascii ( c) ;
105
+ Self { data, alive : range }
79
106
}
80
107
81
- pub fn from_array < const M : usize > ( array : [ ascii:: Char ; M ] ) -> Self {
82
- const { assert ! ( M <= N ) } ;
108
+ pub const fn unicode ( c : char ) -> Self {
109
+ let ( data, range) = escape_unicode ( c) ;
110
+ Self { data, alive : range }
111
+ }
83
112
84
- let mut data = [ ascii :: Char :: Null ; N ] ;
85
- data [ .. M ] . copy_from_slice ( & array ) ;
86
- Self :: new ( data , 0 ..M as u8 )
113
+ # [ inline ]
114
+ pub const fn empty ( ) -> Self {
115
+ Self { data : [ ascii :: Char :: Null ; N ] , alive : 0 ..0 }
87
116
}
88
117
118
+ #[ inline]
89
119
pub fn as_ascii ( & self ) -> & [ ascii:: Char ] {
90
- & self . data [ usize:: from ( self . alive . start ) ..usize:: from ( self . alive . end ) ]
120
+ // SAFETY: `self.alive` is guaranteed to be a valid range for indexing `self.data`.
121
+ unsafe {
122
+ self . data . get_unchecked ( usize:: from ( self . alive . start ) ..usize:: from ( self . alive . end ) )
123
+ }
91
124
}
92
125
126
+ #[ inline]
93
127
pub fn as_str ( & self ) -> & str {
94
128
self . as_ascii ( ) . as_str ( )
95
129
}
96
130
131
+ #[ inline]
97
132
pub fn len ( & self ) -> usize {
98
133
usize:: from ( self . alive . end - self . alive . start )
99
134
}
100
135
101
136
pub fn next ( & mut self ) -> Option < u8 > {
102
- self . alive . next ( ) . map ( |i| self . data [ usize:: from ( i) ] . to_u8 ( ) )
137
+ let i = self . alive . next ( ) ?;
138
+
139
+ // SAFETY: `i` is guaranteed to be a valid index for `self.data`.
140
+ unsafe { Some ( self . data . get_unchecked ( usize:: from ( i) ) . to_u8 ( ) ) }
103
141
}
104
142
105
143
pub fn next_back ( & mut self ) -> Option < u8 > {
106
- self . alive . next_back ( ) . map ( |i| self . data [ usize:: from ( i) ] . to_u8 ( ) )
144
+ let i = self . alive . next_back ( ) ?;
145
+
146
+ // SAFETY: `i` is guaranteed to be a valid index for `self.data`.
147
+ unsafe { Some ( self . data . get_unchecked ( usize:: from ( i) ) . to_u8 ( ) ) }
107
148
}
108
149
109
150
pub fn advance_by ( & mut self , n : usize ) -> Result < ( ) , NonZero < usize > > {
0 commit comments