use quote::ToTokens;
pub(crate) type TypeType = syn::Type;
pub(crate) type XcoderType = XcoderLike;
#[derive(Debug, Clone)]
pub(crate) enum XcoderLike {
Path(syn::Path),
Expr(syn::Expr),
Macro(syn::Macro),
}
impl syn::parse::Parse for XcoderLike {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let lookahead = input.lookahead1();
let fork = input.fork();
if fork.parse::<syn::Path>().is_ok() && fork.peek(syn::Token![!]) {
let mcro: syn::Macro = input.parse()?;
return Ok(XcoderLike::Macro(mcro));
}
drop(fork);
if input.peek(syn::token::Paren)
|| input.peek(syn::token::Brace)
|| input.peek(syn::Token![if])
|| input.peek(syn::Token![match])
{
if let Ok(x) = input.parse::<syn::Expr>() {
return Ok(XcoderLike::Expr(x));
}
}
if let Ok(x) = input.parse::<syn::Path>() {
return Ok(XcoderLike::Path(x));
}
Err(lookahead.error())
}
}
impl ToTokens for XcoderLike {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
match self {
XcoderLike::Path(path) => path.to_tokens(tokens),
XcoderLike::Macro(mcro) => mcro.to_tokens(tokens),
XcoderLike::Expr(expr) => expr.to_tokens(tokens),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum XcoderSigil {
None,
Ref,
Deref,
}
#[derive(Debug, Clone)]
pub(crate) struct SiguledXcoder {
pub(crate) sigil: XcoderSigil,
pub(crate) inner: XcoderLike,
}
impl syn::parse::Parse for SiguledXcoder {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let sigil = if input.peek(syn::Token![&]) {
let _: syn::Token![&] = input.parse()?;
XcoderSigil::Ref
} else if input.peek(syn::Token![*]) {
let _: syn::Token![*] = input.parse()?;
XcoderSigil::Deref
} else {
XcoderSigil::None
};
let inner: XcoderLike = input.parse()?;
Ok(SiguledXcoder { sigil, inner })
}
}
impl ToTokens for SiguledXcoder {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
match &self.inner {
XcoderLike::Path(path) => path.to_tokens(tokens),
XcoderLike::Macro(mcro) => mcro.to_tokens(tokens),
XcoderLike::Expr(expr) => expr.to_tokens(tokens),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct LatebindXcoder {
pub(crate) is_mut: bool,
pub(crate) inner: XcoderLike,
}
#[derive(Debug, Clone)]
pub(crate) enum DefaultValue {
Call,
Expr(syn::Expr),
}
impl syn::parse::Parse for LatebindXcoder {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let is_mut = if input.peek(syn::Token![&]) && input.peek2(syn::Token![mut]) {
let _: syn::Token![&] = input.parse()?;
let _: syn::Token![mut] = input.parse()?;
true
} else if input.peek(syn::Token![&]) {
return Err(input.error(
"`&` without `mut` on `latebind` is invalid: use `latebind = path` \
(consuming, Fn(T) -> U) or `latebind = &mut path` (mutating, Fn(&mut T))",
));
} else {
false
};
let inner: XcoderLike = input.parse()?;
Ok(LatebindXcoder { is_mut, inner })
}
}