Skip to content

Commit c40fc5e

Browse files
Add new Literal::str_value, Literal::cstr_value and Literal::byte_str_value methods
1 parent 72aaf49 commit c40fc5e

File tree

2 files changed

+94
-0
lines changed

2 files changed

+94
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ features = ["span-locations"]
3030

3131
[dependencies]
3232
unicode-ident = "1.0"
33+
rustc-literal-escaper = "0.0.5"
3334

3435
[dev-dependencies]
3536
flate2 = "1.0"

src/lib.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
#![cfg_attr(any(proc_macro_span, super_unstable), feature(proc_macro_span))]
8989
#![cfg_attr(super_unstable, feature(proc_macro_def_site))]
9090
#![cfg_attr(docsrs, feature(doc_cfg))]
91+
#![cfg_attr(procmacro2_semver_exempt, feature(proc_macro_value))]
9192
#![deny(unsafe_op_in_unsafe_fn)]
9293
#![allow(
9394
clippy::cast_lossless,
@@ -1271,6 +1272,98 @@ impl Literal {
12711272
pub unsafe fn from_str_unchecked(repr: &str) -> Self {
12721273
Literal::_new(unsafe { imp::Literal::from_str_unchecked(repr) })
12731274
}
1275+
1276+
/// Returns the unescaped string value if the current literal is a string or a string literal.
1277+
#[cfg(procmacro2_semver_exempt)]
1278+
pub fn str_value(&self) -> Result<String, proc_macro::ConversionErrorKind> {
1279+
match self.inner {
1280+
imp::Literal::Compiler(ref compiler_lit) => compiler_lit.str_value(),
1281+
imp::Literal::Fallback(ref fallback) => {
1282+
if !fallback.repr.starts_with('"') {
1283+
return Err(proc_macro::ConversionErrorKind::InvalidLiteralKind);
1284+
}
1285+
let mut error = None;
1286+
let mut buf = String::with_capacity(fallback.repr.len());
1287+
rustc_literal_escaper::unescape_str(&fallback.repr, |_, res| match res {
1288+
Ok(c) => buf.push(c),
1289+
Err(err) => {
1290+
if err.is_fatal() {
1291+
error = Some(ConversionErrorKind::FailedToUnescape(err));
1292+
}
1293+
}
1294+
});
1295+
if let Some(error) = error {
1296+
Err(error)
1297+
} else {
1298+
Ok(buf)
1299+
}
1300+
}
1301+
}
1302+
}
1303+
1304+
/// Returns the unescaped string value if the current literal is a c-string or a c-string
1305+
/// literal.
1306+
#[cfg(procmacro2_semver_exempt)]
1307+
pub fn cstr_value(&self) -> Result<Vec<u8>, proc_macro::ConversionErrorKind> {
1308+
match self.inner {
1309+
imp::Literal::Compiler(ref compiler_lit) => compiler_lit.cstr_value(),
1310+
imp::Literal::Fallback(ref fallback) => {
1311+
if !fallback.repr.starts_with('c') {
1312+
return Err(proc_macro::ConversionErrorKind::InvalidLiteralKind);
1313+
}
1314+
let mut error = None;
1315+
let mut buf = Vec::with_capacity(symbol.len());
1316+
1317+
rustc_literal_escaper::unescape_c_str(symbol, |_span, res| match res {
1318+
Ok(MixedUnit::Char(c)) => {
1319+
buf.extend_from_slice(c.get().encode_utf8(&mut [0; 4]).as_bytes())
1320+
}
1321+
Ok(MixedUnit::HighByte(b)) => buf.push(b.get()),
1322+
Err(err) => {
1323+
if err.is_fatal() {
1324+
error = Some(ConversionErrorKind::FailedToUnescape(err));
1325+
}
1326+
}
1327+
});
1328+
if let Some(error) = error {
1329+
Err(error)
1330+
} else {
1331+
buf.push(0);
1332+
Ok(buf)
1333+
}
1334+
}
1335+
}
1336+
}
1337+
1338+
/// Returns the unescaped string value if the current literal is a byte string or a byte string
1339+
/// literal.
1340+
#[cfg(procmacro2_semver_exempt)]
1341+
pub fn byte_str_value(&self) -> Result<Vec<u8>, proc_macro::ConversionErrorKind> {
1342+
match self.inner {
1343+
imp::Literal::Compiler(ref compiler_lit) => compiler_lit.byte_str_value(),
1344+
imp::Literal::Fallback(ref fallback) => {
1345+
if !fallback.repr.starts_with('c') {
1346+
return Err(proc_macro::ConversionErrorKind::InvalidLiteralKind);
1347+
}
1348+
let mut error = None;
1349+
let mut buf = Vec::with_capacity(symbol.len());
1350+
1351+
rustc_literal_escaper::unescape_byte_str(symbol, |_span, res| match res {
1352+
Ok(c) => buf.push(c),
1353+
Err(err) => {
1354+
if err.is_fatal() {
1355+
error = Some(ConversionErrorKind::FailedToUnescape(err));
1356+
}
1357+
}
1358+
});
1359+
if let Some(error) = error {
1360+
Err(error)
1361+
} else {
1362+
Ok(buf)
1363+
}
1364+
}
1365+
}
1366+
}
12741367
}
12751368

12761369
impl FromStr for Literal {

0 commit comments

Comments
 (0)