|
88 | 88 | #![cfg_attr(any(proc_macro_span, super_unstable), feature(proc_macro_span))]
|
89 | 89 | #![cfg_attr(super_unstable, feature(proc_macro_def_site))]
|
90 | 90 | #![cfg_attr(docsrs, feature(doc_cfg))]
|
| 91 | +#![cfg_attr( |
| 92 | + all(procmacro2_semver_exempt, feature = "proc-macro"), |
| 93 | + feature(proc_macro_value) |
| 94 | +)] |
91 | 95 | #![deny(unsafe_op_in_unsafe_fn)]
|
92 | 96 | #![allow(
|
93 | 97 | clippy::cast_lossless,
|
@@ -178,6 +182,11 @@ use std::ffi::CStr;
|
178 | 182 | #[cfg(span_locations)]
|
179 | 183 | use std::path::PathBuf;
|
180 | 184 |
|
| 185 | +#[cfg(all(procmacro2_semver_exempt, feature = "proc-macro"))] |
| 186 | +use proc_macro::ConversionErrorKind; |
| 187 | +#[cfg(all(procmacro2_semver_exempt, feature = "proc-macro"))] |
| 188 | +use rustc_literal_escaper::MixedUnit; |
| 189 | + |
181 | 190 | #[cfg(span_locations)]
|
182 | 191 | #[cfg_attr(docsrs, doc(cfg(feature = "span-locations")))]
|
183 | 192 | pub use crate::location::LineColumn;
|
@@ -1271,6 +1280,113 @@ impl Literal {
|
1271 | 1280 | pub unsafe fn from_str_unchecked(repr: &str) -> Self {
|
1272 | 1281 | Literal::_new(unsafe { imp::Literal::from_str_unchecked(repr) })
|
1273 | 1282 | }
|
| 1283 | + |
| 1284 | + /// Returns the unescaped string value if the current literal is a string or a string literal. |
| 1285 | + #[cfg(all(procmacro2_semver_exempt, feature = "proc-macro"))] |
| 1286 | + pub fn str_value(&self) -> Result<String, ConversionErrorKind> { |
| 1287 | + match self.inner { |
| 1288 | + imp::Literal::Compiler(ref compiler_lit) => compiler_lit.str_value(), |
| 1289 | + imp::Literal::Fallback(ref fallback) => { |
| 1290 | + if !fallback.repr.starts_with('"') { |
| 1291 | + return Err(ConversionErrorKind::InvalidLiteralKind); |
| 1292 | + } |
| 1293 | + let mut error = None; |
| 1294 | + let mut buf = String::with_capacity(fallback.repr.len()); |
| 1295 | + rustc_literal_escaper::unescape_str(&fallback.repr, |_, res| match res { |
| 1296 | + Ok(c) => buf.push(c), |
| 1297 | + Err(err) => { |
| 1298 | + if err.is_fatal() { |
| 1299 | + // `proc_macro::EscapeError` is the reexport of |
| 1300 | + // `rustc_literal_escaper::EscapeError` so we safely transmute between |
| 1301 | + // the two. |
| 1302 | + error = Some(ConversionErrorKind::FailedToUnescape(unsafe { |
| 1303 | + std::mem::transmute(err) |
| 1304 | + })); |
| 1305 | + } |
| 1306 | + } |
| 1307 | + }); |
| 1308 | + if let Some(error) = error { |
| 1309 | + Err(error) |
| 1310 | + } else { |
| 1311 | + Ok(buf) |
| 1312 | + } |
| 1313 | + } |
| 1314 | + } |
| 1315 | + } |
| 1316 | + |
| 1317 | + /// Returns the unescaped string value if the current literal is a c-string or a c-string |
| 1318 | + /// literal. |
| 1319 | + #[cfg(all(procmacro2_semver_exempt, feature = "proc-macro"))] |
| 1320 | + pub fn cstr_value(&self) -> Result<Vec<u8>, ConversionErrorKind> { |
| 1321 | + match self.inner { |
| 1322 | + imp::Literal::Compiler(ref compiler_lit) => compiler_lit.cstr_value(), |
| 1323 | + imp::Literal::Fallback(ref fallback) => { |
| 1324 | + if !fallback.repr.starts_with('c') { |
| 1325 | + return Err(ConversionErrorKind::InvalidLiteralKind); |
| 1326 | + } |
| 1327 | + let mut error = None; |
| 1328 | + let mut buf = Vec::with_capacity(fallback.repr.len()); |
| 1329 | + |
| 1330 | + rustc_literal_escaper::unescape_c_str(&fallback.repr, |_span, res| match res { |
| 1331 | + Ok(MixedUnit::Char(c)) => { |
| 1332 | + buf.extend_from_slice(c.get().encode_utf8(&mut [0; 4]).as_bytes()) |
| 1333 | + } |
| 1334 | + Ok(MixedUnit::HighByte(b)) => buf.push(b.get()), |
| 1335 | + Err(err) => { |
| 1336 | + if err.is_fatal() { |
| 1337 | + // `proc_macro::EscapeError` is the reexport of |
| 1338 | + // `rustc_literal_escaper::EscapeError` so we safely transmute between |
| 1339 | + // the two. |
| 1340 | + error = Some(ConversionErrorKind::FailedToUnescape(unsafe { |
| 1341 | + std::mem::transmute(err) |
| 1342 | + })); |
| 1343 | + } |
| 1344 | + } |
| 1345 | + }); |
| 1346 | + if let Some(error) = error { |
| 1347 | + Err(error) |
| 1348 | + } else { |
| 1349 | + buf.push(0); |
| 1350 | + Ok(buf) |
| 1351 | + } |
| 1352 | + } |
| 1353 | + } |
| 1354 | + } |
| 1355 | + |
| 1356 | + /// Returns the unescaped string value if the current literal is a byte string or a byte string |
| 1357 | + /// literal. |
| 1358 | + #[cfg(all(procmacro2_semver_exempt, feature = "proc-macro"))] |
| 1359 | + pub fn byte_str_value(&self) -> Result<Vec<u8>, ConversionErrorKind> { |
| 1360 | + match self.inner { |
| 1361 | + imp::Literal::Compiler(ref compiler_lit) => compiler_lit.byte_str_value(), |
| 1362 | + imp::Literal::Fallback(ref fallback) => { |
| 1363 | + if !fallback.repr.starts_with('c') { |
| 1364 | + return Err(ConversionErrorKind::InvalidLiteralKind); |
| 1365 | + } |
| 1366 | + let mut error = None; |
| 1367 | + let mut buf = Vec::with_capacity(fallback.repr.len()); |
| 1368 | + |
| 1369 | + rustc_literal_escaper::unescape_byte_str(&fallback.repr, |_span, res| match res { |
| 1370 | + Ok(c) => buf.push(c), |
| 1371 | + Err(err) => { |
| 1372 | + if err.is_fatal() { |
| 1373 | + // `proc_macro::EscapeError` is the reexport of |
| 1374 | + // `rustc_literal_escaper::EscapeError` so we safely transmute between |
| 1375 | + // the two. |
| 1376 | + error = Some(ConversionErrorKind::FailedToUnescape(unsafe { |
| 1377 | + std::mem::transmute(err) |
| 1378 | + })); |
| 1379 | + } |
| 1380 | + } |
| 1381 | + }); |
| 1382 | + if let Some(error) = error { |
| 1383 | + Err(error) |
| 1384 | + } else { |
| 1385 | + Ok(buf) |
| 1386 | + } |
| 1387 | + } |
| 1388 | + } |
| 1389 | + } |
1274 | 1390 | }
|
1275 | 1391 |
|
1276 | 1392 | impl FromStr for Literal {
|
|
0 commit comments