use syn::{
FnArg, GenericArgument, ImplItemMethod, Pat, PatIdent, PatType, PathArguments, Receiver, Type,
TypePath, TypeReference,
};
pub fn is_method_mutable(method: &ImplItemMethod) -> bool {
match method.sig.inputs.first() {
Some(FnArg::Receiver(Receiver { mutability, .. })) => mutability.is_some(),
Some(FnArg::Typed(PatType { ty, pat, .. })) => {
if let Pat::Ident(PatIdent { ident, .. }) = pat.as_ref() {
if ident != "self" {
return false;
}
}
if let Type::Path(TypePath { path, .. }) = ty.as_ref() {
if !crate::syntax::path::path_compare_str(path, &["Pin"]) {
return false;
}
if let Some(last) = path.segments.last() {
if let PathArguments::AngleBracketed(args) = &last.arguments {
if let Some(GenericArgument::Type(Type::Reference(TypeReference {
mutability: Some(_),
..
}))) = args.args.first()
{
return true;
}
}
}
}
false
}
_ => false,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tests::tokens_to_syn;
use quote::quote;
#[test]
fn test_is_method_mutable_self() {
assert!(!is_method_mutable(&tokens_to_syn(quote! {
fn invokable(&self) {}
})));
assert!(is_method_mutable(&tokens_to_syn(quote! {
fn invokable_with_return_cxx_type(self: Pin<&mut Self>) -> f64 {}
})));
}
#[test]
fn test_is_method_mutable_value() {
assert!(!is_method_mutable(&tokens_to_syn(quote! {
fn invokable(value: T) {}
})));
assert!(!is_method_mutable(&tokens_to_syn(quote! {
fn invokable_with_return_cxx_type(value: Pin<&mut T>) -> f64 {}
})));
assert!(!is_method_mutable(&tokens_to_syn(quote! {
fn invokable_with_return_cxx_type(mut value: T) -> f64 {}
})));
}
}