use std::{
ffi::{CStr, CString},
rc::Rc,
sync::Arc,
};
use syn::{
LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitInt, LitStr, Token, parenthesized,
token::Bracket,
};
pub use syn::{Result, parse::ParseStream};
#[cfg(feature = "macros")]
pub use ::tanager_macros::Parse;
pub trait Parse
where
Self: Sized,
{
fn parse(input: ParseStream<'_>) -> crate::Result<Self>;
#[inline]
fn parse_without_container(input: ParseStream<'_>) -> crate::Result<Self> {
Self::parse(input)
}
#[doc(hidden)]
#[inline]
fn parse_seq(input: ParseStream<'_>) -> crate::Result<Vec<Self>> {
let inner;
syn::bracketed!(inner in input);
inner.call(|x| Self::parse_seq_without_container(x))
}
#[doc(hidden)]
#[inline]
fn parse_seq_without_container(input: ParseStream<'_>) -> crate::Result<Vec<Self>> {
Ok(input
.parse_terminated(Self::parse, Token![,])?
.into_iter()
.collect())
}
}
impl Parse for u8 {
#[inline]
fn parse(input: ParseStream<'_>) -> crate::Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(LitInt) {
input.parse::<LitInt>().and_then(|x| x.base10_parse())
} else if lookahead.peek(LitByte) {
input.parse::<LitByte>().map(|x| x.value())
} else {
Err(lookahead.error())
}
}
fn parse_seq(input: ParseStream<'_>) -> crate::Result<Vec<Self>> {
let lookahead = input.lookahead1();
if lookahead.peek(LitByteStr) {
input.parse::<LitByteStr>().map(|x| x.value())
} else if lookahead.peek(Bracket) {
let inner;
syn::bracketed!(inner in input);
Ok(inner
.parse_terminated(Self::parse, Token![,])?
.into_iter()
.collect())
} else {
Err(lookahead.error())
}
}
fn parse_seq_without_container(input: ParseStream<'_>) -> crate::Result<Vec<Self>> {
let lookahead = input.lookahead1();
if lookahead.peek(LitByteStr) {
input.parse::<LitByteStr>().map(|x| x.value())
} else if lookahead.peek(Bracket) {
Ok(input
.parse_terminated(Self::parse, Token![,])?
.into_iter()
.collect())
} else {
Err(lookahead.error())
}
}
}
macro_rules! impl_integer {
($ty:ty) => {
impl Parse for $ty {
#[inline]
fn parse(input: ParseStream<'_>) -> crate::Result<Self> {
input.parse::<LitInt>().and_then(|x| x.base10_parse())
}
}
};
}
impl_integer!(usize);
impl_integer!(isize);
impl_integer!(i8);
impl_integer!(u16);
impl_integer!(i16);
impl_integer!(u32);
impl_integer!(i32);
impl_integer!(u64);
impl_integer!(i64);
impl_integer!(u128);
impl_integer!(i128);
macro_rules! impl_float {
($ty:ty) => {
impl Parse for $ty {
#[inline]
fn parse(input: ParseStream<'_>) -> crate::Result<Self> {
input.parse::<LitFloat>().and_then(|x| x.base10_parse())
}
}
};
}
impl_float!(f32);
impl_float!(f64);
macro_rules! impl_generic {
($lit:ty as $ty:ty) => {
impl Parse for $ty {
#[inline]
fn parse(input: ParseStream<'_>) -> crate::Result<Self> {
input.parse::<$lit>().map(|x| x.value().into())
}
}
};
}
impl_generic!(LitBool as bool);
impl_generic!(LitChar as char);
impl_generic!(LitStr as String);
impl_generic!(LitStr as Box<str>);
impl_generic!(LitStr as Rc<str>);
impl_generic!(LitStr as Arc<str>);
impl_generic!(LitCStr as CString);
impl_generic!(LitCStr as Box<CStr>);
impl_generic!(LitCStr as Rc<CStr>);
impl_generic!(LitCStr as Arc<CStr>);
macro_rules! impl_seq {
($ty:ty) => {
impl<T> Parse for $ty
where
T: Parse,
{
#[inline]
fn parse(input: ParseStream<'_>) -> crate::Result<Self> {
T::parse_seq(input).map(|x| x.into())
}
#[inline]
fn parse_without_container(input: ParseStream<'_>) -> crate::Result<Self> {
T::parse_seq_without_container(input).map(|x| x.into())
}
}
};
}
impl_seq!(Vec<T>);
impl_seq!(Box<[T]>);
impl_seq!(Rc<[T]>);
impl_seq!(Arc<[T]>);
impl<T> Parse for Option<T>
where
T: Parse,
{
fn parse(input: ParseStream<'_>) -> crate::Result<Self> {
mod kw {
syn::custom_keyword!(None);
syn::custom_keyword!(Some);
}
let lookahead = input.lookahead1();
if lookahead.peek(kw::Some) {
let _ = input.parse::<kw::Some>()?;
let inner;
parenthesized!(inner in input);
Ok(Some(inner.call(T::parse)?))
} else if lookahead.peek(kw::None) {
let _ = input.parse::<kw::None>()?;
Ok(None)
} else {
Err(lookahead.error())
}
}
}
#[inline]
pub fn parse<T>(tokens: proc_macro2::TokenStream) -> syn::Result<T>
where
T: Parse,
{
struct Parser<T>(T);
impl<T> syn::parse::Parse for Parser<T>
where
T: Parse,
{
#[inline]
fn parse(input: ParseStream) -> Result<Self> {
input.call(|x| T::parse(x)).map(|x| Self(x))
}
}
syn::parse2::<Parser<T>>(tokens).map(|x| x.0)
}
#[inline]
pub fn parse_without_container<T>(tokens: proc_macro2::TokenStream) -> syn::Result<T>
where
T: Parse,
{
struct Parser<T>(T);
impl<T> syn::parse::Parse for Parser<T>
where
T: Parse,
{
#[inline]
fn parse(input: ParseStream) -> Result<Self> {
input
.call(|x| T::parse_without_container(x))
.map(|x| Self(x))
}
}
syn::parse2::<Parser<T>>(tokens).map(|x| x.0)
}
#[cfg(feature = "macros")]
#[doc(hidden)]
pub mod __macro {
pub use ::std::format;
pub use ::tanager_macros::Parse;
pub use syn;
}