use associated consts
This commit is contained in:
parent
52ade64bf7
commit
8eb5dc0667
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
```
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(specialization, const_fn, proc_macro)]
|
||||
#![feature(specialization, proc_macro, const_fn, associated_consts)]
|
||||
|
||||
//! Rust bindings to the Python interpreter.
|
||||
//!
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![allow(dead_code, unused_variables)]
|
||||
#![feature(proc_macro, specialization)]
|
||||
#![feature(proc_macro, specialization, associated_consts)]
|
||||
|
||||
extern crate pyo3;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(proc_macro, specialization)]
|
||||
#![feature(proc_macro, specialization, associated_consts)]
|
||||
#![allow(dead_code, unused_variables)]
|
||||
|
||||
extern crate pyo3;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(proc_macro, specialization)]
|
||||
#![feature(proc_macro, specialization, associated_consts)]
|
||||
#![allow(dead_code, unused_variables)]
|
||||
|
||||
extern crate pyo3;
|
||||
|
|
Loading…
Reference in New Issue