@@ -50,11 +50,22 @@ use std::{error, fmt};
50
50
51
51
#[ unstable( feature = "proc_macro_diagnostic" , issue = "54140" ) ]
52
52
pub use diagnostic:: { Diagnostic , Level , MultiSpan } ;
53
+ #[ stable( feature = "proc_macro_lib2" , since = "1.86.0" ) ]
54
+ pub use literal_escaper:: EscapeError ;
53
55
#[ unstable( feature = "proc_macro_totokens" , issue = "130977" ) ]
54
56
pub use to_tokens:: ToTokens ;
55
57
56
58
use crate :: escape:: { EscapeOptions , escape_bytes} ;
57
59
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
+
58
69
/// Determines whether proc_macro has been made accessible to the currently
59
70
/// running program.
60
71
///
@@ -1450,6 +1461,106 @@ impl Literal {
1450
1461
}
1451
1462
} )
1452
1463
}
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
+ }
1453
1564
}
1454
1565
1455
1566
/// Parse a single literal from its stringified representation.
0 commit comments