@@ -51,11 +51,24 @@ use std::{error, fmt};
5151
5252#[ unstable( feature = "proc_macro_diagnostic" , issue = "54140" ) ]
5353pub use diagnostic:: { Diagnostic , Level , MultiSpan } ;
54+ #[ unstable( feature = "proc_macro_value" , issue = "136652" ) ]
55+ pub use rustc_literal_escaper:: EscapeError ;
56+ use rustc_literal_escaper:: { MixedUnit , Mode , byte_from_char, unescape_mixed, unescape_unicode} ;
5457#[ unstable( feature = "proc_macro_totokens" , issue = "130977" ) ]
5558pub use to_tokens:: ToTokens ;
5659
5760use crate :: escape:: { EscapeOptions , escape_bytes} ;
5861
62+ /// Errors returned when trying to retrieve a literal unescaped value.
63+ #[ unstable( feature = "proc_macro_value" , issue = "136652" ) ]
64+ #[ derive( Debug , PartialEq , Eq ) ]
65+ pub enum ConversionErrorKind {
66+ /// The literal failed to be escaped, take a look at [`EscapeError`] for more information.
67+ FailedToUnescape ( EscapeError ) ,
68+ /// Trying to convert a literal with the wrong type.
69+ InvalidLiteralKind ,
70+ }
71+
5972/// Determines whether proc_macro has been made accessible to the currently
6073/// running program.
6174///
@@ -1451,6 +1464,107 @@ impl Literal {
14511464 }
14521465 } )
14531466 }
1467+
1468+ /// Returns the unescaped string value if the current literal is a string or a string literal.
1469+ #[ unstable( feature = "proc_macro_value" , issue = "136652" ) ]
1470+ pub fn str_value ( & self ) -> Result < String , ConversionErrorKind > {
1471+ self . 0 . symbol . with ( |symbol| match self . 0 . kind {
1472+ bridge:: LitKind :: Str => {
1473+ if symbol. contains ( '\\' ) {
1474+ let mut buf = String :: with_capacity ( symbol. len ( ) ) ;
1475+ let mut error = None ;
1476+ // Force-inlining here is aggressive but the closure is
1477+ // called on every char in the string, so it can be hot in
1478+ // programs with many long strings containing escapes.
1479+ unescape_unicode (
1480+ symbol,
1481+ Mode :: Str ,
1482+ & mut #[ inline ( always) ]
1483+ |_, c| match c {
1484+ Ok ( c) => buf. push ( c) ,
1485+ Err ( err) => {
1486+ if err. is_fatal ( ) {
1487+ error = Some ( ConversionErrorKind :: FailedToUnescape ( err) ) ;
1488+ }
1489+ }
1490+ } ,
1491+ ) ;
1492+ if let Some ( error) = error { Err ( error) } else { Ok ( buf) }
1493+ } else {
1494+ Ok ( symbol. to_string ( ) )
1495+ }
1496+ }
1497+ bridge:: LitKind :: StrRaw ( _) => Ok ( symbol. to_string ( ) ) ,
1498+ _ => Err ( ConversionErrorKind :: InvalidLiteralKind ) ,
1499+ } )
1500+ }
1501+
1502+ /// Returns the unescaped string value if the current literal is a c-string or a c-string
1503+ /// literal.
1504+ #[ unstable( feature = "proc_macro_value" , issue = "136652" ) ]
1505+ pub fn cstr_value ( & self ) -> Result < Vec < u8 > , ConversionErrorKind > {
1506+ self . 0 . symbol . with ( |symbol| match self . 0 . kind {
1507+ bridge:: LitKind :: CStr => {
1508+ let mut error = None ;
1509+ let mut buf = Vec :: with_capacity ( symbol. len ( ) ) ;
1510+
1511+ unescape_mixed ( symbol, Mode :: CStr , & mut |_span, c| match c {
1512+ Ok ( MixedUnit :: Char ( c) ) => {
1513+ buf. extend_from_slice ( c. encode_utf8 ( & mut [ 0 ; 4 ] ) . as_bytes ( ) )
1514+ }
1515+ Ok ( MixedUnit :: HighByte ( b) ) => buf. push ( b) ,
1516+ Err ( err) => {
1517+ if err. is_fatal ( ) {
1518+ error = Some ( ConversionErrorKind :: FailedToUnescape ( err) ) ;
1519+ }
1520+ }
1521+ } ) ;
1522+ if let Some ( error) = error {
1523+ Err ( error)
1524+ } else {
1525+ buf. push ( 0 ) ;
1526+ Ok ( buf)
1527+ }
1528+ }
1529+ bridge:: LitKind :: CStrRaw ( _) => {
1530+ // Raw strings have no escapes so we can convert the symbol
1531+ // directly to a `Lrc<u8>` after appending the terminating NUL
1532+ // char.
1533+ let mut buf = symbol. to_owned ( ) . into_bytes ( ) ;
1534+ buf. push ( 0 ) ;
1535+ Ok ( buf)
1536+ }
1537+ _ => Err ( ConversionErrorKind :: InvalidLiteralKind ) ,
1538+ } )
1539+ }
1540+
1541+ /// Returns the unescaped string value if the current literal is a byte string or a byte string
1542+ /// literal.
1543+ #[ unstable( feature = "proc_macro_value" , issue = "136652" ) ]
1544+ pub fn byte_str_value ( & self ) -> Result < Vec < u8 > , ConversionErrorKind > {
1545+ self . 0 . symbol . with ( |symbol| match self . 0 . kind {
1546+ bridge:: LitKind :: ByteStr => {
1547+ let mut buf = Vec :: with_capacity ( symbol. len ( ) ) ;
1548+ let mut error = None ;
1549+
1550+ unescape_unicode ( symbol, Mode :: ByteStr , & mut |_, c| match c {
1551+ Ok ( c) => buf. push ( byte_from_char ( c) ) ,
1552+ Err ( err) => {
1553+ if err. is_fatal ( ) {
1554+ error = Some ( ConversionErrorKind :: FailedToUnescape ( err) ) ;
1555+ }
1556+ }
1557+ } ) ;
1558+ if let Some ( error) = error { Err ( error) } else { Ok ( buf) }
1559+ }
1560+ bridge:: LitKind :: ByteStrRaw ( _) => {
1561+ // Raw strings have no escapes so we can convert the symbol
1562+ // directly to a `Lrc<u8>`.
1563+ Ok ( symbol. to_owned ( ) . into_bytes ( ) )
1564+ }
1565+ _ => Err ( ConversionErrorKind :: InvalidLiteralKind ) ,
1566+ } )
1567+ }
14541568}
14551569
14561570/// Parse a single literal from its stringified representation.
0 commit comments