Fix items in pyo3-derive-backed::args test module

This commit is contained in:
Martin Larralde 2018-05-14 01:49:12 +02:00
parent 4414d684e4
commit ecadcef0c9
3 changed files with 266 additions and 267 deletions

View file

@ -150,15 +150,22 @@ pub fn parse_arguments(items: &[syn::NestedMeta]) -> Vec<Argument> {
#[cfg(test)]
mod test {
use syn;
use args::{Argument, parse_arguments};
use quote::ToTokens;
use syn::buffer::TokenBuffer;
use proc_macro::TokenStream;
fn items(s: &'static str) -> Vec<syn::NestedMeta> {
let i = syn::parse_outer_attr(s).unwrap();
match i.value {
syn::Meta::List(_, items) => {
items
let stream = s.parse::<TokenStream>().unwrap();
let buffer = TokenBuffer::new(stream);
let i = syn::Attribute::parse_outer(buffer.begin()).unwrap().0;
match i.interpret_meta() {
Some(syn::Meta::List(syn::MetaList { nested, .. })) => {
nested.iter().map(Clone::clone).collect()
}
_ => unreachable!()
}

View file

@ -29,17 +29,15 @@ pub enum MethodProto {
}
impl MethodProto {
pub fn eq(&self, name: &str) -> bool {
match *self {
MethodProto::Free{name: n, proto: _} => n == name,
MethodProto::Unary{name: n, pyres: _, proto: _} => n == name,
MethodProto::Binary{name: n, arg: _, pyres: _, proto: _} => n == name,
MethodProto::BinaryS{name: n, arg1: _, arg2: _, pyres: _, proto: _} => n == name,
MethodProto::Ternary{name: n, arg1: _, arg2: _, pyres: _, proto: _} => n == name,
MethodProto::TernaryS{name: n, arg1: _, arg2: _, arg3: _,
pyres: _, proto: _} => n == name,
MethodProto::Quaternary{name: n, arg1: _, arg2: _, arg3: _, proto: _} => n == name,
MethodProto::Free{name: n, ..} => n == name,
MethodProto::Unary{name: n, ..} => n == name,
MethodProto::Binary{name: n, ..} => n == name,
MethodProto::BinaryS{name: n, ..} => n == name,
MethodProto::Ternary{name: n, ..} => n == name,
MethodProto::TernaryS{name: n, ..} => n == name,
MethodProto::Quaternary{name: n, ..} => n == name,
}
}
}
@ -51,268 +49,208 @@ pub fn impl_method_proto(
meth: &MethodProto
) -> Tokens {
let decl = sig.decl.clone();
if let MethodProto::Free{proto, ..} = meth {
let p: syn::Path = syn::parse_str(proto).unwrap();
return quote! {
impl<'p> #p<'p> for #cls {}
}
}
match *meth {
MethodProto::Free{name: _, proto} => {
let p: syn::Path = syn::parse_str(proto).unwrap();
return quote! {
impl<'p> #p<'p> for #cls {}
if let syn::ReturnType::Type(_, ref ty) = sig.decl.output.clone() {
match *meth {
MethodProto::Free{..} => {
unreachable!()
}
},
_ => (),
};
MethodProto::Unary{pyres, proto, ..} => {
let p: syn::Path = syn::parse_str(proto).unwrap();
let (ty, succ) = get_res_success(ty);
match decl.output {
syn::ReturnType::Type(_, ref ty) => {
match *meth {
MethodProto::Free{name: _, proto: _} => unreachable!(),
MethodProto::Unary{name: _, pyres, proto} => {
let p: syn::Path = syn::parse_str(proto).unwrap();
let (ty, succ) = get_res_success(ty);
let tmp: syn::ItemFn = parse_quote!{
fn test(&self) -> <#cls as #p<'p>>::Result {}
};
sig.decl.output = tmp.decl.output;
modify_self_ty(sig);
let tmp = extract_decl(parse_quote!{
fn test(&self) -> <#cls as #p<'p>>::Result {}
});
sig.decl.output = tmp.output.clone();
modify_self_ty(sig);
if pyres {
quote! {
impl<'p> #p<'p> for #cls {
type Success = #succ;
type Result = #ty;
}
}
} else {
quote! {
impl<'p> #p<'p> for #cls {
type Result = #ty;
}
if pyres {
quote! {
impl<'p> #p<'p> for #cls {
type Success = #succ;
type Result = #ty;
}
}
},
MethodProto::Binary{name: n, arg, pyres, proto} => {
if sig.decl.inputs.len() <= 1 {
println!("Not enough arguments for {}", n);
return Tokens::new();
}
let p: syn::Path = syn::parse_str(proto).unwrap();
let arg_name = syn::Ident::from(arg);
let arg_ty = get_arg_ty(sig, 1);
let (ty, succ) = get_res_success(ty);
let tmp = extract_decl(
parse_quote!{
fn test(&self,arg: <#cls as #p<'p>>::#arg_name)-> <#cls as #p<'p>>::Result {}
});
let tmp2 = extract_decl(
parse_quote!{
fn test( &self, arg: Option<<#cls as #p<'p>>::#arg_name>) -> <#cls as #p<'p>>::Result {}
});
modify_arg_ty(sig, 1, &tmp, &tmp2);
modify_self_ty(sig);
if pyres {
quote! {
impl<'p> #p<'p> for #cls {
type #arg_name = #arg_ty;
type Success = #succ;
type Result = #ty;
}
}
} else {
quote! {
impl<'p> #p<'p> for #cls {
type #arg_name = #arg_ty;
type Result = #ty;
}
} else {
quote! {
impl<'p> #p<'p> for #cls {
type Result = #ty;
}
}
},
MethodProto::BinaryS{name: n, arg1, arg2, pyres, proto} => {
if sig.decl.inputs.len() <= 1 {
print_err(format!("Not enough arguments {}", n), quote!(sig));
return Tokens::new();
}
let p: syn::Path = syn::parse_str(proto).unwrap();
let arg1_name = syn::Ident::from(arg1);
let arg1_ty = get_arg_ty(sig, 0);
let arg2_name = syn::Ident::from(arg2);
let arg2_ty = get_arg_ty(sig, 1);
let (ty, succ) = get_res_success(ty);
}
},
MethodProto::Binary{name, arg, pyres, proto} => {
// rewrite ty
let tmp = extract_decl(
parse_quote!{fn test(
arg1: <#cls as #p<'p>>::#arg1_name,
arg2: <#cls as #p<'p>>::#arg2_name)
-> <#cls as #p<'p>>::Result {}});
let tmp2 = extract_decl(
parse_quote!{fn test(
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
arg2: Option<<#cls as #p<'p>>::#arg2_name>)
-> <#cls as #p<'p>>::Result {}});
modify_arg_ty(sig, 0, &tmp, &tmp2);
modify_arg_ty(sig, 1, &tmp, &tmp2);
if sig.decl.inputs.len() <= 1 {
println!("Not enough arguments for {}", name);
return Tokens::new();
}
if pyres {
quote! {
impl<'p> #p<'p> for #cls {
type #arg1_name = #arg1_ty;
type #arg2_name = #arg2_ty;
type Success = #succ;
type Result = #ty;
}
}
} else {
quote! {
impl<'p> #p<'p> for #cls {
type #arg1_name = #arg1_ty;
type #arg2_name = #arg2_ty;
type Result = #ty;
}
let p: syn::Path = syn::parse_str(proto).unwrap();
let arg_name = syn::Ident::from(arg);
let arg_ty = get_arg_ty(sig, 1);
let (ty, succ) = get_res_success(ty);
let tmp = extract_decl(parse_quote!{
fn test(&self,arg: <#cls as #p<'p>>::#arg_name)-> <#cls as #p<'p>>::Result {}
});
let tmp2 = extract_decl(parse_quote!{
fn test( &self, arg: Option<<#cls as #p<'p>>::#arg_name>) -> <#cls as #p<'p>>::Result {}
});
modify_arg_ty(sig, 1, &tmp, &tmp2);
modify_self_ty(sig);
if pyres {
quote! {
impl<'p> #p<'p> for #cls {
type #arg_name = #arg_ty;
type Success = #succ;
type Result = #ty;
}
}
},
MethodProto::Ternary{name: n, arg1, arg2, pyres, proto} => {
if sig.decl.inputs.len() <= 2 {
print_err(format!("Not enough arguments {}", n), quote!(sig));
return Tokens::new();
}
let p: syn::Path = syn::parse_str(proto).unwrap();
let arg1_name = syn::Ident::from(arg1);
let arg1_ty = get_arg_ty(sig, 1);
let arg2_name = syn::Ident::from(arg2);
let arg2_ty = get_arg_ty(sig, 2);
let (ty, succ) = get_res_success(ty);
// rewrite ty
let tmp = extract_decl(
parse_quote! {fn test(
&self,
arg1: <#cls as #p<'p>>::#arg1_name,
arg2: <#cls as #p<'p>>::#arg2_name)
-> <#cls as #p<'p>>::Result {}});
let tmp2 = extract_decl(
parse_quote! {fn test(
&self,
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
arg2: Option<<#cls as #p<'p>>::#arg2_name>)
-> <#cls as #p<'p>>::Result {}});
modify_arg_ty(sig, 1, &tmp, &tmp2);
modify_arg_ty(sig, 2, &tmp, &tmp2);
modify_self_ty(sig);
if pyres {
quote! {
impl<'p> #p<'p> for #cls {
type #arg1_name = #arg1_ty;
type #arg2_name = #arg2_ty;
type Success = #succ;
type Result = #ty;
}
}
} else {
quote! {
impl<'p> #p<'p> for #cls {
type #arg1_name = #arg1_ty;
type #arg2_name = #arg2_ty;
type Result = #ty;
}
} else {
quote! {
impl<'p> #p<'p> for #cls {
type #arg_name = #arg_ty;
type Result = #ty;
}
}
},
MethodProto::TernaryS{name: n, arg1, arg2, arg3, pyres, proto} => {
if sig.decl.inputs.len() <= 2 {
print_err(format!("Not enough arguments {}", n), quote!(sig));
return Tokens::new();
}
let p: syn::Path = syn::parse_str(proto).unwrap();
let arg1_name = syn::Ident::from(arg1);
let arg1_ty = get_arg_ty(sig, 0);
let arg2_name = syn::Ident::from(arg2);
let arg2_ty = get_arg_ty(sig, 1);
let arg3_name = syn::Ident::from(arg3);
let arg3_ty = get_arg_ty(sig, 2);
let (ty, succ) = get_res_success(ty);
}
},
MethodProto::BinaryS{name, arg1, arg2, pyres, proto} => {
if sig.decl.inputs.len() <= 1 {
print_err(format!("Not enough arguments {}", name), quote!(sig));
return Tokens::new();
}
let p: syn::Path = syn::parse_str(proto).unwrap();
let arg1_name = syn::Ident::from(arg1);
let arg1_ty = get_arg_ty(sig, 0);
let arg2_name = syn::Ident::from(arg2);
let arg2_ty = get_arg_ty(sig, 1);
let (ty, succ) = get_res_success(ty);
// rewrite ty
let tmp = extract_decl(
parse_quote! {fn test(
arg1: <#cls as #p<'p>>::#arg1_name,
arg2: <#cls as #p<'p>>::#arg2_name,
arg3: <#cls as #p<'p>>::#arg3_name)
-> <#cls as #p<'p>>::Result {}});
let tmp2 = extract_decl(
parse_quote! {fn test(
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
arg2: Option<<#cls as #p<'p>>::#arg2_name>,
arg3: Option<<#cls as #p<'p>>::#arg3_name>)
-> <#cls as #p<'p>>::Result {}});
modify_arg_ty(sig, 0, &tmp, &tmp2);
modify_arg_ty(sig, 1, &tmp, &tmp2);
modify_arg_ty(sig, 2, &tmp, &tmp2);
// rewrite ty
let tmp = extract_decl(
parse_quote!{fn test(
arg1: <#cls as #p<'p>>::#arg1_name,
arg2: <#cls as #p<'p>>::#arg2_name)
-> <#cls as #p<'p>>::Result {}});
let tmp2 = extract_decl(
parse_quote!{fn test(
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
arg2: Option<<#cls as #p<'p>>::#arg2_name>)
-> <#cls as #p<'p>>::Result {}});
modify_arg_ty(sig, 0, &tmp, &tmp2);
modify_arg_ty(sig, 1, &tmp, &tmp2);
if pyres {
quote! {
impl<'p> #p<'p> for #cls {
type #arg1_name = #arg1_ty;
type #arg2_name = #arg2_ty;
type #arg3_name = #arg3_ty;
type Success = #succ;
type Result = #ty;
}
}
} else {
quote! {
impl<'p> #p<'p> for #cls {
type #arg1_name = #arg1_ty;
type #arg2_name = #arg2_ty;
type #arg3_name = #arg3_ty;
type Result = #ty;
}
if pyres {
quote! {
impl<'p> #p<'p> for #cls {
type #arg1_name = #arg1_ty;
type #arg2_name = #arg2_ty;
type Success = #succ;
type Result = #ty;
}
}
},
MethodProto::Quaternary{name: n, arg1, arg2, arg3, proto} => {
if sig.decl.inputs.len() <= 3 {
print_err(format!("Not enough arguments {}", n), quote!(sig));
return Tokens::new();
} else {
quote! {
impl<'p> #p<'p> for #cls {
type #arg1_name = #arg1_ty;
type #arg2_name = #arg2_ty;
type Result = #ty;
}
}
let p: syn::Path = syn::parse_str(proto).unwrap();
let arg1_name = syn::Ident::from(arg1);
let arg1_ty = get_arg_ty(sig, 1);
let arg2_name = syn::Ident::from(arg2);
let arg2_ty = get_arg_ty(sig, 2);
let arg3_name = syn::Ident::from(arg3);
let arg3_ty = get_arg_ty(sig, 3);
let (ty, succ) = get_res_success(ty);
}
},
MethodProto::Ternary{name, arg1, arg2, pyres, proto} => {
if sig.decl.inputs.len() <= 2 {
print_err(format!("Not enough arguments {}", name), quote!(sig));
return Tokens::new();
}
let p: syn::Path = syn::parse_str(proto).unwrap();
let arg1_name = syn::Ident::from(arg1);
let arg1_ty = get_arg_ty(sig, 1);
let arg2_name = syn::Ident::from(arg2);
let arg2_ty = get_arg_ty(sig, 2);
let (ty, succ) = get_res_success(ty);
// rewrite ty
let tmp = extract_decl(
parse_quote! {fn test(
&self,
arg1: <#cls as #p<'p>>::#arg1_name,
arg2: <#cls as #p<'p>>::#arg2_name,
arg3: <#cls as #p<'p>>::#arg3_name)
-> <#cls as #p<'p>>::Result {}});
let tmp2 = extract_decl(
parse_quote! {fn test(
&self,
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
arg2: Option<<#cls as #p<'p>>::#arg2_name>,
arg3: Option<<#cls as #p<'p>>::#arg3_name>)
-> <#cls as #p<'p>>::Result {}});
modify_arg_ty(sig, 1, &tmp, &tmp2);
modify_arg_ty(sig, 2, &tmp, &tmp2);
modify_arg_ty(sig, 3, &tmp, &tmp2);
modify_self_ty(sig);
// rewrite ty
let tmp = extract_decl(
parse_quote! {fn test(
&self,
arg1: <#cls as #p<'p>>::#arg1_name,
arg2: <#cls as #p<'p>>::#arg2_name)
-> <#cls as #p<'p>>::Result {}});
let tmp2 = extract_decl(
parse_quote! {fn test(
&self,
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
arg2: Option<<#cls as #p<'p>>::#arg2_name>)
-> <#cls as #p<'p>>::Result {}});
modify_arg_ty(sig, 1, &tmp, &tmp2);
modify_arg_ty(sig, 2, &tmp, &tmp2);
modify_self_ty(sig);
if pyres {
quote! {
impl<'p> #p<'p> for #cls {
type #arg1_name = #arg1_ty;
type #arg2_name = #arg2_ty;
type Success = #succ;
type Result = #ty;
}
}
} else {
quote! {
impl<'p> #p<'p> for #cls {
type #arg1_name = #arg1_ty;
type #arg2_name = #arg2_ty;
type Result = #ty;
}
}
}
},
MethodProto::TernaryS{name, arg1, arg2, arg3, pyres, proto} => {
if sig.decl.inputs.len() <= 2 {
print_err(format!("Not enough arguments {}", name), quote!(sig));
return Tokens::new();
}
let p: syn::Path = syn::parse_str(proto).unwrap();
let arg1_name = syn::Ident::from(arg1);
let arg1_ty = get_arg_ty(sig, 0);
let arg2_name = syn::Ident::from(arg2);
let arg2_ty = get_arg_ty(sig, 1);
let arg3_name = syn::Ident::from(arg3);
let arg3_ty = get_arg_ty(sig, 2);
let (ty, succ) = get_res_success(ty);
// rewrite ty
let tmp = extract_decl(
parse_quote! {fn test(
arg1: <#cls as #p<'p>>::#arg1_name,
arg2: <#cls as #p<'p>>::#arg2_name,
arg3: <#cls as #p<'p>>::#arg3_name)
-> <#cls as #p<'p>>::Result {}});
let tmp2 = extract_decl(
parse_quote! {fn test(
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
arg2: Option<<#cls as #p<'p>>::#arg2_name>,
arg3: Option<<#cls as #p<'p>>::#arg3_name>)
-> <#cls as #p<'p>>::Result {}});
modify_arg_ty(sig, 0, &tmp, &tmp2);
modify_arg_ty(sig, 1, &tmp, &tmp2);
modify_arg_ty(sig, 2, &tmp, &tmp2);
if pyres {
quote! {
impl<'p> #p<'p> for #cls {
type #arg1_name = #arg1_ty;
@ -322,10 +260,64 @@ pub fn impl_method_proto(
type Result = #ty;
}
}
},
}
},
_ => panic!("fn return type is not supported"),
} else {
quote! {
impl<'p> #p<'p> for #cls {
type #arg1_name = #arg1_ty;
type #arg2_name = #arg2_ty;
type #arg3_name = #arg3_ty;
type Result = #ty;
}
}
}
},
MethodProto::Quaternary{name, arg1, arg2, arg3, proto} => {
if sig.decl.inputs.len() <= 3 {
print_err(format!("Not enough arguments {}", name), quote!(sig));
return Tokens::new();
}
let p: syn::Path = syn::parse_str(proto).unwrap();
let arg1_name = syn::Ident::from(arg1);
let arg1_ty = get_arg_ty(sig, 1);
let arg2_name = syn::Ident::from(arg2);
let arg2_ty = get_arg_ty(sig, 2);
let arg3_name = syn::Ident::from(arg3);
let arg3_ty = get_arg_ty(sig, 3);
let (ty, succ) = get_res_success(ty);
// rewrite ty
let tmp = extract_decl(
parse_quote! {fn test(
&self,
arg1: <#cls as #p<'p>>::#arg1_name,
arg2: <#cls as #p<'p>>::#arg2_name,
arg3: <#cls as #p<'p>>::#arg3_name)
-> <#cls as #p<'p>>::Result {}});
let tmp2 = extract_decl(
parse_quote! {fn test(
&self,
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
arg2: Option<<#cls as #p<'p>>::#arg2_name>,
arg3: Option<<#cls as #p<'p>>::#arg3_name>)
-> <#cls as #p<'p>>::Result {}});
modify_arg_ty(sig, 1, &tmp, &tmp2);
modify_arg_ty(sig, 2, &tmp, &tmp2);
modify_arg_ty(sig, 3, &tmp, &tmp2);
modify_self_ty(sig);
quote! {
impl<'p> #p<'p> for #cls {
type #arg1_name = #arg1_ty;
type #arg2_name = #arg2_ty;
type #arg3_name = #arg3_ty;
type Success = #succ;
type Result = #ty;
}
}
},
}
} else {
panic!("fn return type is not supported")
}
}
@ -359,7 +351,7 @@ fn get_arg_ty(sig: &syn::MethodSig, idx: usize) -> syn::Type {
_ => panic!("fn arg type is not supported"),
};
// Add a lifetime if there is none
if let syn::Type::Reference(ref mut r) = ty {
r.lifetime.get_or_insert(parse_quote!{'p});
}

View file

@ -10,14 +10,14 @@ use proc_macro::TokenStream;
///
/// nightly-2018-04-05: ( name=CustomName )
/// nightly-2018-04-28: name=CustomName
pub fn attr_with_parentheses(attr: TokenStream) -> String {
let attr = attr.to_string();
if attr.len() > 0 && !attr.starts_with("(") {
return format!("({})", attr);
} else {
return attr;
}
}
// pub fn attr_with_parentheses(attr: TokenStream) -> String {
// let attr = attr.to_string();
// if attr.len() > 0 && !attr.starts_with("(") {
// return format!("({})", attr);
// } else {
// return attr;
// }
// }
pub fn print_err(msg: String, t: Tokens) {
println!("Error: {} in '{}'", msg, t.to_string());