pyproto: small refactoring to backend macro
This commit is contained in:
parent
8f4ed55801
commit
d10708abbf
|
@ -52,13 +52,26 @@ pub(crate) fn impl_method_proto(
|
|||
for (i, arg) in meth.args.iter().enumerate() {
|
||||
let idx = if meth.with_self { i + 1 } else { i };
|
||||
let arg_name = syn::Ident::new(arg, Span::call_site());
|
||||
let arg_ty = get_arg_ty(sig, idx)?;
|
||||
|
||||
let input = match &mut sig.inputs[idx] {
|
||||
syn::FnArg::Typed(input) => input,
|
||||
receiver @ syn::FnArg::Receiver(_) => {
|
||||
bail_spanned!(receiver.span() => "unexpected receiver in #[pyproto]")
|
||||
}
|
||||
};
|
||||
// replace signature in trait with the parametrised one, which is identical to the declared
|
||||
// function signature.
|
||||
let decl = syn::parse_quote! { <#cls as #module::#proto<'p>>::#arg_name };
|
||||
let mut arg_ty = match crate::utils::option_type_argument(&input.ty) {
|
||||
Some(arg_ty) => {
|
||||
let arg_ty = arg_ty.clone();
|
||||
*input.ty = syn::parse_quote! { Option<#decl> };
|
||||
arg_ty
|
||||
}
|
||||
None => std::mem::replace(&mut *input.ty, decl),
|
||||
};
|
||||
// ensure the type has all lifetimes so it can be used in the protocol trait associated type
|
||||
insert_lifetime(&mut arg_ty);
|
||||
impl_types.push(quote! {type #arg_name = #arg_ty;});
|
||||
|
||||
let type1 = syn::parse_quote! { arg: <#cls as #module::#proto<'p>>::#arg_name};
|
||||
let type2 = syn::parse_quote! { arg: Option<<#cls as #module::#proto<'p>>::#arg_name>};
|
||||
modify_arg_ty(sig, idx, &type1, &type2)?;
|
||||
}
|
||||
|
||||
if meth.with_self {
|
||||
|
@ -89,32 +102,6 @@ pub(crate) fn impl_method_proto(
|
|||
})
|
||||
}
|
||||
|
||||
/// Some hacks for arguments: get `T` from `Option<T>` and insert lifetime
|
||||
fn get_arg_ty(sig: &syn::Signature, idx: usize) -> syn::Result<syn::Type> {
|
||||
fn get_option_ty(path: &syn::Path) -> Option<syn::Type> {
|
||||
let seg = path.segments.last()?;
|
||||
if seg.ident == "Option" {
|
||||
if let syn::PathArguments::AngleBracketed(ref data) = seg.arguments {
|
||||
if let Some(syn::GenericArgument::Type(ref ty)) = data.args.last() {
|
||||
return Some(ty.to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
let mut ty = match &sig.inputs[idx] {
|
||||
syn::FnArg::Typed(ref cap) => match &*cap.ty {
|
||||
// For `Option<T>`, we use `T` as an associated type for the protocol.
|
||||
syn::Type::Path(ref ty) => get_option_ty(&ty.path).unwrap_or_else(|| *cap.ty.clone()),
|
||||
_ => *cap.ty.clone(),
|
||||
},
|
||||
ty => bail_spanned!(ty.span() => format!("unsupported argument type: {:?}", ty)),
|
||||
};
|
||||
insert_lifetime(&mut ty);
|
||||
Ok(ty)
|
||||
}
|
||||
|
||||
/// Insert lifetime `'p` to `PyRef<Self>` or references (e.g., `&PyType`).
|
||||
fn insert_lifetime(ty: &mut syn::Type) {
|
||||
fn insert_lifetime_for_path(path: &mut syn::TypePath) {
|
||||
|
@ -147,26 +134,6 @@ fn insert_lifetime(ty: &mut syn::Type) {
|
|||
}
|
||||
}
|
||||
|
||||
fn modify_arg_ty(
|
||||
sig: &mut syn::Signature,
|
||||
idx: usize,
|
||||
decl1: &syn::FnArg,
|
||||
decl2: &syn::FnArg,
|
||||
) -> syn::Result<()> {
|
||||
let arg = sig.inputs[idx].clone();
|
||||
match arg {
|
||||
syn::FnArg::Typed(ref cap) if crate::utils::option_type_argument(&*cap.ty).is_some() => {
|
||||
sig.inputs[idx] = fix_name(&cap.pat, &decl2)?;
|
||||
}
|
||||
syn::FnArg::Typed(ref cap) => {
|
||||
sig.inputs[idx] = fix_name(&cap.pat, &decl1)?;
|
||||
}
|
||||
_ => bail_spanned!(arg.span() => "not supported"),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn modify_self_ty(sig: &mut syn::Signature) {
|
||||
match sig.inputs[0] {
|
||||
syn::FnArg::Receiver(ref mut slf) => {
|
||||
|
@ -175,16 +142,3 @@ fn modify_self_ty(sig: &mut syn::Signature) {
|
|||
syn::FnArg::Typed(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn fix_name(pat: &syn::Pat, arg: &syn::FnArg) -> syn::Result<syn::FnArg> {
|
||||
if let syn::FnArg::Typed(ref cap) = arg {
|
||||
Ok(syn::FnArg::Typed(syn::PatType {
|
||||
attrs: cap.attrs.clone(),
|
||||
pat: Box::new(pat.clone()),
|
||||
colon_token: cap.colon_token,
|
||||
ty: cap.ty.clone(),
|
||||
}))
|
||||
} else {
|
||||
Err(err_spanned!(arg.span() => "expected a typed argument"))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue