allow to override class name #14

This commit is contained in:
Nikolay Kim 2017-06-09 12:30:13 -07:00
parent ea8f11fa6d
commit cfb2b16288
4 changed files with 118 additions and 19 deletions

View file

@ -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();

View file

@ -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<syn::Ident> = 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<syn::Ident>) -> Tokens {
let cls_name = quote! { #cls }.as_str().to_string();
fn impl_class(cls: &syn::Ident, base: &syn::Ident,
token: Option<syn::Ident>, 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
}

View file

@ -93,10 +93,15 @@ impl PyTuple {
}
}
//#[inline]
//pub fn iter(&self) -> slice::Iter<PyObject> {
//self.as_slice(py).iter()
//}
#[inline]
pub fn iter(&self, py: Python) -> slice::Iter<PyObject> {
self.as_slice(py).iter()
}
#[inline]
pub unsafe fn drop_ref(&mut self) {
self.0.drop_ref();
}
}
impl IntoPyTuple for PyTuple {

View file

@ -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<T> 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
<T as PyTypeObject>::init_type(py);
@ -99,7 +95,7 @@ impl<T> 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(<Self as PyTypeInfo>::offset()) as *mut Self::Type;
std::ptr::drop_in_place(ptr);