use syn::{Expr, GenericArgument, Ident, PathArguments, Type, parse_quote};
pub trait TypeExt {
fn ident(&self) -> Option<&Ident>;
fn to_option(&self) -> Type;
fn is_option_of(&self, ident: &str) -> bool;
fn is(&self, ident: &str) -> bool;
}
impl TypeExt for Type {
fn ident(&self) -> Option<&Ident> {
match self {
Type::Path(type_path) => type_path.path.segments.last().map(|segment| &segment.ident),
_ => None,
}
}
fn to_option(&self) -> Type {
if self.is("Option") {
self.clone()
} else {
parse_quote! { Option<#self> }
}
}
fn is_option_of(&self, ident: &str) -> bool {
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.is(ident)
} else {
false
}
}
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
}
}
}
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,
}
}
}