@@ -45,6 +45,7 @@ mod escape;
4545mod to_tokens;
4646
4747use core:: ops:: BitOr ;
48+ use std:: borrow:: Cow ;
4849use std:: ffi:: CStr ;
4950use std:: ops:: { Range , RangeBounds } ;
5051use std:: path:: PathBuf ;
@@ -1183,6 +1184,62 @@ macro_rules! unsuffixed_int_literals {
11831184 ) * )
11841185}
11851186
1187+ macro_rules! integer_values {
1188+ ( $( $nb: ident => $fn_name: ident, ) +) => {
1189+ $(
1190+ #[ doc = concat!(
1191+ "Returns the unescaped `" ,
1192+ stringify!( $nb) ,
1193+ "` value if the literal is a `" ,
1194+ stringify!( $nb) ,
1195+ "` or if it's an \" unmarked\" integer which doesn't overflow." ) ]
1196+ #[ unstable( feature = "proc_macro_value" , issue = "136652" ) ]
1197+ pub fn $fn_name( & self ) -> Result <$nb, ConversionErrorKind > {
1198+ if self . 0 . kind != bridge:: LitKind :: Integer {
1199+ return Err ( ConversionErrorKind :: InvalidLiteralKind ) ;
1200+ }
1201+ self . with_symbol_and_suffix( |symbol, suffix| {
1202+ match suffix {
1203+ stringify!( $nb) | "" => {
1204+ let ( number, base) = parse_number( symbol) ;
1205+ $nb:: from_str_radix( & number, base as u32 ) . map_err( |_| ConversionErrorKind :: InvalidLiteralKind )
1206+ }
1207+ _ => Err ( ConversionErrorKind :: InvalidLiteralKind ) ,
1208+ }
1209+ } )
1210+ }
1211+ ) +
1212+ }
1213+ }
1214+
1215+ macro_rules! float_values {
1216+ ( $( $nb: ident => $fn_name: ident, ) +) => {
1217+ $(
1218+ #[ doc = concat!(
1219+ "Returns the unescaped `" ,
1220+ stringify!( $nb) ,
1221+ "` value if the literal is a `" ,
1222+ stringify!( $nb) ,
1223+ "` or if it's an \" unmarked\" float which doesn't overflow." ) ]
1224+ #[ unstable( feature = "proc_macro_value" , issue = "136652" ) ]
1225+ pub fn $fn_name( & self ) -> Result <$nb, ConversionErrorKind > {
1226+ if self . 0 . kind != bridge:: LitKind :: Float {
1227+ return Err ( ConversionErrorKind :: InvalidLiteralKind ) ;
1228+ }
1229+ self . with_symbol_and_suffix( |symbol, suffix| {
1230+ match suffix {
1231+ stringify!( $nb) | "" => {
1232+ let number = only_digits( symbol) ;
1233+ $nb:: from_str( & number) . map_err( |_| ConversionErrorKind :: InvalidLiteralKind )
1234+ }
1235+ _ => Err ( ConversionErrorKind :: InvalidLiteralKind ) ,
1236+ }
1237+ } )
1238+ }
1239+ ) +
1240+ }
1241+ }
1242+
11861243impl Literal {
11871244 fn new ( kind : bridge:: LitKind , value : & str , suffix : Option < & str > ) -> Self {
11881245 Literal ( bridge:: Literal {
@@ -1578,6 +1635,98 @@ impl Literal {
15781635 _ => Err ( ConversionErrorKind :: InvalidLiteralKind ) ,
15791636 } )
15801637 }
1638+
1639+ integer_values ! {
1640+ u8 => u8_value,
1641+ u16 => u16_value,
1642+ u32 => u32_value,
1643+ u64 => u64_value,
1644+ u128 => u128_value,
1645+ i8 => i8_value,
1646+ i16 => i16_value,
1647+ i32 => i32_value,
1648+ i64 => i64_value,
1649+ i128 => i128_value,
1650+ }
1651+
1652+ float_values ! {
1653+ // FIXME: To be uncommented when `f16` is stable.
1654+ // f16 => f16_value,
1655+ f32 => f32_value,
1656+ f64 => f64_value,
1657+ // FIXME: `f128` doesn't implement `FromStr` for the moment so we cannot obtain it from
1658+ // a `&str`. To be uncommented when it's added.
1659+ // f128 => f128_value,
1660+ }
1661+ }
1662+
1663+ #[ repr( u32 ) ]
1664+ #[ derive( PartialEq , Eq ) ]
1665+ enum Base {
1666+ Decimal = 10 ,
1667+ Binary = 2 ,
1668+ Octal = 8 ,
1669+ Hexadecimal = 16 ,
1670+ }
1671+
1672+ fn parse_number ( value : & str ) -> ( String , Base ) {
1673+ let mut iter = value. as_bytes ( ) . iter ( ) . copied ( ) ;
1674+ let Some ( first_digit) = iter. next ( ) else {
1675+ return ( "0" . into ( ) , Base :: Decimal ) ;
1676+ } ;
1677+ let Some ( second_digit) = iter. next ( ) else {
1678+ let mut output = String :: with_capacity ( 1 ) ;
1679+ output. push ( first_digit as char ) ;
1680+ return ( output, Base :: Decimal ) ;
1681+ } ;
1682+
1683+ let mut base = Base :: Decimal ;
1684+ if first_digit == b'0' {
1685+ // Attempt to parse encoding base.
1686+ match second_digit {
1687+ b'b' => {
1688+ base = Base :: Binary ;
1689+ }
1690+ b'o' => {
1691+ base = Base :: Octal ;
1692+ }
1693+ b'x' => {
1694+ base = Base :: Hexadecimal ;
1695+ }
1696+ _ => { }
1697+ }
1698+ }
1699+
1700+ let mut output = if base == Base :: Decimal {
1701+ let mut output = String :: with_capacity ( value. len ( ) ) ;
1702+ output. push ( first_digit as char ) ;
1703+ output. push ( second_digit as char ) ;
1704+ output
1705+ } else {
1706+ String :: with_capacity ( value. len ( ) - 2 )
1707+ } ;
1708+
1709+ for c in iter {
1710+ if c != b'_' {
1711+ output. push ( c as char ) ;
1712+ }
1713+ }
1714+
1715+ ( output, base)
1716+ }
1717+
1718+ fn only_digits ( value_s : & str ) -> Cow < ' _ , str > {
1719+ let value = value_s. as_bytes ( ) ;
1720+ if value. iter ( ) . copied ( ) . all ( |c| c != b'_' && c != b'f' ) {
1721+ return Cow :: Borrowed ( value_s) ;
1722+ }
1723+ let mut output = String :: with_capacity ( value. len ( ) ) ;
1724+ for c in value. iter ( ) . copied ( ) {
1725+ if c != b'_' {
1726+ output. push ( c as char ) ;
1727+ }
1728+ }
1729+ Cow :: Owned ( output)
15811730}
15821731
15831732/// Parse a single literal from its stringified representation.
0 commit comments