@@ -11,15 +11,6 @@ pub fn bytes(input: TokenStream2) -> TokenStream2 {
1111 Err ( e) => return e. to_compile_error ( ) ,
1212 } ;
1313
14- // Convert the integer literal into a base10 string, and into a slice of
15- // bytes, via a big integer. The conversion should never fail because
16- // syn::LitInt already validated the integer, unless the value is negative.
17- // Any leading zeroes are discarded.
18- let int = match BigUint :: from_str ( lit. base10_digits ( ) ) {
19- Ok ( int) => int,
20- Err ( _) => return Error :: new ( lit. span ( ) , "negative values unsupported" ) . to_compile_error ( ) ,
21- } ;
22-
2314 // Get the raw integer literal as it appears in the token stream.
2415 let raw = lit. to_string ( ) ;
2516
@@ -28,37 +19,31 @@ pub fn bytes(input: TokenStream2) -> TokenStream2 {
2819
2920 // Remove any leading prefix that indicates the base, and use the base to
3021 // determine how many bits per leading zero needs to be prefilled into the
31- // bytes generated. If bits_per_digit is None, leading zero digits are
32- // unsupported.
33- let ( form, bits_per_zero_digit, remainder) = match normalized. as_bytes ( ) {
34- [ b'0' , b'x' , r @ ..] => ( "hex" , Some ( 4 ) , r) ,
35- [ b'0' , b'b' , r @ ..] => ( "binary" , Some ( 1 ) , r) ,
36- [ b'0' , b'o' , r @ ..] => ( "octal" , None , r) ,
37- [ r @ ..] => ( "decimal" , None , r) ,
22+ // bytes generated.
23+ let ( bits_per_zero_digit, remainder) = match normalized. as_bytes ( ) {
24+ [ b'0' , b'x' , r @ ..] => ( 4 , r) ,
25+ [ b'0' , b'b' , r @ ..] => ( 1 , r) ,
26+ _ => {
27+ return Error :: new (
28+ lit. span ( ) ,
29+ "only positive hex (0x) and binary (0b) integer literals are supported" ,
30+ )
31+ . to_compile_error ( ) ;
32+ }
3833 } ;
3934
35+ // Convert the integer literal into a base10 string, and into a slice of
36+ // bytes, via a big integer. The conversion should never fail because
37+ // syn::LitInt already validated the integer, and the form check above
38+ // ensures only non-negative hex/binary literals reach here.
39+ let int = BigUint :: from_str ( lit. base10_digits ( ) ) . expect ( "valid hex or binary literal" ) ;
40+
4041 // Count the leading zero bits by counting the number of leading zeros and
4142 // multiplying by the bits per digit.
4243 let leading_zero_count = remainder. iter ( ) . take_while ( |d| * * d == b'0' ) . count ( ) ;
43- let leading_zero_bits = if let Some ( bits_per_digit) = bits_per_zero_digit {
44- leading_zero_count
45- . checked_mul ( bits_per_digit)
46- . expect ( "overflow" )
47- } else if leading_zero_count > 0 {
48- // If there are leading zeros without a bits per digit error, since a
49- // caller may expect the zeros to be preserved, and so it is better for
50- // us to error. They can proceed by removing the zeros.
51- return Error :: new (
52- lit. span ( ) ,
53- format ! (
54- "leading zeros are not preserved or supported on integer literals in {} form" ,
55- form,
56- ) ,
57- )
58- . to_compile_error ( ) ;
59- } else {
60- 0
61- } ;
44+ let leading_zero_bits = leading_zero_count
45+ . checked_mul ( bits_per_zero_digit)
46+ . expect ( "overflow" ) ;
6247
6348 // Create the final byte slice, which has length of the leading zero bytes,
6449 // followed by the big integer bytes.
@@ -84,9 +69,12 @@ mod test {
8469 #[ test]
8570 fn neg ( ) {
8671 let tokens = bytes ( quote ! { -0x1 } ) ;
87- let expect = Error :: new ( Span :: call_site ( ) , "negative values unsupported" )
88- . to_compile_error ( )
89- . to_string ( ) ;
72+ let expect = Error :: new (
73+ Span :: call_site ( ) ,
74+ "only positive hex (0x) and binary (0b) integer literals are supported" ,
75+ )
76+ . to_compile_error ( )
77+ . to_string ( ) ;
9078 assert_eq ! ( tokens. to_string( ) , expect) ;
9179 }
9280
@@ -114,21 +102,38 @@ mod test {
114102 }
115103
116104 #[ test]
117- fn base10 ( ) {
118- let tokens = bytes ( quote ! { 340_282_366_920_938_463_463_374_607_431_768_211_455u128 } ) ;
119- let parsed = syn:: parse2 :: < ExprArray > ( tokens) . unwrap ( ) ;
120- let expect = syn:: parse_quote!( [
121- 255u8 , 255u8 , 255u8 , 255u8 , 255u8 , 255u8 , 255u8 , 255u8 , 255u8 , 255u8 , 255u8 , 255u8 ,
122- 255u8 , 255u8 , 255u8 , 255u8
123- ] ) ;
124- assert_eq ! ( parsed, expect) ;
125-
126- let tokens = bytes ( quote ! { 340_282_366_920_938_463_463_374_607_431_768_211_456 } ) ;
127- let parsed = syn:: parse2 :: < ExprArray > ( tokens) . unwrap ( ) ;
128- let expect = syn:: parse_quote!( [
129- 1u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8
130- ] ) ;
131- assert_eq ! ( parsed, expect) ;
105+ fn decimal_and_octal_unsupported ( ) {
106+ let table: & [ _ ] = & [
107+ // Decimal.
108+ quote ! ( 0 ) ,
109+ quote ! ( 1 ) ,
110+ quote ! ( 9 ) ,
111+ quote ! ( 255 ) ,
112+ quote ! ( 256 ) ,
113+ quote ! ( 0255 ) ,
114+ quote ! ( 00255 ) ,
115+ quote ! ( 00 ) ,
116+ quote ! ( 340_282_366_920_938_463_463_374_607_431_768_211_455u128 ) ,
117+ quote ! ( 340_282_366_920_938_463_463_374_607_431_768_211_456 ) ,
118+ // Octal.
119+ quote ! ( 0o0 ) ,
120+ quote ! ( 0o1 ) ,
121+ quote ! ( 0o377 ) ,
122+ quote ! ( 0o0377 ) ,
123+ quote ! ( 0o00377 ) ,
124+ quote ! ( 0o00 ) ,
125+ quote ! ( 0o400 ) ,
126+ ] ;
127+ let expect = Error :: new (
128+ Span :: call_site ( ) ,
129+ "only positive hex (0x) and binary (0b) integer literals are supported" ,
130+ )
131+ . to_compile_error ( )
132+ . to_string ( ) ;
133+ for ( i, input) in table. iter ( ) . enumerate ( ) {
134+ let tokens = bytes ( input. clone ( ) ) ;
135+ assert_eq ! ( tokens. to_string( ) , expect, "table entry: {}" , i) ;
136+ }
132137 }
133138
134139 #[ test]
@@ -172,35 +177,108 @@ mod test {
172177 }
173178
174179 #[ test]
175- fn leading_zeros_prohibited ( ) {
176- let table: & [ ( _ , Result < ExprArray , Error > ) ] = & [
177- // Base 8.
178- ( quote ! ( 0o377 ) , Ok ( parse_quote ! ( [ 255u8 ] ) ) ) ,
179- ( quote ! ( 0o0377 ) , Err ( Error :: new ( Span :: call_site ( ) , "leading zeros are not preserved or supported on integer literals in octal form" ) ) ) ,
180- ( quote ! ( 0o00377 ) , Err ( Error :: new ( Span :: call_site ( ) , "leading zeros are not preserved or supported on integer literals in octal form" ) ) ) ,
181- ( quote ! ( 0o400 ) , Ok ( parse_quote ! ( [ 1u8 , 0u8 ] ) ) ) ,
182- // Base 10.
183- ( quote ! ( 255 ) , Ok ( parse_quote ! ( [ 255u8 ] ) ) ) ,
184- ( quote ! ( 0255 ) , Err ( Error :: new ( Span :: call_site ( ) , "leading zeros are not preserved or supported on integer literals in decimal form" ) ) ) ,
185- ( quote ! ( 00255 ) , Err ( Error :: new ( Span :: call_site ( ) , "leading zeros are not preserved or supported on integer literals in decimal form" ) ) ) ,
186- ( quote ! ( 256 ) , Ok ( parse_quote ! ( [ 1u8 , 0u8 ] ) ) ) ,
180+ fn zero ( ) {
181+ let table: & [ ( _ , ExprArray ) ] = & [
182+ ( quote ! ( 0x0 ) , parse_quote ! ( [ 0u8 ] ) ) ,
183+ ( quote ! ( 0x00 ) , parse_quote ! ( [ 0u8 ] ) ) ,
184+ ( quote ! ( 0b0 ) , parse_quote ! ( [ 0u8 ] ) ) ,
185+ ( quote ! ( 0b00000000 ) , parse_quote ! ( [ 0u8 ] ) ) ,
187186 ] ;
188- for ( i, t) in table. iter ( ) . enumerate ( ) {
189- let tokens = bytes ( t. 0 . clone ( ) ) ;
190- match t. 1 . clone ( ) {
191- Ok ( expect) => {
192- let parsed = syn:: parse2 :: < ExprArray > ( tokens) ;
193- assert_eq ! ( parsed. unwrap( ) , expect, "table entry: {}" , i) ;
194- }
195- Err ( e) => {
196- assert_eq ! (
197- tokens. to_string( ) ,
198- e. to_compile_error( ) . to_string( ) ,
199- "table entry: {}" ,
200- i
201- ) ;
202- }
203- } ;
187+ for ( i, t) in table. iter ( ) . cloned ( ) . enumerate ( ) {
188+ let tokens = bytes ( t. 0 ) ;
189+ let parsed = syn:: parse2 :: < ExprArray > ( tokens) . unwrap ( ) ;
190+ let expect = t. 1 ;
191+ assert_eq ! ( parsed, expect, "table entry: {}" , i) ;
204192 }
205193 }
194+
195+ #[ test]
196+ fn byte_boundaries ( ) {
197+ let table: & [ ( _ , ExprArray ) ] = & [
198+ // u8 max
199+ ( quote ! ( 0xff ) , parse_quote ! ( [ 255u8 ] ) ) ,
200+ ( quote ! ( 0b11111111 ) , parse_quote ! ( [ 255u8 ] ) ) ,
201+ // u8 max + 1
202+ ( quote ! ( 0x100 ) , parse_quote ! ( [ 1u8 , 0u8 ] ) ) ,
203+ ( quote ! ( 0b100000000 ) , parse_quote ! ( [ 1u8 , 0u8 ] ) ) ,
204+ // u16 max
205+ ( quote ! ( 0xffff ) , parse_quote ! ( [ 255u8 , 255u8 ] ) ) ,
206+ // u16 max + 1
207+ ( quote ! ( 0x10000 ) , parse_quote ! ( [ 1u8 , 0u8 , 0u8 ] ) ) ,
208+ // u32 max
209+ (
210+ quote ! ( 0xffffffff ) ,
211+ parse_quote ! ( [ 255u8 , 255u8 , 255u8 , 255u8 ] ) ,
212+ ) ,
213+ // u32 max + 1
214+ ( quote ! ( 0x100000000 ) , parse_quote ! ( [ 1u8 , 0u8 , 0u8 , 0u8 , 0u8 ] ) ) ,
215+ // u64 max
216+ (
217+ quote ! ( 0xffffffffffffffff ) ,
218+ parse_quote ! ( [ 255u8 , 255u8 , 255u8 , 255u8 , 255u8 , 255u8 , 255u8 , 255u8 ] ) ,
219+ ) ,
220+ // u64 max + 1
221+ (
222+ quote ! ( 0x10000000000000000 ) ,
223+ parse_quote ! ( [ 1u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 ] ) ,
224+ ) ,
225+ // u128 max
226+ (
227+ quote ! ( 0xffffffffffffffffffffffffffffffff ) ,
228+ parse_quote ! ( [
229+ 255u8 , 255u8 , 255u8 , 255u8 , 255u8 , 255u8 , 255u8 , 255u8 , 255u8 , 255u8 , 255u8 ,
230+ 255u8 , 255u8 , 255u8 , 255u8 , 255u8
231+ ] ) ,
232+ ) ,
233+ // u128 max + 1
234+ (
235+ quote ! ( 0x100000000000000000000000000000000 ) ,
236+ parse_quote ! ( [
237+ 1u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 ,
238+ 0u8
239+ ] ) ,
240+ ) ,
241+ ] ;
242+ for ( i, t) in table. iter ( ) . cloned ( ) . enumerate ( ) {
243+ let tokens = bytes ( t. 0 ) ;
244+ let parsed = syn:: parse2 :: < ExprArray > ( tokens) . unwrap ( ) ;
245+ let expect = t. 1 ;
246+ assert_eq ! ( parsed, expect, "table entry: {}" , i) ;
247+ }
248+ }
249+
250+ #[ test]
251+ fn one ( ) {
252+ let table: & [ ( _ , ExprArray ) ] = & [
253+ ( quote ! ( 0x1 ) , parse_quote ! ( [ 1u8 ] ) ) ,
254+ ( quote ! ( 0b1 ) , parse_quote ! ( [ 1u8 ] ) ) ,
255+ ] ;
256+ for ( i, t) in table. iter ( ) . cloned ( ) . enumerate ( ) {
257+ let tokens = bytes ( t. 0 ) ;
258+ let parsed = syn:: parse2 :: < ExprArray > ( tokens) . unwrap ( ) ;
259+ let expect = t. 1 ;
260+ assert_eq ! ( parsed, expect, "table entry: {}" , i) ;
261+ }
262+ }
263+
264+ #[ test]
265+ fn empty_input ( ) {
266+ let tokens = bytes ( quote ! { } ) ;
267+ let expect = Error :: new (
268+ Span :: call_site ( ) ,
269+ "unexpected end of input, expected integer literal" ,
270+ )
271+ . to_compile_error ( )
272+ . to_string ( ) ;
273+ assert_eq ! ( tokens. to_string( ) , expect) ;
274+ }
275+
276+ #[ test]
277+ fn non_integer_input ( ) {
278+ let tokens = bytes ( quote ! { "hello" } ) ;
279+ let expect = Error :: new ( Span :: call_site ( ) , "expected integer literal" )
280+ . to_compile_error ( )
281+ . to_string ( ) ;
282+ assert_eq ! ( tokens. to_string( ) , expect) ;
283+ }
206284}
0 commit comments