use quote::quote;
use syn::{
Attribute, FnArg, ImplItem, ImplItemFn, PatType, Signature, TraitItem, TraitItemFn, Type,
TypeReference, Visibility,
};
pub trait ItemExt {
fn as_fn(&self) -> Option<impl ItemFnExt>;
}
pub trait ItemFnExt {
fn vis(&self) -> Option<&Visibility>;
fn doc(&self) -> impl Iterator<Item = &Attribute>;
fn sig(&self) -> &Signature;
}
impl ItemExt for ImplItem {
fn as_fn(&self) -> Option<impl ItemFnExt> {
match self {
ImplItem::Fn(item_fn) => Some(item_fn),
_ => None,
}
}
}
impl ItemFnExt for &ImplItemFn {
fn vis(&self) -> Option<&Visibility> {
Some(&self.vis)
}
fn doc(&self) -> impl Iterator<Item = &Attribute> {
self.attrs.iter().filter(|attr| attr.path().is_ident("doc"))
}
fn sig(&self) -> &Signature {
&self.sig
}
}
impl ItemExt for TraitItem {
fn as_fn(&self) -> Option<impl ItemFnExt> {
match self {
TraitItem::Fn(item_fn) => Some(item_fn),
_ => None,
}
}
}
impl ItemFnExt for &TraitItemFn {
fn vis(&self) -> Option<&Visibility> {
None
}
fn doc(&self) -> impl Iterator<Item = &Attribute> {
self.attrs.iter().filter(|attr| attr.path().is_ident("doc"))
}
fn sig(&self) -> &Signature {
&self.sig
}
}
pub trait FnArgExt {
fn typed(&self) -> Option<&PatType>;
fn contains(&self, needle: &str) -> bool;
}
pub trait TypeExt {
fn reference(&self) -> Option<&TypeReference>;
fn contains(&self, needle: &str) -> bool;
}
impl FnArgExt for FnArg {
fn typed(&self) -> Option<&PatType> {
match self {
FnArg::Typed(typed) => Some(typed),
_ => None,
}
}
fn contains(&self, needle: &str) -> bool {
let PatType { ty, .. } = match self.typed() {
Some(ty) => ty,
None => return false,
};
match ty.reference() {
Some(ty_ref) => ty_ref.elem.contains(needle),
None => ty.contains(needle),
}
}
}
impl TypeExt for Type {
fn reference(&self) -> Option<&TypeReference> {
match self {
Type::Reference(reference) => Some(reference),
_ => None,
}
}
fn contains(&self, needle: &str) -> bool {
quote! { #self }.to_string().contains(needle)
}
}