Skip to content

Commit 3381417

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

File tree

2 files changed

+93
-0
lines changed

2 files changed

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

12761368
impl FromStr for Literal {

0 commit comments

Comments
 (0)