use quote::ToTokens;
use syn::{Ident, Lifetime, Type};
#[allow(dead_code)]
#[derive(Clone)]
pub enum ParameterInfo {
SelfRef, ImmutableReference(Box<ParameterInfo>), MutableReference(Box<ParameterInfo>), LifeTime(Lifetime, Box<ParameterInfo>), Typed {
name: Ident, ty: Type, }, }
#[allow(dead_code)]
impl ParameterInfo {
fn inner(&self) -> &ParameterInfo {
match self {
ParameterInfo::ImmutableReference(pi) => pi.inner(),
ParameterInfo::MutableReference(pi) => pi.inner(),
ParameterInfo::SelfRef => self,
ParameterInfo::Typed { name: _, ty: _ } => self,
ParameterInfo::LifeTime(..) => panic!("Recursive Lifetime should not happen"),
}
}
pub fn name(&self) -> String {
match self.inner() {
ParameterInfo::SelfRef => "self".to_string(),
ParameterInfo::Typed { name, ty: _ } => name.to_string(),
_ => panic!("Should have been removed in inner()"),
}
}
pub fn is_self(&self) -> bool {
matches!(self.inner(), ParameterInfo::SelfRef)
}
pub fn get_self_type(&self) -> SelfType {
match self {
ParameterInfo::SelfRef => SelfType::Value,
ParameterInfo::ImmutableReference(inner)
if matches!(**inner, ParameterInfo::SelfRef) =>
{
SelfType::Reference
}
ParameterInfo::MutableReference(inner) if matches!(**inner, ParameterInfo::SelfRef) => {
SelfType::MutableReference
}
_ => panic!("Called get_self_type on non-self parameter"),
}
}
pub fn new_owned(name: &str, ty: syn::Type) -> Self {
ParameterInfo::Typed {
name: syn::Ident::new(name, proc_macro2::Span::call_site()),
ty,
}
}
pub fn new_ref(name: &str, ty: syn::Type) -> Self {
ParameterInfo::ImmutableReference(Box::new(ParameterInfo::Typed {
name: syn::Ident::new(name, proc_macro2::Span::call_site()),
ty,
}))
}
pub fn new_mut_ref(name: &str, ty: syn::Type) -> Self {
ParameterInfo::MutableReference(Box::new(ParameterInfo::Typed {
name: syn::Ident::new(name, proc_macro2::Span::call_site()),
ty,
}))
}
}
pub fn analyze_parameters(sig: &syn::Signature) -> Vec<ParameterInfo> {
sig.inputs
.iter()
.filter_map(|arg| match arg {
syn::FnArg::Receiver(receiver) => {
let kind = if receiver.reference.is_some() {
if receiver.mutability.is_some() {
ParameterInfo::MutableReference(Box::new(ParameterInfo::SelfRef))
} else {
ParameterInfo::ImmutableReference(Box::new(ParameterInfo::SelfRef))
}
} else {
panic!("Self should be passed by reference or not be present")
};
Some(kind)
}
syn::FnArg::Typed(pat_type) => {
if let syn::Pat::Ident(pat_ident) = *pat_type.pat.clone() {
let param_info = ParameterInfo::Typed {
name: pat_ident.ident.clone(),
ty: *pat_type.ty.clone(),
};
let kind = if pat_ident.by_ref.is_some() {
if pat_ident.mutability.is_some() {
ParameterInfo::MutableReference(Box::new(param_info))
} else {
ParameterInfo::ImmutableReference(Box::new(param_info))
}
} else {
param_info
};
Some(kind)
} else {
None
}
}
})
.collect()
}
#[allow(dead_code)]
#[derive(Debug)]
pub enum SelfType {
Value,
Reference,
MutableReference,
}
impl ToTokens for ParameterInfo {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
match self {
ParameterInfo::SelfRef => tokens.extend(quote::quote!(self)),
ParameterInfo::ImmutableReference(inner) => {
tokens.extend(quote::quote!(&));
inner.to_tokens(tokens);
}
ParameterInfo::MutableReference(inner) => {
tokens.extend(quote::quote!(&mut));
inner.to_tokens(tokens);
}
ParameterInfo::LifeTime(lifetime, inner) => {
lifetime.to_tokens(tokens);
tokens.extend(quote::quote!(:));
inner.to_tokens(tokens);
}
ParameterInfo::Typed { name, ty } => {
name.to_tokens(tokens);
tokens.extend(quote::quote!(:));
ty.to_tokens(tokens);
}
}
}
}