Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve panic! messages in hex-literal #664

Merged
merged 4 commits into from Nov 11, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 19 additions & 3 deletions hex-literal/src/lib.rs
Expand Up @@ -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<u8> = 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();
Expand All @@ -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<u8> {
loop {
let v = self.buf.next()?;
Expand All @@ -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),
newpavlov marked this conversation as resolved.
Show resolved Hide resolved
};
return Some(n);
}
Expand All @@ -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<TokenTree> {
let v = if self.is_punct {
TokenTree::Punct(Punct::new(',', Spacing::Alone))
Expand All @@ -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);
}
Expand Down
83 changes: 83 additions & 0 deletions hex-literal/tests/basic.rs
@@ -0,0 +1,83 @@
use hex_literal::hex;

#[test]
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]);
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");
}
41 changes: 41 additions & 0 deletions 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]
);
}