use proc_macro2::TokenStream;
use quote::{ToTokens, quote};
use syn::{Expr, GenericArgument, Ident, PathArguments, Type, parse_quote};
pub trait IntoTokenStream {
fn into_token_stream(self) -> TokenStream;
}
impl<T, U> IntoTokenStream for T
where
T: Iterator<Item = U>,
U: ToTokens,
{
fn into_token_stream(self) -> TokenStream {
let tokens = self.map(|item| item.to_token_stream());
quote! { #(#tokens)* }
}
}
pub trait TypeExt {
fn is(&self, ident: &str) -> bool;
fn to_option(&self) -> Type;
fn unwrap_option(&self) -> Type;
fn unwrap_all(&self) -> Type;
fn is_unit(&self) -> bool;
}
impl TypeExt for Type {
fn is_unit(&self) -> bool {
matches!(self, Type::Tuple(tuple) if tuple.elems.is_empty())
}
fn is(&self, ident: &str) -> bool {
if let Type::Path(type_path) = self
&& let Some(segment) = type_path.path.segments.last()
&& segment.ident == ident
{
true
} else {
false
}
}
fn to_option(&self) -> Type {
if self.is("Option") {
self.clone()
} else {
parse_quote! { Option<#self> }
}
}
fn unwrap_option(&self) -> Type {
if let Type::Path(type_path) = self
&& let Some(segment) = type_path.path.segments.last()
&& segment.ident == "Option"
&& let PathArguments::AngleBracketed(args) = &segment.arguments
&& let Some(GenericArgument::Type(ty)) = args.args.first()
{
ty.clone()
} else {
self.clone()
}
}
fn unwrap_all(&self) -> Type {
if let Type::Path(type_path) = self
&& let Some(segment) = type_path.path.segments.last()
&& let PathArguments::AngleBracketed(args) = &segment.arguments
&& let Some(GenericArgument::Type(ty)) = args.args.first()
{
ty.unwrap_all()
} else {
self.clone()
}
}
}
pub trait ExprExt {
fn ident(&self) -> Option<&Ident>;
}
impl ExprExt for Expr {
fn ident(&self) -> Option<&Ident> {
match self {
Expr::Path(p) => p.path.get_ident(),
Expr::Assign(a) => match &*a.left {
Expr::Path(p) => p.path.get_ident(),
_ => None,
},
Expr::Call(c) => match &*c.func {
Expr::Path(p) => p.path.get_ident(),
_ => None,
},
_ => None,
}
}
}