diff --git a/README.md b/README.md index d29e13c4..cea36774 100644 --- a/README.md +++ b/README.md @@ -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}; diff --git a/guide/src/class.md b/guide/src/class.md index 156811df..25f74019 100644 --- a/guide/src/class.md +++ b/guide/src/class.md @@ -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; ``` diff --git a/pyo3cls/src/py_class.rs b/pyo3cls/src/py_class.rs index 4472955c..7a670763 100644 --- a/pyo3cls/src/py_class.rs +++ b/pyo3cls/src/py_class.rs @@ -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()); } }); } diff --git a/src/lib.rs b/src/lib.rs index 401e19be..c498a32d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(specialization, const_fn, proc_macro)] +#![feature(specialization, proc_macro, const_fn, associated_consts)] //! Rust bindings to the Python interpreter. //! diff --git a/src/objects/mod.rs b/src/objects/mod.rs index 47d5b5b8..4cd88a57 100644 --- a/src/objects/mod.rs +++ b/src/objects/mod.rs @@ -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 { diff --git a/src/objects/module.rs b/src/objects/module.rs index c7bf367c..39686d60 100644 --- a/src/objects/module.rs +++ b/src/objects/module.rs @@ -109,23 +109,21 @@ impl PyModule { pub fn add_class(&self) -> PyResult<()> where T: ::typeob::PyTypeInfo { - let mut ty = ::type_object(); - let type_name = ::type_name(); + let mut ty = unsafe{::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 = ::type_description(); ::typeob::initialize_type::( - self.token(), Some(name), type_name, type_description, ty) - .expect(format!("An error occurred while initializing class {}", - ::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) } } diff --git a/src/typeob.rs b/src/typeob.rs index 036016a0..0340899a 100644 --- a/src/typeob.rs +++ b/src/typeob.rs @@ -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 { - ::type_name() - } - - #[inline] - default fn type_object() -> &'static mut ffi::PyTypeObject { + default unsafe fn type_object() -> &'static mut ffi::PyTypeObject { ::type_object() } @@ -140,15 +134,12 @@ impl PyTypeObject for T where T: PyObjectAlloc + PyTypeInfo { #[inline] default fn init_type(py: Python) { - let mut ty = ::type_object(); + let mut ty = unsafe { ::type_object() }; if (ty.tp_flags & ffi::Py_TPFLAGS_READY) == 0 { // automatically initialize the class on-demand - initialize_type::( - py, None, ::type_name(), - ::type_description(), ty).expect( - format!("An error occurred while initializing class {}", - ::type_name()).as_ref()); + initialize_type::(py, None, ty).expect( + format!("An error occurred while initializing class {}", T::NAME).as_ref()); } } @@ -163,21 +154,19 @@ impl PyTypeObject for T where T: PyObjectAlloc + 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 + 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::); diff --git a/tests/test_buffer_protocol.rs b/tests/test_buffer_protocol.rs index 2c37b684..0ad10c64 100644 --- a/tests/test_buffer_protocol.rs +++ b/tests/test_buffer_protocol.rs @@ -1,5 +1,5 @@ #![allow(dead_code, unused_variables)] -#![feature(proc_macro, specialization)] +#![feature(proc_macro, specialization, associated_consts)] extern crate pyo3; diff --git a/tests/test_class.rs b/tests/test_class.rs index c95b86fe..eff717bc 100644 --- a/tests/test_class.rs +++ b/tests/test_class.rs @@ -1,4 +1,4 @@ -#![feature(proc_macro, specialization)] +#![feature(proc_macro, specialization, associated_consts)] #![allow(dead_code, unused_variables)] extern crate pyo3; diff --git a/tests/test_slice.rs b/tests/test_slice.rs index 20e31317..8cedc178 100644 --- a/tests/test_slice.rs +++ b/tests/test_slice.rs @@ -1,4 +1,4 @@ -#![feature(proc_macro, specialization)] +#![feature(proc_macro, specialization, associated_consts)] #![allow(dead_code, unused_variables)] extern crate pyo3;