From cfb2b1628862901e8322928fab95990b2ff86da5 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Fri, 9 Jun 2017 12:30:13 -0700 Subject: [PATCH] allow to override class name #14 --- pyo3cls/src/lib.rs | 4 +- pyo3cls/src/py_class.rs | 106 ++++++++++++++++++++++++++++++++++++++-- src/objects/tuple.rs | 13 +++-- src/typeob.rs | 14 ++---- 4 files changed, 118 insertions(+), 19 deletions(-) diff --git a/pyo3cls/src/lib.rs b/pyo3cls/src/lib.rs index ced7d335..9d71c623 100644 --- a/pyo3cls/src/lib.rs +++ b/pyo3cls/src/lib.rs @@ -44,7 +44,7 @@ pub fn proto(_: TokenStream, input: TokenStream) -> TokenStream { } #[proc_macro_attribute] -pub fn class(_: TokenStream, input: TokenStream) -> TokenStream { +pub fn class(attr: TokenStream, input: TokenStream) -> TokenStream { // Construct a string representation of the type definition let source = input.to_string(); @@ -52,7 +52,7 @@ pub fn class(_: TokenStream, input: TokenStream) -> TokenStream { let mut ast = syn::parse_derive_input(&source).unwrap(); // Build the output - let expanded = py_class::build_py_class(&mut ast); + let expanded = py_class::build_py_class(&mut ast, attr.to_string()); // Return the generated impl as a TokenStream let mut tokens = Tokens::new(); diff --git a/pyo3cls/src/py_class.rs b/pyo3cls/src/py_class.rs index e0aedfa5..23814db9 100644 --- a/pyo3cls/src/py_class.rs +++ b/pyo3cls/src/py_class.rs @@ -1,10 +1,15 @@ // Copyright (c) 2017-present PyO3 Project and Contributors +use std; +use std::collections::HashMap; + use syn; use quote::Tokens; -pub fn build_py_class(ast: &mut syn::DeriveInput) -> Tokens { +pub fn build_py_class(ast: &mut syn::DeriveInput, attr: String) -> Tokens { + let params = parse_attribute(attr); + let base = syn::Ident::from("_pyo3::PyObject"); let mut token: Option = None; @@ -21,7 +26,7 @@ pub fn build_py_class(ast: &mut syn::DeriveInput) -> Tokens { } let dummy_const = syn::Ident::new(format!("_IMPL_PYO3_CLS_{}", ast.ident)); - let tokens = impl_class(&ast.ident, &base, token); + let tokens = impl_class(&ast.ident, &base, token, params); quote! { #[feature(specialization)] @@ -36,8 +41,12 @@ pub fn build_py_class(ast: &mut syn::DeriveInput) -> Tokens { } } -fn impl_class(cls: &syn::Ident, base: &syn::Ident, token: Option) -> Tokens { - let cls_name = quote! { #cls }.as_str().to_string(); +fn impl_class(cls: &syn::Ident, base: &syn::Ident, + token: Option, params: HashMap<&'static str, syn::Ident>) -> Tokens { + let cls_name = match params.get("name") { + Some(name) => quote! { #name }.as_str().to_string(), + None => quote! { #cls }.as_str().to_string() + }; let extra = if let Some(token) = token { Some(quote! { @@ -210,3 +219,92 @@ fn is_python_token(field: &syn::Field) -> bool { } return false } + +fn parse_attribute(attr: String) -> HashMap<&'static str, syn::Ident> { + let mut params = HashMap::new(); + + if let Ok(tts) = syn::parse_token_trees(&attr) { + let mut elems = Vec::new(); + + for tt in tts.iter() { + match tt { + &syn::TokenTree::Token(_) => { + println!("Wrong format: {:?}", attr.to_string()); + } + &syn::TokenTree::Delimited(ref delimited) => { + let mut elem = Vec::new(); + for tt in delimited.tts.iter() { + match tt { + &syn::TokenTree::Token(syn::Token::Comma) => { + let el = std::mem::replace(&mut elem, Vec::new()); + elems.push(el); + }, + _ => elem.push(tt.clone()) + } + } + } + } + } + + for elem in elems { + if elem.len() < 3 { + println!("Wrong format: {:?}", elem); + continue + } + + let key = match elem[0] { + syn::TokenTree::Token(syn::Token::Ident(ref ident)) => { + ident.as_ref().to_owned().to_lowercase() + }, + _ => { + println!("Wrong format: {:?}", attr.to_string()); + continue + } + }; + + match elem[1] { + syn::TokenTree::Token(syn::Token::Eq) => (), + _ => { + println!("Wrong format: {:?}", attr.to_string()); + continue + } + } + + match key.as_ref() { + "freelist" => { + if elem.len() != 3 { + println!("Wrong 'freelist' format: {:?}", elem); + } else { + match elem[2] { + syn::TokenTree::Token( + syn::Token::Literal( + syn::Lit::Int(val, _))) => { + params.insert("freelist", syn::Ident::from(val.to_string())); + } + _ => println!("Wrong 'freelist' format: {:?}", elem) + } + } + }, + "name" => { + if elem.len() != 3 { + println!("Wrong 'name' format: {:?}", elem); + } else { + match elem[2] { + syn::TokenTree::Token(syn::Token::Ident(ref ident)) => { + params.insert("name", ident.clone()); + }, + _ => println!("Wrong 'name' format: {:?}", elem) + } + } + }, + "base" => { + + } + _ => { + println!("Unsupported parameter: {:?}", key); + } + } + } + } + params +} diff --git a/src/objects/tuple.rs b/src/objects/tuple.rs index 678847fb..d34a3748 100644 --- a/src/objects/tuple.rs +++ b/src/objects/tuple.rs @@ -93,10 +93,15 @@ impl PyTuple { } } - //#[inline] - //pub fn iter(&self) -> slice::Iter { - //self.as_slice(py).iter() - //} + #[inline] + pub fn iter(&self, py: Python) -> slice::Iter { + self.as_slice(py).iter() + } + + #[inline] + pub unsafe fn drop_ref(&mut self) { + self.0.drop_ref(); + } } impl IntoPyTuple for PyTuple { diff --git a/src/typeob.rs b/src/typeob.rs index 578c3f5e..47cddf10 100644 --- a/src/typeob.rs +++ b/src/typeob.rs @@ -63,9 +63,7 @@ pub trait PyObjectAlloc { type Type; /// Allocates a new object (usually by calling ty->tp_alloc), - /// and initializes it using init_val. - /// `ty` must be derived from the Self type, and the resulting object - /// must be of type `ty`. + /// and initializes it using value. unsafe fn alloc(py: Python, value: Self::Type) -> PyResult<*mut ffi::PyObject>; /// Calls the rust destructor for the object and frees the memory @@ -74,15 +72,13 @@ pub trait PyObjectAlloc { unsafe fn dealloc(py: Python, obj: *mut ffi::PyObject); } -/// A PythonObject that is usable as a base type for #[class] +/// A Python object allocator that is usable as a base type for #[class] impl PyObjectAlloc for T where T : PyTypeInfo { type Type = T::Type; /// Allocates a new object (usually by calling ty->tp_alloc), - /// and initializes it using init_val. - /// `ty` must be derived from the Self type, and the resulting object - /// must be of type `ty`. - unsafe fn alloc(py: Python, value: T::Type) -> PyResult<*mut ffi::PyObject> { + /// and initializes it using value. + default unsafe fn alloc(py: Python, value: Self::Type) -> PyResult<*mut ffi::PyObject> { // TODO: remove this ::init_type(py); @@ -99,7 +95,7 @@ impl PyObjectAlloc for T where T : PyTypeInfo { /// Calls the rust destructor for the object and frees the memory /// (usually by calling ptr->ob_type->tp_free). /// This function is used as tp_dealloc implementation. - unsafe fn dealloc(_py: Python, obj: *mut ffi::PyObject) { + default unsafe fn dealloc(_py: Python, obj: *mut ffi::PyObject) { let ptr = (obj as *mut u8).offset(::offset()) as *mut Self::Type; std::ptr::drop_in_place(ptr);