use crate::{IntoTokens, Parse, ProcMacro, ProcMacroExt, ToTokenStream};
use std::{ffi, fmt::Display, str::FromStr};
#[cfg(feature = "literal-value")]
#[derive(Clone, Debug)]
pub enum LiteralValue<S: crate::Span> {
String(StringLiteral<S>),
ByteString(ByteStringLiteral<S>),
CString(CStringLiteral<S>),
Character(CharacterLiteral<S>),
ByteCharacter(ByteCharacterLiteral<S>),
Int(IntLiteral<S>),
Float(FloatLiteral<S>),
I8(I8Literal<S>),
I16(I16Literal<S>),
I32(I32Literal<S>),
I64(I64Literal<S>),
I128(I128Literal<S>),
Isize(IsizeLiteral<S>),
U8(U8Literal<S>),
U16(U16Literal<S>),
U32(U32Literal<S>),
U64(U64Literal<S>),
U128(U128Literal<S>),
Usize(UsizeLiteral<S>),
F32(F32Literal<S>),
F64(F64Literal<S>),
}
#[cfg(feature = "literal-value")]
enum OptByteOrChar {
Byte(u8),
Char(char),
None,
}
#[cfg(feature = "literal-value")]
impl<S: crate::SpanExt> FromStr for LiteralValue<S> {
type Err = crate::Error<S>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut input = s.as_bytes();
#[derive(Clone, Copy)]
enum Escapes {
Char,
String,
CString,
}
fn bin_digit<S: crate::SpanExt>(b: u8) -> Result<u8, crate::Error<S>> {
match b {
b'0'..=b'1' => Ok(b - b'0'),
_ => Err(crate::Error::new("expected binary digit")),
}
}
fn oct_digit<S: crate::SpanExt>(b: u8) -> Result<u8, crate::Error<S>> {
match b {
b'0'..=b'7' => Ok(b - b'0'),
_ => Err(crate::Error::new("expected octal digit")),
}
}
fn hex_digit<S: crate::SpanExt>(b: u8) -> Result<u8, crate::Error<S>> {
match b {
b'0'..=b'9' => Ok(b - b'0'),
b'a'..=b'f' => Ok(b - b'a' + 10),
b'A'..=b'F' => Ok(b - b'A' + 10),
_ => Err(crate::Error::new("expected hexadecimal digit")),
}
}
fn from_int<S: crate::SpanExt>(
value: u128,
suffix: &[u8],
) -> Result<LiteralValue<S>, crate::Error<S>> {
macro_rules! make {
($($s:literal => $t:ident: $token:ident $(: $as:ident)?),* $(,)?) => {
match suffix {
$(
$s => Ok(LiteralValue::$t($token::new(
(value $(as $as)?)
.try_into()
.map_err(|_| crate::Error::new("suffixed literal out of range"))?,
))),
)*
b"" => Ok(LiteralValue::Int(IntLiteral::new(value))),
_ => unreachable!(),
}
};
}
make! {
b"u8" => U8: U8Literal,
b"u16" => U16: U16Literal,
b"u32" => U32: U32Literal,
b"u64" => U64: U64Literal,
b"u128" => U128: U128Literal,
b"usize" => Usize: UsizeLiteral,
b"i8" => I8: I8Literal,
b"i16" => I16: I16Literal,
b"i32" => I32: I32Literal,
b"i64" => I64: I64Literal,
b"i128" => I128: I128Literal,
b"isize" => Isize: IsizeLiteral,
b"f32" => F32: F32Literal: f32,
b"f64" => F64: F64Literal: f64,
}
}
fn parse_suffix<'a>(input: &mut &'a [u8], include_float: bool) -> &'a [u8] {
if input.len() >= 2 {
let suffix = &input[input.len() - 2..];
match suffix {
b"u8" | b"i8" => {
*input = &input[..input.len() - 2];
return suffix;
}
_ => (),
}
if input.len() >= 3 {
let suffix = &input[input.len() - 3..];
match suffix {
b"u16" | b"u32" | b"u64" | b"i16" | b"i32" | b"i64" => {
*input = &input[..input.len() - 3];
return suffix;
}
b"f32" | b"f64" if include_float => {
*input = &input[..input.len() - 3];
return suffix;
}
_ => (),
}
if input.len() >= 4 {
let suffix = &input[input.len() - 4..];
match suffix {
b"u128" | b"i128" => {
*input = &input[..input.len() - 4];
return suffix;
}
_ => (),
}
if input.len() >= 5 {
let suffix = &input[input.len() - 5..];
match suffix {
b"usize" | b"isize" => {
*input = &input[..input.len() - 5];
return suffix;
}
_ => (),
}
}
}
}
}
&input[0..0]
}
fn parse_byte_escape<S: crate::SpanExt>(
input: &mut &[u8],
escapes: Escapes,
) -> Result<Option<u8>, crate::Error<S>> {
assert_eq!(input[0], b'\\');
if input.len() >= 2 {
let escape = input[1];
*input = &input[2..];
match escape {
b'\'' => Ok(Some(b'\'')),
b'\"' => Ok(Some(b'\"')),
b'\\' => Ok(Some(b'\\')),
b'0' => Ok(Some(b'\0')),
b'n' => Ok(Some(b'\n')),
b'r' => Ok(Some(b'\r')),
b't' => Ok(Some(b'\t')),
b'\n' if matches!(escapes, Escapes::String) => Ok(None),
b'x' if input.len() >= 2 => {
let value = hex_digit(input[0])? << 4 | hex_digit(input[1])?;
*input = &input[2..];
Ok(Some(value))
}
_ => Err(crate::Error::new("unrecognized byte escape")),
}
} else {
Err(crate::Error::new("unrecognized byte escape"))
}
}
fn parse_byte<S: crate::SpanExt>(
input: &mut &[u8],
escapes: Escapes,
) -> Result<Option<u8>, crate::Error<S>> {
if let Some(&value) = input.first() {
if value == b'\\' {
Ok(parse_byte_escape(input, escapes)?)
} else {
*input = &input[1..];
Ok(Some(value))
}
} else {
Err(crate::Error::new("expected byte"))
}
}
fn parse_char_escape<S: crate::SpanExt>(
input: &mut &[u8],
escapes: Escapes,
) -> Result<OptByteOrChar, crate::Error<S>> {
assert_eq!(input[0], b'\\');
if input.len() >= 2 {
let escape = input[1];
*input = &input[2..];
match escape {
b'\'' => Ok(OptByteOrChar::Char('\'')),
b'\"' => Ok(OptByteOrChar::Char('\"')),
b'\\' => Ok(OptByteOrChar::Char('\\')),
b'0' if !matches!(escapes, Escapes::CString) => Ok(OptByteOrChar::Char('\0')),
b'n' => Ok(OptByteOrChar::Char('\n')),
b'r' => Ok(OptByteOrChar::Char('\r')),
b't' => Ok(OptByteOrChar::Char('\t')),
b'\n' if matches!(escapes, Escapes::String | Escapes::CString) => {
Ok(OptByteOrChar::None)
}
b'x' if input.len() >= 2 => {
if matches!(escapes, Escapes::CString) {
let value = hex_digit(input[0])? << 4 | hex_digit(input[1])?;
*input = &input[2..];
Ok(OptByteOrChar::Byte(value))
} else {
let value = oct_digit(input[0])? << 4 | hex_digit(input[1])?;
*input = &input[2..];
Ok(OptByteOrChar::Char(char::from(value)))
}
}
b'u' if input.len() > 2 && input[0] == b'{' => {
*input = &input[1..];
let mut value: u32 = 0;
while !input.is_empty() && input[0] != b'}' {
value = value
.checked_shl(4)
.ok_or(crate::Error::new("invalid unicode escape"))?
| hex_digit(input[0])? as u32;
*input = &input[1..];
}
if input[0] == b'}' {
*input = &input[1..];
Ok(OptByteOrChar::Char(
char::from_u32(value)
.ok_or(crate::Error::new("invalid unicode escape"))?,
))
} else {
Err(crate::Error::new("expected `}`"))
}
}
_ => Err(crate::Error::new("unrecognized character escape")),
}
} else {
Err(crate::Error::new("unexpected end of input after escape"))
}
}
fn parse_char<S: crate::SpanExt>(
input: &mut &[u8],
escapes: Escapes,
) -> Result<OptByteOrChar, crate::Error<S>> {
if !input.is_empty() && input[0] == b'\\' {
let value = parse_char_escape(input, escapes)?;
if matches!(value, OptByteOrChar::Byte(_) | OptByteOrChar::Char(_)) {
Ok(value)
} else if matches!(escapes, Escapes::String | Escapes::CString) {
Ok(OptByteOrChar::None)
} else {
Err(crate::Error::new("unrecognized character escape"))
}
} else if !input.is_empty() {
match input[0] {
value @ 0x00..=0x7f => {
*input = &input[1..];
Ok(OptByteOrChar::Char(char::from(value)))
}
0xc0..=0xdf => {
let value = ((input[0] & 0x1f) as u32) << 6 | (input[1] & 0x3f) as u32;
*input = &input[2..];
Ok(OptByteOrChar::Char(char::from_u32(value).unwrap()))
}
0xe0..=0xef => {
let value = (((input[0] & 0x0f) as u32) << 6 | (input[1] & 0x3f) as u32)
<< 6
| (input[2] & 0x3f) as u32;
*input = &input[3..];
Ok(OptByteOrChar::Char(char::from_u32(value).unwrap()))
}
0xf0..=0xf7 => {
let value = ((((input[0] & 0x07) as u32) << 6 | (input[1] & 0x3f) as u32)
<< 6
| (input[2] & 0x3f) as u32)
<< 6
| (input[3] & 0x3f) as u32;
*input = &input[4..];
Ok(OptByteOrChar::Char(char::from_u32(value).unwrap()))
}
_ => unreachable!(),
}
} else {
Err(crate::Error::new("expected character"))
}
}
match input[0] {
b'\'' => {
if input[input.len() - 1] == b'\'' {
let OptByteOrChar::Char(c) =
parse_char(&mut &input[1..input.len() - 1], Escapes::Char)?
else {
unreachable!()
};
Ok(LiteralValue::Character(CharacterLiteral::new(c)))
} else {
Err(crate::Error::new("unterminated character literal"))
}
}
b'\"' => {
if input[input.len() - 1] == b'\"' {
input = &input[1..input.len() - 1];
let mut s = String::new();
while !input.is_empty() {
if let OptByteOrChar::Char(c) = parse_char(&mut input, Escapes::String)? {
s.push(c);
} else {
while !input.is_empty() && input[0].is_ascii_whitespace() {
input = &input[1..];
}
}
}
Ok(LiteralValue::String(StringLiteral::new(s)))
} else {
Err(crate::Error::new("unterminated string literal"))
}
}
b'r' => {
let mut s = &s[1..];
while let Some(ss) = s.strip_prefix('#') {
s = ss
.strip_suffix('#')
.ok_or(crate::Error::new("unmatched `#` in raw string literal"))?;
}
let s = s
.strip_prefix('"')
.and_then(|s| s.strip_suffix('"'))
.ok_or(crate::Error::new("unterminated raw string literal"))?;
Ok(LiteralValue::String(StringLiteral::new(s.to_owned())))
}
b'b' => {
input = &input[1..];
if !input.is_empty() {
match input[0] {
b'\'' => {
if input.len() > 1 && input[input.len() - 1] == b'\'' {
Ok(LiteralValue::ByteCharacter(ByteCharacterLiteral::new(
parse_byte(&mut &input[1..input.len() - 1], Escapes::Char)?
.unwrap(),
)))
} else {
Err(crate::Error::new("unterminated byte character literal"))
}
}
b'\"' => {
if input.len() > 1 && input[input.len() - 1] == b'\"' {
input = &input[1..input.len() - 1];
let mut s = Vec::new();
while !input.is_empty() {
if let Some(c) = parse_byte(&mut input, Escapes::String)? {
s.push(c);
} else {
while !input.is_empty() && input[0].is_ascii_whitespace() {
input = &input[1..];
}
}
}
Ok(LiteralValue::ByteString(ByteStringLiteral::new(s)))
} else {
Err(crate::Error::new("unterminated byte string literal"))
}
}
b'r' => {
input = &input[1..];
while input.len() > 1
&& input[0] == b'#'
&& input[input.len() - 1] == b'#'
{
input = &input[1..input.len() - 1];
}
if input.len() > 1 && input[0] == b'"' && input[input.len() - 1] == b'"'
{
Ok(LiteralValue::ByteString(ByteStringLiteral::new(
input[1..input.len() - 1].to_owned(),
)))
} else {
Err(crate::Error::new("unterminated raw byte string literal"))
}
}
_ => Err(crate::Error::new("unrecognized literal prefix")),
}
} else {
Err(crate::Error::new("unexpected end of input after `b`"))
}
}
b'c' => {
input = &input[1..];
if !input.is_empty() {
match input[0] {
b'\"' => {
if input.len() > 1 && input[input.len() - 1] == b'\"' {
input = &input[1..input.len() - 1];
let mut sch = String::new();
let mut bytes = Vec::new();
while !input.is_empty() {
match parse_char(&mut input, Escapes::CString)? {
OptByteOrChar::Byte(b) => bytes.push(b),
OptByteOrChar::Char(c) => {
sch.clear();
sch.push(c);
for &byte in sch.as_bytes() {
bytes.push(byte);
}
}
OptByteOrChar::None => {
while !input.is_empty()
&& input[0].is_ascii_whitespace()
{
input = &input[1..];
}
}
}
}
bytes.push(0);
Ok(LiteralValue::CString(CStringLiteral::new(
ffi::CString::from_vec_with_nul(bytes).map_err(|_| {
crate::Error::new("null byte in c string literal")
})?,
)))
} else {
Err(crate::Error::new("unterminated c string literal"))
}
}
b'r' => {
input = &input[1..];
while input.len() > 1
&& input[0] == b'#'
&& input[input.len() - 1] == b'#'
{
input = &input[1..input.len() - 1];
}
if input.len() > 1 && input[0] == b'"' && input[input.len() - 1] == b'"'
{
let mut bytes = input[1..input.len() - 1].to_owned();
bytes.push(0);
Ok(LiteralValue::CString(CStringLiteral::new(
ffi::CString::from_vec_with_nul(bytes).map_err(|_| {
crate::Error::new("null byte in raw c string literal")
})?,
)))
} else {
Err(crate::Error::new("unterminated raw c string literal"))
}
}
_ => Err(crate::Error::new("unrecognized literal prefix")),
}
} else {
Err(crate::Error::new("unexpected end of input after `c`"))
}
}
b'0'..=b'9' => {
if input[0] == b'0' && input.len() > 1 {
match input[1] {
b'b' | b'B' => {
let mut input = &input[2..];
let suffix = parse_suffix(&mut input, true);
if !input.is_empty() {
let mut value: u128 = bin_digit(input[0])?.into();
for &digit in &input[1..] {
if digit != b'_' {
value = value
.checked_shl(1)
.ok_or(crate::Error::new("literal value overflow"))?
| bin_digit(digit)? as u128;
}
}
return from_int(value, suffix);
} else {
return Err(crate::Error::new("missing value after `0b` prefix"));
}
}
b'o' | b'O' => {
let mut input = &input[2..];
let suffix = parse_suffix(&mut input, true);
if !input.is_empty() {
let mut value: u128 = oct_digit(input[0])?.into();
for &digit in &input[1..] {
if digit != b'_' {
value = value
.checked_shl(3)
.ok_or(crate::Error::new("literal value overflow"))?
| oct_digit(digit)? as u128;
}
}
return from_int(value, suffix);
} else {
return Err(crate::Error::new("missing value after `0o` prefix"));
}
}
b'x' | b'X' => {
let mut input = &input[2..];
let suffix = parse_suffix(&mut input, false);
if !input.is_empty() {
let mut value: u128 = hex_digit(input[0])?.into();
for &digit in &input[1..] {
if digit != b'_' {
value = value
.checked_shl(4)
.ok_or(crate::Error::new("literal value overflow"))?
| hex_digit(digit)? as u128;
}
}
return from_int(value, suffix);
} else {
return Err(crate::Error::new("missing value after `0x` prefix"));
}
}
_ => (),
}
}
let suffix = parse_suffix(&mut input, true);
let mut is_float = false;
let s: String = input
.iter()
.filter_map(|&b| {
if matches!(b, b'.' | b'e' | b'E' | b'+' | b'-') {
is_float = true;
}
if b != b'_' {
Some(char::from(b))
} else {
None
}
})
.collect();
if is_float {
if suffix == b"f32" {
let value: f32 = s
.parse()
.map_err(|_| crate::Error::new("failed to parse f32"))?;
Ok(LiteralValue::F32(F32Literal::new(value)))
} else {
let value: f64 = s
.parse()
.map_err(|_| crate::Error::new("failed to parse f64"))?;
if suffix == b"f64" {
Ok(LiteralValue::F64(F64Literal::new(value)))
} else {
Ok(LiteralValue::Float(FloatLiteral::new(value)))
}
}
} else {
from_int(
s.parse()
.map_err(|_| crate::Error::new("failed to parse u128"))?,
suffix,
)
}
}
_ => Err(crate::Error::new("unrecognized literal")),
}
}
}
#[cfg(feature = "literal-value")]
impl<T: crate::TokenTreeExt> Parse<T> for LiteralValue<T::Span> {
#[inline]
fn parse(buf: &mut &crate::TokenBuf<T>) -> Result<Self, crate::Error<T::Span>> {
T::Literal::parse(buf).map(|x| x.into())
}
}
#[cfg(feature = "literal-value")]
impl<T: crate::TokenTreeExt> crate::IntoTokens<T> for LiteralValue<T::Span> {
#[inline]
fn into_tokens(self) -> impl Iterator<Item = T> {
T::Literal::from(self).into_tokens()
}
}
#[cfg(feature = "literal-value")]
impl<T: crate::TokenStreamExt> crate::ToTokenStream<T> for LiteralValue<T::Span> {
#[inline]
fn extend_token_stream(&self, token_stream: &mut T) {
token_stream.extend([T::TokenTree::from(T::Literal::from(self.clone()))])
}
}
macro_rules! def_literal_tokens {
($($(#[$attr:meta])* $ident:ident: $variant:ident: $t:ty),* $(,)?) => { $(
#[cfg(feature = "literal-value")]
$( #[$attr] )*
#[derive(Clone, Debug)]
pub struct $ident<S: crate::Span> {
value: $t,
span: S,
}
#[cfg(feature = "literal-value")]
impl<S: crate::Span> $ident<S> {
#[doc = concat!("Create a new `", stringify!($ident), "`.")]
#[inline]
pub fn new(value: $t) -> Self {
Self {
value,
span: S::call_site(),
}
}
#[doc = concat!("Create a new `", stringify!($ident), "` with a custom span.")]
#[inline]
pub const fn with_span(value: $t, span: S) -> Self {
Self { value, span }
}
#[inline]
pub const fn value(&self) -> &$t {
&self.value
}
#[inline]
pub fn value_mut(&mut self) -> &mut $t {
&mut self.value
}
pub fn into_value(self) -> $t {
self.value
}
#[inline]
pub const fn span(&self) -> S {
self.span
}
#[inline]
pub fn set_span(&mut self, span: S) {
self.span = span;
}
}
#[cfg(feature = "literal-value")]
impl<S: crate::SpanExt> TryFrom<LiteralValue<S>> for $ident<S> {
type Error = crate::Error<S>;
#[inline]
fn try_from(value: LiteralValue<S>) -> Result<Self, Self::Error> {
if let LiteralValue::$variant(value) = value {
Ok(value)
} else {
Err(crate::Error::new("type mismatch"))
}
}
}
#[cfg(feature = "literal-value")]
impl<S: crate::SpanExt> From<$ident<S>> for LiteralValue<S> {
#[inline]
fn from(value: $ident<S>) -> Self {
LiteralValue::$variant(value)
}
}
#[cfg(all(feature = "proc-macro", feature = "literal-value"))]
impl TryFrom<proc_macro::Literal> for $ident<proc_macro::Span> {
type Error = crate::Error<proc_macro::Span>;
#[inline]
fn try_from(value: proc_macro::Literal) -> Result<Self, Self::Error> {
LiteralValue::from(value).try_into()
}
}
#[cfg(all(feature = "proc-macro2", feature = "literal-value"))]
impl TryFrom<proc_macro2::Literal> for $ident<proc_macro2::Span> {
type Error = crate::Error<proc_macro2::Span>;
#[inline]
fn try_from(value: proc_macro2::Literal) -> Result<Self, Self::Error> {
LiteralValue::from(value).try_into()
}
}
#[cfg(all(feature = "proc-macro", feature = "literal-value"))]
impl From<$ident<proc_macro::Span>> for proc_macro::Literal {
#[inline]
fn from(value: $ident<proc_macro::Span>) -> Self {
LiteralValue::from(value).into()
}
}
#[cfg(all(feature = "proc-macro2", feature = "literal-value"))]
impl From<$ident<proc_macro2::Span>> for proc_macro2::Literal {
#[inline]
fn from(value: $ident<proc_macro2::Span>) -> Self {
LiteralValue::from(value).into()
}
}
#[cfg(feature = "literal-value")]
impl<T: crate::TokenTreeExt> Parse<T> for $ident<T::Span> {
#[inline]
fn parse(buf: &mut &crate::TokenBuf<T>) -> Result<Self, crate::Error<T::Span>> {
let mut buf2 = *buf;
if let Ok(token) = LiteralValue::parse(&mut buf2)
.map_err(|mut e| { e.set_message(concat!("expected ", stringify!($ident))); e })?
.try_into()
{
*buf = buf2;
Ok(token)
} else {
Err(buf.error(concat!("expected ", stringify!($ident))))
}
}
}
#[cfg(feature = "literal-value")]
impl<T: crate::TokenTreeExt> crate::IntoTokens<T> for $ident<T::Span>
where LiteralValue<T::Span>: crate::IntoTokens<T> {
#[inline]
fn into_tokens(self) -> impl Iterator<Item = T> {
LiteralValue::$variant(self).into_tokens()
}
}
#[cfg(feature = "literal-value")]
impl<T: crate::TokenStreamExt> crate::ToTokenStream<T> for $ident<T::Span> {
#[inline]
fn extend_token_stream(&self, token_stream: &mut T) {
LiteralValue::$variant(self.clone()).extend_token_stream(token_stream);
}
}
)* };
}
def_literal_tokens! {
StringLiteral: String: String,
ByteStringLiteral: ByteString: Vec<u8>,
CStringLiteral: CString: ffi::CString,
CharacterLiteral: Character: char,
ByteCharacterLiteral: ByteCharacter: u8,
IntLiteral: Int: u128,
FloatLiteral: Float: f64,
I8Literal: I8: i8,
I16Literal: I16: i16,
I32Literal: I32: i32,
I64Literal: I64: i64,
I128Literal: I128: i128,
IsizeLiteral: Isize: isize,
U8Literal: U8: u8,
U16Literal: U16: u16,
U32Literal: U32: u32,
U64Literal: U64: u64,
U128Literal: U128: u128,
UsizeLiteral: Usize: usize,
F32Literal: F32: f32,
F64Literal: F64: f64,
}
macro_rules! def {
($([$what:tt] $($id:ident: $t:ty),* $(,)?)*) => { $(
$( def!(@ $what $id: $t); )*
)* };
(@ suffixed_int $ident:ident: $t:ty) => {
fn $ident(n: $t) -> Self;
};
(@ unsuffixed_int $ident:ident: $t:ty) => {
fn $ident(n: $t) -> Self;
};
(@ suffixed_float $ident:ident: $t:ty) => {
fn $ident(n: $t) -> Self;
};
(@ unsuffixed_float $ident:ident: $t:ty) => {
fn $ident(n: $t) -> Self;
};
}
pub trait Literal: ProcMacro<Literal = Self> + Display + FromStr {
def! {
[suffixed_int]
i8_suffixed: i8,
i16_suffixed: i16,
i32_suffixed: i32,
i64_suffixed: i64,
i128_suffixed: i128,
isize_suffixed: isize,
u8_suffixed: u8,
u16_suffixed: u16,
u32_suffixed: u32,
u64_suffixed: u64,
u128_suffixed: u128,
usize_suffixed: usize,
[unsuffixed_int]
i8_unsuffixed: i8,
i16_unsuffixed: i16,
i32_unsuffixed: i32,
i64_unsuffixed: i64,
i128_unsuffixed: i128,
isize_unsuffixed: isize,
u8_unsuffixed: u8,
u16_unsuffixed: u16,
u32_unsuffixed: u32,
u64_unsuffixed: u64,
u128_unsuffixed: u128,
usize_unsuffixed: usize,
[suffixed_float]
f32_suffixed: f32,
f64_suffixed: f64,
[unsuffixed_float]
f32_unsuffixed: f32,
f64_unsuffixed: f64,
}
fn string(str: &str) -> Self;
fn character(c: char) -> Self;
fn byte_character(b: u8) -> Self;
fn byte_string(bytes: &[u8]) -> Self;
fn c_string(str: &ffi::CStr) -> Self;
fn span(&self) -> Self::Span;
fn set_span(&mut self, span: Self::Span);
}
#[cfg(not(feature = "literal-value"))]
pub trait LiteralExt:
ProcMacroExt<LiteralExt = Self>
+ Literal
+ Parse<Self::TokenTree>
+ IntoTokens<Self::TokenTree>
+ crate::ToTokens<Self::TokenTree>
+ ToTokenStream<Self::TokenStream>
{
}
#[cfg(feature = "literal-value")]
pub trait LiteralExt:
ProcMacroExt<LiteralExt = Self>
+ Literal
+ From<LiteralValue<Self::Span>>
+ From<StringLiteral<Self::Span>>
+ From<ByteStringLiteral<Self::Span>>
+ From<CharacterLiteral<Self::Span>>
+ From<ByteCharacterLiteral<Self::Span>>
+ From<IntLiteral<Self::Span>>
+ From<FloatLiteral<Self::Span>>
+ From<I8Literal<Self::Span>>
+ From<I16Literal<Self::Span>>
+ From<I32Literal<Self::Span>>
+ From<I64Literal<Self::Span>>
+ From<I128Literal<Self::Span>>
+ From<IsizeLiteral<Self::Span>>
+ From<U8Literal<Self::Span>>
+ From<U16Literal<Self::Span>>
+ From<U32Literal<Self::Span>>
+ From<U64Literal<Self::Span>>
+ From<U128Literal<Self::Span>>
+ From<UsizeLiteral<Self::Span>>
+ From<F32Literal<Self::Span>>
+ From<F64Literal<Self::Span>>
+ Into<LiteralValue<Self::Span>>
+ TryInto<StringLiteral<Self::Span>>
+ TryInto<ByteStringLiteral<Self::Span>>
+ TryInto<CharacterLiteral<Self::Span>>
+ TryInto<ByteCharacterLiteral<Self::Span>>
+ TryInto<IntLiteral<Self::Span>>
+ TryInto<FloatLiteral<Self::Span>>
+ TryInto<I8Literal<Self::Span>>
+ TryInto<I16Literal<Self::Span>>
+ TryInto<I32Literal<Self::Span>>
+ TryInto<I64Literal<Self::Span>>
+ TryInto<I128Literal<Self::Span>>
+ TryInto<IsizeLiteral<Self::Span>>
+ TryInto<U8Literal<Self::Span>>
+ TryInto<U16Literal<Self::Span>>
+ TryInto<U32Literal<Self::Span>>
+ TryInto<U64Literal<Self::Span>>
+ TryInto<U128Literal<Self::Span>>
+ TryInto<UsizeLiteral<Self::Span>>
+ TryInto<F32Literal<Self::Span>>
+ TryInto<F64Literal<Self::Span>>
+ Parse<Self::TokenTree>
+ IntoTokens<Self::TokenTree>
+ crate::ToTokens<Self::TokenTree>
+ ToTokenStream<Self::TokenStream>
{
fn to_value(&self) -> LiteralValue<Self::Span>;
}
macro_rules! impl_literal {
($($pm:ident: $feature:literal),*) => { $(
#[cfg(all(feature = $feature, feature = "literal-value"))]
impl From<$pm::Literal> for LiteralValue<$pm::Span> {
#[inline]
fn from(value: $pm::Literal) -> Self {
value.to_value()
}
}
#[cfg(all(feature = $feature, feature = "literal-value"))]
impl From<LiteralValue<$pm::Span>> for $pm::Literal {
#[inline]
fn from(value: LiteralValue<$pm::Span>) -> Self {
let (mut lit, span) = match value {
LiteralValue::String(t) => ($pm::Literal::string(t.value()), t.span()),
LiteralValue::ByteString(t) => ($pm::Literal::byte_string(t.value()), t.span()),
LiteralValue::CString(t) => (<$pm::Literal as Literal>::c_string(t.value()), t.span()),
LiteralValue::Character(t) => ($pm::Literal::character(*t.value()), t.span()),
LiteralValue::ByteCharacter(t) => (<$pm::Literal as Literal>::byte_character(*t.value()), t.span()),
LiteralValue::Int(t) => ($pm::Literal::u128_unsuffixed(*t.value()), t.span()),
LiteralValue::Float(t) => ($pm::Literal::f64_unsuffixed(*t.value()), t.span()),
LiteralValue::I8(t) => ($pm::Literal::i8_suffixed(*t.value()), t.span()),
LiteralValue::I16(t) => ($pm::Literal::i16_suffixed(*t.value()), t.span()),
LiteralValue::I32(t) => ($pm::Literal::i32_suffixed(*t.value()), t.span()),
LiteralValue::I64(t) => ($pm::Literal::i64_suffixed(*t.value()), t.span()),
LiteralValue::I128(t) => ($pm::Literal::i128_suffixed(*t.value()), t.span()),
LiteralValue::Isize(t) => ($pm::Literal::isize_suffixed(*t.value()), t.span()),
LiteralValue::U8(t) => ($pm::Literal::u8_suffixed(*t.value()), t.span()),
LiteralValue::U16(t) => ($pm::Literal::u16_suffixed(*t.value()), t.span()),
LiteralValue::U32(t) => ($pm::Literal::u32_suffixed(*t.value()), t.span()),
LiteralValue::U64(t) => ($pm::Literal::u64_suffixed(*t.value()), t.span()),
LiteralValue::U128(t) => ($pm::Literal::u128_suffixed(*t.value()), t.span()),
LiteralValue::Usize(t) => ($pm::Literal::usize_suffixed(*t.value()), t.span()),
LiteralValue::F32(t) => ($pm::Literal::f32_suffixed(*t.value()), t.span()),
LiteralValue::F64(t) => ($pm::Literal::f64_suffixed(*t.value()), t.span()),
};
lit.set_span(span);
lit
}
}
#[cfg(feature = $feature)]
impl Literal for $pm::Literal {
impl_literal! { @ $pm
i8_suffixed: n: i8,
i16_suffixed: n: i16,
i32_suffixed: n: i32,
i64_suffixed: n: i64,
i128_suffixed: n: i128,
isize_suffixed: n: isize,
u8_suffixed: n: u8,
u16_suffixed: n: u16,
u32_suffixed: n: u32,
u64_suffixed: n: u64,
u128_suffixed: n: u128,
usize_suffixed: n: usize,
i8_unsuffixed: n: i8,
i16_unsuffixed: n: i16,
i32_unsuffixed: n: i32,
i64_unsuffixed: n: i64,
i128_unsuffixed: n: i128,
isize_unsuffixed: n: isize,
u8_unsuffixed: n: u8,
u16_unsuffixed: n: u16,
u32_unsuffixed: n: u32,
u64_unsuffixed: n: u64,
u128_unsuffixed: n: u128,
usize_unsuffixed: n: usize,
f32_unsuffixed: n: f32,
f32_suffixed: n: f32,
f64_unsuffixed: n: f64,
f64_suffixed: n: f64,
string: str: &str,
character: c: char,
byte_string: bytes: &[u8],
}
#[inline]
fn byte_character(b: u8) -> Self {
format!("b'\\x{b:02x}'").parse().unwrap()
}
#[inline]
fn c_string(str: &ffi::CStr) -> Self {
let mut src = String::from("c\"");
for b in str.to_bytes() {
src.push_str(&format!("\\x{b:02x}"));
}
src.push_str("\"");
src.parse().unwrap()
}
#[inline]
fn span(&self) -> Self::Span {
self.span()
}
#[inline]
fn set_span(&mut self, span: Self::Span) {
self.set_span(span)
}
}
#[cfg(feature = $feature)]
impl LiteralExt for $pm::Literal {
#[cfg(feature = "literal-value")]
#[inline]
fn to_value(&self) -> LiteralValue<$pm::Span> {
self.to_string().parse().unwrap()
}
}
#[cfg(feature = $feature)]
impl Parse<$pm::TokenTree> for $pm::Literal {
#[inline]
fn parse(buf: &mut &crate::TokenBuf<$pm::TokenTree>) -> Result<Self, crate::Error<$pm::Span>> {
buf.parse_prefix(|token| {
if let $pm::TokenTree::Literal(t) = token {
crate::Match::Complete(t.clone())
} else {
crate::Match::NoMatch
}
}).map_err(|mut e|{ e.set_message("expected literal"); e })
}
}
#[cfg(feature = $feature)]
impl crate::IntoTokens<$pm::TokenTree> for $pm::Literal {
#[inline]
fn into_tokens(self) -> impl Iterator<Item = $pm::TokenTree> {
std::iter::once($pm::TokenTree::Literal(self))
}
}
#[cfg(feature = $feature)]
impl crate::ToTokenStream<$pm::TokenStream> for $pm::Literal {
#[inline]
fn extend_token_stream(&self, token_stream: &mut $pm::TokenStream) {
token_stream.extend([$pm::TokenTree::from(self.clone())]);
}
}
)* };
(@ $pm:ident $($id:ident: $arg:ident: $t:ty),* $(,)?) => { $(
#[inline]
fn $id($arg: $t) -> Self {
$pm::Literal::$id($arg)
}
)* };
(@ to_literal($value:expr)) => {
impl_literal!(@ to_literal($value) for
I8: i8_suffixed,
I16: i16_suffixed,
I32: i32_suffixed,
I64: i64_suffixed,
I128: i128_suffixed,
Isize: isize_suffixed,
U8: u8_suffixed,
U16: u16_suffixed,
U32: u32_suffixed,
U64: u64_suffixed,
U128: u128_suffixed,
Usize: usize_suffixed,
F32: f32_suffixed,
F64: f64_suffixed,
)
};
(@ to_literal($value:expr) for $($id:ident: $suffixed:ident),* $(,)?) => {
match $value {
LiteralValue::String(s) => Self::string(&s),
LiteralValue::ByteString(bytes) => Self::byte_string(&bytes),
LiteralValue::CString(s) => <Self as Literal>::c_string(&s),
LiteralValue::Character(c) => Self::character(c),
LiteralValue::ByteCharacter(b) => <Self as Literal>::byte_character(b),
LiteralValue::Int(value) => Self::u128_unsuffixed(value),
LiteralValue::Float(value) => Self::f64_unsuffixed(value),
$( LiteralValue::Suffixed(Suffixed::$id(value)) => Self::$suffixed(value), )*
}
};
}
impl_literal!(proc_macro: "proc-macro", proc_macro2: "proc-macro2");