Skip to content

Commit

Permalink
Add Literal::byte_character constructor
Browse files Browse the repository at this point in the history
  • Loading branch information
dtolnay committed Apr 14, 2024
1 parent 5bdf9be commit 3a4a8d9
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 1 deletion.
4 changes: 4 additions & 0 deletions build.rs
Expand Up @@ -63,6 +63,10 @@ fn main() {
println!("cargo:rustc-cfg=no_source_text");
}

if rustc < 79 {
println!("cargo:rustc-cfg=no_literal_byte_character");
}

if !cfg!(feature = "proc-macro") {
println!("cargo:rerun-if-changed=build.rs");
return;
Expand Down
21 changes: 20 additions & 1 deletion src/fallback.rs
Expand Up @@ -926,7 +926,7 @@ impl Debug for Ident {

#[derive(Clone)]
pub(crate) struct Literal {
repr: String,
pub(crate) repr: String,
span: Span,
}

Expand Down Expand Up @@ -1048,6 +1048,25 @@ impl Literal {
Literal::_new(repr)
}

pub fn byte_character(byte: u8) -> Literal {
let mut repr = "b'".to_string();
#[allow(clippy::match_overlapping_arm)]
match byte {
b'\0' => repr.push_str(r"\0"),
b'\t' => repr.push_str(r"\t"),
b'\n' => repr.push_str(r"\n"),
b'\r' => repr.push_str(r"\r"),
b'\'' => repr.push_str("\\\'"),
b'\\' => repr.push_str(r"\\"),
b'\x20'..=b'\x7E' => repr.push(byte as char),
_ => {
let _ = write!(repr, r"\x{:02X}", byte);
}
}
repr.push('\'');
Literal::_new(repr)
}

pub fn byte_string(bytes: &[u8]) -> Literal {
let mut repr = "b\"".to_string();
let mut bytes = bytes.iter();
Expand Down
5 changes: 5 additions & 0 deletions src/lib.rs
Expand Up @@ -1234,6 +1234,11 @@ impl Literal {
Literal::_new(imp::Literal::character(ch))
}

/// Byte character literal.
pub fn byte_character(byte: u8) -> Literal {
Literal::_new(imp::Literal::byte_character(byte))
}

/// Byte string literal.
pub fn byte_string(s: &[u8]) -> Literal {
Literal::_new(imp::Literal::byte_string(s))
Expand Down
19 changes: 19 additions & 0 deletions src/wrapper.rs
Expand Up @@ -862,6 +862,25 @@ impl Literal {
}
}

pub fn byte_character(byte: u8) -> Literal {
if inside_proc_macro() {
Literal::Compiler({
#[cfg(not(no_literal_byte_character))]
{
proc_macro::Literal::byte_character(byte)
}

#[cfg(no_literal_byte_character)]
{
let fallback = fallback::Literal::byte_character(byte);
fallback.repr.parse::<proc_macro::Literal>().unwrap()
}
})
} else {
Literal::Fallback(fallback::Literal::byte_character(byte))
}
}

pub fn byte_string(bytes: &[u8]) -> Literal {
if inside_proc_macro() {
Literal::Compiler(proc_macro::Literal::byte_string(bytes))
Expand Down
12 changes: 12 additions & 0 deletions tests/test.rs
Expand Up @@ -132,6 +132,18 @@ fn literal_raw_string() {
.unwrap_err();
}

#[test]
fn literal_byte_character() {
assert_eq!(Literal::byte_character(b'\0').to_string(), r"b'\0'");
assert_eq!(Literal::byte_character(b'\t').to_string(), r"b'\t'");
assert_eq!(Literal::byte_character(b'\n').to_string(), r"b'\n'");
assert_eq!(Literal::byte_character(b'\r').to_string(), r"b'\r'");
assert_eq!(Literal::byte_character(b'\'').to_string(), r"b'\''");
assert_eq!(Literal::byte_character(b'\\').to_string(), r"b'\\'");
assert_eq!(Literal::byte_character(b'\x1f').to_string(), r"b'\x1F'");
assert_eq!(Literal::byte_character(b'"').to_string(), "b'\"'");
}

#[test]
fn literal_byte_string() {
assert_eq!(Literal::byte_string(b"").to_string(), "b\"\"");
Expand Down

0 comments on commit 3a4a8d9

Please sign in to comment.