use associated consts

This commit is contained in:
Nikolay Kim 2017-07-13 16:45:50 -07:00
parent 52ade64bf7
commit 8eb5dc0667
10 changed files with 34 additions and 58 deletions

View File

@ -75,7 +75,7 @@ features = ["extension-module"]
**`src/lib.rs`**
```rust
#![feature(proc_macro, specialization)]
#![feature(proc_macro, specialization, associated_consts)]
extern crate pyo3;
use pyo3::{py, PyResult, Python, PyModule};

View File

@ -4,7 +4,7 @@ Python class generation is powered by unstable [Procedural Macros](https://doc.r
[Specialization](https://github.com/rust-lang/rfcs/blob/master/text/1210-impl-specialization.md) features, so you need to turn on `proc_macro` and `specialization` features:
```rust
#![feature(proc_macro, specialization)]
#![feature(proc_macro, specialization, associated_consts)]
extern crate pyo3;
```

View File

@ -32,7 +32,6 @@ pub fn build_py_class(ast: &mut syn::DeriveInput, attr: String) -> Tokens {
let tokens = impl_class(&ast.ident, &base, token, doc, params);
quote! {
#[feature(specialization)]
#[allow(non_upper_case_globals, unused_attributes,
unused_qualifications, unused_variables, non_camel_case_types)]
const #dummy_const: () = {
@ -167,6 +166,8 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
quote! {
impl _pyo3::typeob::PyTypeInfo for #cls {
type Type = #cls;
const NAME: &'static str = #cls_name;
const DESCRIPTION: &'static str = #doc;
#[inline]
fn size() -> usize {
@ -182,16 +183,10 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
((bs + align - 1) / align * align) as isize
}
fn type_name() -> &'static str { #cls_name }
fn type_description() -> &'static str {
#doc
}
#[inline]
fn type_object() -> &'static mut _pyo3::ffi::PyTypeObject {
unsafe fn type_object() -> &'static mut _pyo3::ffi::PyTypeObject {
static mut TYPE_OBJECT: _pyo3::ffi::PyTypeObject = _pyo3::ffi::PyTypeObject_INIT;
unsafe { &mut TYPE_OBJECT }
&mut TYPE_OBJECT
}
#[inline]
@ -206,16 +201,13 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
fn init_type(py: Python) {
static START: std::sync::Once = std::sync::ONCE_INIT;
START.call_once(|| {
let mut ty = <#cls as _pyo3::typeob::PyTypeInfo>::type_object();
let mut ty = unsafe{<#cls as _pyo3::typeob::PyTypeInfo>::type_object()};
if (ty.tp_flags & _pyo3::ffi::Py_TPFLAGS_READY) == 0 {
// automatically initialize the class on-demand
_pyo3::typeob::initialize_type::<#cls>(
py, None, <#cls as _pyo3::typeob::PyTypeInfo>::type_name(),
<#cls as _pyo3::typeob::PyTypeInfo>::type_description(), ty).expect(
_pyo3::typeob::initialize_type::<#cls>(py, None, ty).expect(
format!("An error occurred while initializing class {}",
<#cls as _pyo3::typeob::PyTypeInfo>::type_name())
.as_ref());
<#cls as _pyo3::typeob::PyTypeInfo>::NAME).as_ref());
}
});
}

View File

@ -1,4 +1,4 @@
#![feature(specialization, const_fn, proc_macro)]
#![feature(specialization, proc_macro, const_fn, associated_consts)]
//! Rust bindings to the Python interpreter.
//!

View File

@ -139,6 +139,7 @@ macro_rules! pyobject_nativetype(
impl $crate::typeob::PyTypeInfo for $name {
type Type = ();
const NAME: &'static str = stringify!($name);
#[inline]
fn size() -> usize {
@ -149,12 +150,8 @@ macro_rules! pyobject_nativetype(
0
}
#[inline]
fn type_name() -> &'static str {
stringify!($name)
}
#[inline]
fn type_object() -> &'static mut $crate::ffi::PyTypeObject {
unsafe { &mut $crate::ffi::$typeobject }
unsafe fn type_object() -> &'static mut $crate::ffi::PyTypeObject {
&mut $crate::ffi::$typeobject
}
#[inline]
fn is_instance(ptr: *mut $crate::ffi::PyObject) -> bool {

View File

@ -109,23 +109,21 @@ impl PyModule {
pub fn add_class<T>(&self) -> PyResult<()>
where T: ::typeob::PyTypeInfo
{
let mut ty = <T as ::typeob::PyTypeInfo>::type_object();
let type_name = <T as ::typeob::PyTypeInfo>::type_name();
let mut ty = unsafe{<T as ::typeob::PyTypeInfo>::type_object()};
let ty = if (ty.tp_flags & ffi::Py_TPFLAGS_READY) != 0 {
unsafe { PyType::from_type_ptr(self.token(), ty) }
} else {
// automatically initialize the class
let name = self.name()?;
let type_description = <T as ::typeob::PyTypeInfo>::type_description();
::typeob::initialize_type::<T>(
self.token(), Some(name), type_name, type_description, ty)
.expect(format!("An error occurred while initializing class {}",
<T as ::typeob::PyTypeInfo>::type_name()).as_ref());
self.token(), Some(name), ty)
.expect(
format!("An error occurred while initializing class {}", T::NAME).as_ref());
unsafe { PyType::from_type_ptr(self.token(), ty) }
};
self.setattr(type_name, ty)
self.setattr(T::NAME, ty)
}
}

View File

@ -21,6 +21,10 @@ use class::methods::PyMethodDefType;
pub trait PyTypeInfo {
/// Type of objects to store in PyObject struct
type Type;
/// Class name
const NAME: &'static str;
/// Class doc string
const DESCRIPTION: &'static str = "\0";
/// Size of the PyObject structure
fn size() -> usize;
@ -28,14 +32,8 @@ pub trait PyTypeInfo {
/// `Type` instance offset inside PyObject structure
fn offset() -> isize;
/// Type name
fn type_name() -> &'static str;
/// Type description
fn type_description() -> &'static str { "\0" }
/// PyTypeObject instance for this type
fn type_object() -> &'static mut ffi::PyTypeObject;
unsafe fn type_object() -> &'static mut ffi::PyTypeObject;
/// Check `*mut ffi::PyObject` if it is the same type
fn is_instance(ptr: *mut ffi::PyObject) -> bool;
@ -45,6 +43,7 @@ pub trait PyTypeInfo {
impl<'a, T: ?Sized> PyTypeInfo for &'a T where T: PyTypeInfo {
type Type = T::Type;
const NAME: &'static str = T::NAME;
#[inline]
default fn size() -> usize {
@ -57,12 +56,7 @@ impl<'a, T: ?Sized> PyTypeInfo for &'a T where T: PyTypeInfo {
}
#[inline]
default fn type_name() -> &'static str {
<T as PyTypeInfo>::type_name()
}
#[inline]
default fn type_object() -> &'static mut ffi::PyTypeObject {
default unsafe fn type_object() -> &'static mut ffi::PyTypeObject {
<T as PyTypeInfo>::type_object()
}
@ -140,15 +134,12 @@ impl<T> PyTypeObject for T where T: PyObjectAlloc<T> + PyTypeInfo {
#[inline]
default fn init_type(py: Python) {
let mut ty = <T as PyTypeInfo>::type_object();
let mut ty = unsafe { <T as PyTypeInfo>::type_object() };
if (ty.tp_flags & ffi::Py_TPFLAGS_READY) == 0 {
// automatically initialize the class on-demand
initialize_type::<T>(
py, None, <T as PyTypeInfo>::type_name(),
<T as PyTypeInfo>::type_description(), ty).expect(
format!("An error occurred while initializing class {}",
<T as PyTypeInfo>::type_name()).as_ref());
initialize_type::<T>(py, None, ty).expect(
format!("An error occurred while initializing class {}", T::NAME).as_ref());
}
}
@ -163,21 +154,19 @@ impl<T> PyTypeObject for T where T: PyObjectAlloc<T> + PyTypeInfo {
pub fn initialize_type<'p, T>(py: Python<'p>,
module_name: Option<&str>,
type_name: &str,
type_description: &'static str,
type_object: &mut ffi::PyTypeObject) -> PyResult<&'p PyType>
where T: PyObjectAlloc<T> + PyTypeInfo
{
// type name
let name = match module_name {
Some(module_name) => CString::new(format!("{}.{}", module_name, type_name)),
None => CString::new(type_name)
Some(module_name) => CString::new(format!("{}.{}", module_name, T::NAME)),
None => CString::new(T::NAME)
};
let name = name.expect(
"Module name/type name must not contain NUL byte").into_raw();
type_object.tp_name = name;
type_object.tp_doc = type_description.as_ptr() as *const _;
type_object.tp_doc = T::DESCRIPTION.as_ptr() as *const _;
// dealloc
type_object.tp_dealloc = Some(tp_dealloc_callback::<T>);

View File

@ -1,5 +1,5 @@
#![allow(dead_code, unused_variables)]
#![feature(proc_macro, specialization)]
#![feature(proc_macro, specialization, associated_consts)]
extern crate pyo3;

View File

@ -1,4 +1,4 @@
#![feature(proc_macro, specialization)]
#![feature(proc_macro, specialization, associated_consts)]
#![allow(dead_code, unused_variables)]
extern crate pyo3;

View File

@ -1,4 +1,4 @@
#![feature(proc_macro, specialization)]
#![feature(proc_macro, specialization, associated_consts)]
#![allow(dead_code, unused_variables)]
extern crate pyo3;