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