use proc_macro2::Ident;
use quote::quote;
use syn::punctuated::Punctuated;
use syn::token::{And, Comma, Mut};
use syn::{FnArg, ItemFn, Pat, Type, TypePath};
use crate::internals::ctx::Context;
pub(crate) struct FnVariable<'a> {
pub(crate) arg: &'a FnArg,
pub(crate) ident: &'a Ident,
pub(crate) path: &'a TypePath,
pub(crate) and_token: Option<And>,
pub(crate) mutability: Option<Mut>,
}
impl<'a> FnVariable<'a> {
pub(crate) fn from_fn_args(
ctx: &Context,
args: &'a Punctuated<FnArg, Comma>,
) -> Punctuated<FnVariable<'a>, Comma> {
let mut vars: Punctuated<FnVariable, Comma> = Punctuated::new();
for arg in args {
match arg {
FnArg::Receiver(_) => continue,
FnArg::Typed(ty) => {
let ident = match ty.pat.as_ref() {
Pat::Ident(ident) => ident,
_ => continue,
};
let (path, mutability, and_token) = match ty.ty.as_ref() {
Type::Reference(ty_ref) => {
if let Type::Path(ty_path) = &*ty_ref.elem {
(ty_path, ty_ref.mutability, Some(ty_ref.and_token))
} else {
let msg =
format!("unexpected function argument type {}", quote! {#ty});
ctx.error_spanned_by(ty, msg);
continue;
}
}
Type::Path(ty_path) => (ty_path, ident.mutability, None),
_ => {
let msg = format!("unexpected function argument type {}", quote! {#ty});
ctx.error_spanned_by(ty, msg);
continue;
}
};
vars.push(FnVariable {
arg,
ident: &ident.ident,
path,
and_token,
mutability,
});
}
}
}
vars
}
}
pub(crate) fn ockam_context_variable_from_input_fn<'a>(
ctx: &Context,
input_fn: &'a ItemFn,
) -> Option<FnVariable<'a>> {
FnVariable::from_fn_args(ctx, &input_fn.sig.inputs)
.into_iter()
.find(|var| match var.path.path.segments.last() {
None => false,
Some(seg) => seg.ident.to_string().eq("Context"),
})
}