Make `build_py_proto` and `build_py_methods` only accept `ImplItem`

This commit is contained in:
Martin Larralde 2018-05-14 13:34:36 +02:00
parent 758d30abbd
commit 580e50f727
3 changed files with 50 additions and 58 deletions

View File

@ -6,15 +6,11 @@ use quote::Tokens;
use py_method;
pub fn build_py_methods(ast: &mut syn::Item) -> Tokens {
if let syn::Item::Impl(ref mut iimpl) = ast {
if iimpl.trait_.is_some() {
panic!("#[methods] can not be used only with trait impl block");
} else {
impl_methods(&iimpl.self_ty, &mut iimpl.items)
}
pub fn build_py_methods(ast: &mut syn::ItemImpl) -> Tokens {
if ast.trait_.is_some() {
panic!("#[methods] can not be used only with trait impl block");
} else {
panic!("#[methods] can only be used with Impl blocks")
impl_methods(&iimpl.self_ty, &mut iimpl.items)
}
}

View File

@ -9,56 +9,52 @@ use method::FnSpec;
use func::impl_method_proto;
pub fn build_py_proto(ast: &mut syn::Item) -> Tokens {
match ast {
syn::Item::Impl(ref mut expr) => {
if let Some((_, ref mut path, _)) = expr.trait_ {
let tokens = if let Some(ref mut segment) = path.segments.last() {
let ty = &expr.self_ty;
let items = &mut expr.items;
match segment.value().ident.as_ref() {
"PyObjectProtocol" =>
impl_proto_impl(ty, items, &defs::OBJECT),
"PyAsyncProtocol" =>
impl_proto_impl(ty, items, &defs::ASYNC),
"PyMappingProtocol" =>
impl_proto_impl(ty, items, &defs::MAPPING),
"PyIterProtocol" =>
impl_proto_impl(ty, items, &defs::ITER),
"PyContextProtocol" =>
impl_proto_impl(ty, items, &defs::CONTEXT),
"PySequenceProtocol" =>
impl_proto_impl(ty, items, &defs::SEQ),
"PyNumberProtocol" =>
impl_proto_impl(ty, items, &defs::NUM),
"PyDescrProtocol" =>
impl_proto_impl(ty, items, &defs::DESCR),
"PyBufferProtocol" =>
impl_proto_impl(ty, items, &defs::BUFFER),
"PyGCProtocol" =>
impl_proto_impl(ty, items, &defs::GC),
_ => {
warn!("#[proto] can not be used with this block");
return Tokens::new()
}
pub fn build_py_proto(ast: &mut syn::ItemImpl) -> Tokens {
if let Some((_, ref mut path, _)) = ast.trait_ {
let tokens = if let Some(ref mut segment) = path.segments.last() {
let ty = &ast.self_ty;
let items = &mut ast.items;
match segment.value().ident.as_ref() {
"PyObjectProtocol" =>
impl_proto_impl(ty, items, &defs::OBJECT),
"PyAsyncProtocol" =>
impl_proto_impl(ty, items, &defs::ASYNC),
"PyMappingProtocol" =>
impl_proto_impl(ty, items, &defs::MAPPING),
"PyIterProtocol" =>
impl_proto_impl(ty, items, &defs::ITER),
"PyContextProtocol" =>
impl_proto_impl(ty, items, &defs::CONTEXT),
"PySequenceProtocol" =>
impl_proto_impl(ty, items, &defs::SEQ),
"PyNumberProtocol" =>
impl_proto_impl(ty, items, &defs::NUM),
"PyDescrProtocol" =>
impl_proto_impl(ty, items, &defs::DESCR),
"PyBufferProtocol" =>
impl_proto_impl(ty, items, &defs::BUFFER),
"PyGCProtocol" =>
impl_proto_impl(ty, items, &defs::GC),
_ => {
warn!("#[proto] can not be used with this block");
return Tokens::new()
}
} else {
panic!("#[proto] can only be used with protocol trait implementations")
};
// attach lifetime
let mut seg = path.segments.pop().unwrap().into_value();
seg.arguments = syn::PathArguments::AngleBracketed(parse_quote!{<'p>});
path.segments.push(seg);
expr.generics.params = parse_quote!{'p};
tokens
}
} else {
panic!("#[proto] can only be used with protocol trait implementations")
}
},
_ => panic!("#[proto] can only be used with Impl blocks"),
}
};
// attach lifetime
let mut seg = path.segments.pop().unwrap().into_value();
seg.arguments = syn::PathArguments::AngleBracketed(parse_quote!{<'p>});
path.segments.push(seg);
expr.generics.params = parse_quote!{'p};
tokens
} else {
panic!("#[proto] can only be used with protocol trait implementations")
}
}
fn impl_proto_impl(

View File

@ -64,7 +64,7 @@ pub fn mod3init(attr: TokenStream, input: TokenStream) -> TokenStream {
#[proc_macro_attribute]
pub fn proto(_: TokenStream, input: TokenStream) -> TokenStream {
// Parse the token stream into a syntax tree
let mut ast: syn::Item = syn::parse(input)
let mut ast: syn::ItemImpl = syn::parse(input)
.expect("#[proto] must be used on an `impl` block");
// Build the output
@ -80,7 +80,7 @@ pub fn proto(_: TokenStream, input: TokenStream) -> TokenStream {
pub fn class(attr: TokenStream, input: TokenStream) -> TokenStream {
// Parse the token stream into a syntax tree
let mut ast: syn::DeriveInput = syn::parse(input)
.expect("#[class] must be used on an ");
.expect("#[class] must be used on a `struct`");
// Parse the macro arguments into a list of expressions
let args: Vec<syn::Expr> = {
@ -101,7 +101,7 @@ pub fn class(attr: TokenStream, input: TokenStream) -> TokenStream {
#[proc_macro_attribute]
pub fn methods(_: TokenStream, input: TokenStream) -> TokenStream {
// Parse the token stream into a syntax tree
let mut ast: syn::Item = syn::parse(input)
let mut ast: syn::ItemImpl = syn::parse(input)
.expect("#[methods] must be used on an `impl` block");
// Build the output