From eaec467b9e8f4ce4d29f2b403d1fd379b55bcaec Mon Sep 17 00:00:00 2001 From: Thomas Castleman Date: Wed, 10 Nov 2021 11:29:23 -0500 Subject: [PATCH 1/4] update panic! messages to include more information: --- hex-literal/src/lib.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/hex-literal/src/lib.rs b/hex-literal/src/lib.rs index 6608d102..80712e74 100644 --- a/hex-literal/src/lib.rs +++ b/hex-literal/src/lib.rs @@ -86,12 +86,16 @@ struct TokenTreeIter { } impl TokenTreeIter { + /// Constructs a new `TokenTreeIter` from a given `proc_macro::Literal`. + /// + /// # Panics + /// This panics if the given `Literal` is not a string literal. fn new(input: Literal) -> Self { let mut buf: Vec = input.to_string().into(); match buf.as_slice() { [b'"', .., b'"'] => (), - _ => panic!("expected string literals"), + _ => panic!("expected string literal, got `{}`", input), }; buf.pop(); let mut iter = buf.into_iter().exclude_comments(); @@ -102,6 +106,11 @@ impl TokenTreeIter { } } + /// Parses a single hex character (a-f/A-F/0-9) as a `u8` from the `TokenTreeIter`'s + /// internal buffer, ignoring whitespace. + /// + /// # Panics + /// This panics if a non-hex, non-whitespace character is encountered. fn next_hex_val(&mut self) -> Option { loop { let v = self.buf.next()?; @@ -110,7 +119,7 @@ impl TokenTreeIter { b'A'..=b'F' => v - 55, b'a'..=b'f' => v - 87, b' ' | b'\r' | b'\n' | b'\t' => continue, - _ => panic!("encountered invalid character"), + c => panic!("encountered invalid character: `{}`", c as char), }; return Some(n); } @@ -120,6 +129,13 @@ impl TokenTreeIter { impl Iterator for TokenTreeIter { type Item = TokenTree; + /// Produces hex values (as `u8` literals) parsed from the `TokenTreeIter`'s + /// internal buffer, alternating with commas to separate the elements of the + /// generated array of bytes. + /// + /// # Panics + /// This panics if the internal buffer contains an odd number of hex + /// characters. fn next(&mut self) -> Option { let v = if self.is_punct { TokenTree::Punct(Punct::new(',', Spacing::Alone)) @@ -145,7 +161,7 @@ pub fn hex(input: TokenStream) -> TokenStream { for tt in ignore_groups(input) { let iter = match tt { TokenTree::Literal(literal) => TokenTreeIter::new(literal), - _ => panic!("expected string literals"), + unexpected => panic!("expected string literal, got `{}`", unexpected), }; out_ts.extend(iter); } From b936de9849c45f2f8bf784b2ff2f206f84499e50 Mon Sep 17 00:00:00 2001 From: Thomas Castleman Date: Wed, 10 Nov 2021 11:49:22 -0500 Subject: [PATCH 2/4] add more tests for the hex!() macro --- hex-literal/tests/basic.rs | 77 +++++++++++++++++++++++++++++++++++ hex-literal/tests/comments.rs | 41 +++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 hex-literal/tests/basic.rs create mode 100644 hex-literal/tests/comments.rs diff --git a/hex-literal/tests/basic.rs b/hex-literal/tests/basic.rs new file mode 100644 index 00000000..2057287c --- /dev/null +++ b/hex-literal/tests/basic.rs @@ -0,0 +1,77 @@ +use hex_literal::hex; + +#[test] +fn single_literal() { + assert_eq!(hex!("ff e4"), [0xff, 0xe4]); +} + +#[test] +fn upper_case() { + assert_eq!(hex!("AE DF 04 B2"), [0xae, 0xdf, 0x04, 0xb2]); + assert_eq!(hex!("FF BA 8C 00 01"), [0xff, 0xba, 0x8c, 0x00, 0x01]); +} + +#[test] +fn mixed_case() { + assert_eq!(hex!("bF dd E4 Cd"), [0xbf, 0xdd, 0xe4, 0xcd]); +} + +#[test] +fn multiple_literals() { + assert_eq!( + hex!( + "01 dd f7 7f" + "ee f0 d8" + ), + [0x01, 0xdd, 0xf7, 0x7f, 0xee, 0xf0, 0xd8] + ); + assert_eq!( + hex!( + "ff" + "e8 d0" + "" + "01 1f" + "ab" + ), + [0xff, 0xe8, 0xd0, 0x01, 0x1f, 0xab] + ); +} + +#[test] +fn no_spacing() { + assert_eq!(hex!("abf0d8bb0f14"), [0xab, 0xf0, 0xd8, 0xbb, 0x0f, 0x14]); + assert_eq!( + hex!("09FFd890cbcCd1d08F"), + [0x09, 0xff, 0xd8, 0x90, 0xcb, 0xcc, 0xd1, 0xd0, 0x8f] + ); +} + +#[test] +fn allows_various_spacing() { + // newlines + assert_eq!( + hex!( + "f + f + d + 0 + e + + 8 + " + ), + [0xff, 0xd0, 0xe8] + ); + // tabs + assert_eq!( + hex!("9f d 1 f07 3 01"), + [0x9f, 0xd1, 0xf0, 0x73, 0x01] + ); + // spaces + assert_eq!(hex!(" e e d0 9 1 f f "), [0xee, 0xd0, 0x91, 0xff]); +} + +#[test] +fn can_use_const() { + const _: [u8; 4] = hex!("ff d3 01 7f"); +} diff --git a/hex-literal/tests/comments.rs b/hex-literal/tests/comments.rs new file mode 100644 index 00000000..7ebb7eb7 --- /dev/null +++ b/hex-literal/tests/comments.rs @@ -0,0 +1,41 @@ +use hex_literal::hex; + +#[test] +fn single_line_comments() { + assert_eq!(hex!("dd 03 // comment"), [0xdd, 0x03]); + assert_eq!( + hex!( + "00 04 f0 // a comment here + 54 fe // another comment" + ), + [0x00, 0x04, 0xf0, 0x54, 0xfe] + ); + assert_eq!( + hex!( + "// initial comment + 01 02" + ), + [0x01, 0x02] + ); +} + +#[test] +fn block_comments() { + assert_eq!( + hex!("00 01 02 /* intervening comment */ 03 04"), + [0x00, 0x01, 0x02, 0x03, 0x04] + ); + assert_eq!(hex!("/* initial comment */ ff df dd"), [0xff, 0xdf, 0xdd]); + assert_eq!( + hex!( + "8f ff 7d /* + comment + on + several + lines + */ + d0 a3" + ), + [0x8f, 0xff, 0x7d, 0xd0, 0xa3] + ); +} From b1000b0c12fd1bf4bf70b9b0e773ad7a9eadefdd Mon Sep 17 00:00:00 2001 From: Thomas Castleman Date: Wed, 10 Nov 2021 16:50:23 -0500 Subject: [PATCH 3/4] actually use tabs in whitespace test, test empty use of hex!() --- hex-literal/tests/basic.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/hex-literal/tests/basic.rs b/hex-literal/tests/basic.rs index 2057287c..b4af38ec 100644 --- a/hex-literal/tests/basic.rs +++ b/hex-literal/tests/basic.rs @@ -5,6 +5,15 @@ fn single_literal() { assert_eq!(hex!("ff e4"), [0xff, 0xe4]); } +#[test] +fn empty() { + let nothing: [u8; 0] = hex!(); + let empty_literals: [u8; 0] = hex!("" "" ""); + let expected: [u8; 0] = []; + assert_eq!(nothing, expected); + assert_eq!(empty_literals, expected); +} + #[test] fn upper_case() { assert_eq!(hex!("AE DF 04 B2"), [0xae, 0xdf, 0x04, 0xb2]); @@ -63,10 +72,7 @@ fn allows_various_spacing() { [0xff, 0xd0, 0xe8] ); // tabs - assert_eq!( - hex!("9f d 1 f07 3 01"), - [0x9f, 0xd1, 0xf0, 0x73, 0x01] - ); + assert_eq!(hex!("9f d 1 f07 3 01 "), [0x9f, 0xd1, 0xf0, 0x73, 0x01]); // spaces assert_eq!(hex!(" e e d0 9 1 f f "), [0xee, 0xd0, 0x91, 0xff]); } From bae9ebd6a3aa6923794e06c804a796c0b522c830 Mon Sep 17 00:00:00 2001 From: Thomas Castleman Date: Thu, 11 Nov 2021 09:40:11 -0500 Subject: [PATCH 4/4] fix for non-ascii characters, update changelog --- hex-literal/CHANGELOG.md | 8 ++++++++ hex-literal/src/lib.rs | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/hex-literal/CHANGELOG.md b/hex-literal/CHANGELOG.md index 36375e7d..43edcac4 100644 --- a/hex-literal/CHANGELOG.md +++ b/hex-literal/CHANGELOG.md @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [UNRELEASED] +### Changed +- Provide more info in `panic!` messages + +### Added +- More tests for `hex!()` macro +- More internal documentation + ## 0.3.3 (2021-07-17) ### Added - Accept sequence of string literals ([#519]) diff --git a/hex-literal/src/lib.rs b/hex-literal/src/lib.rs index 80712e74..73c44723 100644 --- a/hex-literal/src/lib.rs +++ b/hex-literal/src/lib.rs @@ -119,7 +119,8 @@ impl TokenTreeIter { b'A'..=b'F' => v - 55, b'a'..=b'f' => v - 87, b' ' | b'\r' | b'\n' | b'\t' => continue, - c => panic!("encountered invalid character: `{}`", c as char), + 0..=127 => panic!("encountered invalid character: `{}`", v as char), + _ => panic!("encountered invalid non-ASCII character"), }; return Some(n); }