allow to override class name #14
This commit is contained in:
parent
ea8f11fa6d
commit
cfb2b16288
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue