Simplify IntoInitializer

This commit is contained in:
David Hewitt 2020-01-06 13:14:41 +00:00
parent 18e565fab5
commit 60edeb889e
6 changed files with 50 additions and 49 deletions

View file

@ -257,10 +257,10 @@ struct SubSubClass {
#[pymethods]
impl SubSubClass {
#[new]
fn new() -> impl IntoInitializer<Self> {
Ok(SubClass::new()
.into_initializer()?
.add_subclass(SubSubClass{val3: 20}))
fn new() -> PyClassInitializer<Self> {
SubClass::new()
.into_initializer()
.add_subclass(SubSubClass{val3: 20})
}
fn method3(self_: &PyClassShell<Self>) -> PyResult<usize> {

View file

@ -154,7 +154,7 @@ pub fn impl_wrap_new(cls: &syn::Type, spec: &FnSpec<'_>) -> TokenStream {
let body = impl_arg_params_(
spec,
cb,
quote! { pyo3::pyclass_init::IntoInitializer::into_initializer },
quote! { pyo3::derive_utils::IntoPyNewResult::into_pynew_result },
);
quote! {
@ -174,7 +174,7 @@ pub fn impl_wrap_new(cls: &syn::Type, spec: &FnSpec<'_>) -> TokenStream {
#body
match _result.and_then(|init| init.create_shell(_py)) {
match _result.and_then(|init| init.into_initializer().create_shell(_py)) {
Ok(slf) => slf as _,
Err(e) => e.restore_and_null(_py),
}

View file

@ -10,6 +10,7 @@ use crate::init_once;
use crate::instance::PyNativeType;
use crate::types::{PyAny, PyDict, PyModule, PyTuple};
use crate::{ffi, GILPool, IntoPy, PyObject, Python};
use crate::pyclass_init::IntoInitializer;
use std::ptr;
/// Description of a python parameter; used for `parse_args()`.
@ -179,3 +180,23 @@ impl<T: IntoPy<PyObject>> IntoPyResult<T> for PyResult<T> {
self
}
}
use crate::pyclass::PyClass;
/// Variant of IntoPyResult for the specific case of #[new]. In the case of returning (Sub, Base)
/// from #[new], IntoPyResult can't apply because (Sub, Base) doesn't implement IntoPy<PyObject>.
pub trait IntoPyNewResult<T: PyClass, I: IntoInitializer<T>> {
fn into_pynew_result(self) -> PyResult<I>;
}
impl<T: PyClass, I: IntoInitializer<T>> IntoPyNewResult<T, I> for I {
fn into_pynew_result(self) -> PyResult<I> {
Ok(self)
}
}
impl<T: PyClass, I: IntoInitializer<T>> IntoPyNewResult<T, I> for PyResult<I> {
fn into_pynew_result(self) -> PyResult<I> {
self
}
}

View file

@ -42,7 +42,7 @@ impl<T> Py<T> {
<T::BaseType as PyTypeInfo>::ConcreteLayout:
crate::type_object::PyObjectSizedLayout<T::BaseType>,
{
let initializer = value.into_initializer()?;
let initializer = value.into_initializer();
let obj = unsafe { initializer.create_shell(py)? };
let ob = unsafe { Py::from_owned_ptr(obj as _) };
Ok(ob)

View file

@ -136,7 +136,7 @@ impl<T: PyClass> PyClassShell<T> {
crate::type_object::PyObjectSizedLayout<T::BaseType>,
{
unsafe {
let initializer = value.into_initializer()?;
let initializer = value.into_initializer();
let self_ = initializer.create_shell(py)?;
FromPyPointer::from_owned_ptr_or_err(py, self_ as _)
}
@ -149,7 +149,7 @@ impl<T: PyClass> PyClassShell<T> {
crate::type_object::PyObjectSizedLayout<T::BaseType>,
{
unsafe {
let initializer = value.into_initializer()?;
let initializer = value.into_initializer();
let self_ = initializer.create_shell(py)?;
FromPyPointer::from_owned_ptr_or_err(py, self_ as _)
}

View file

@ -109,30 +109,33 @@ impl<T: PyClass> PyObjectInit<T> for PyClassInitializer<T> {
}
}
/// Represets that we can convert the type to `PyClassInitializer`.
///
/// It is mainly used in our proc-macro code.
pub trait IntoInitializer<T: PyClass> {
fn into_initializer(self) -> PyResult<PyClassInitializer<T>>;
}
impl<T> IntoInitializer<T> for T
impl<T> From<T> for PyClassInitializer<T>
where
T: PyClass,
T::BaseType: PyTypeInfo<Initializer = PyNativeTypeInitializer<T::BaseType>>,
{
fn into_initializer(self) -> PyResult<PyClassInitializer<T>> {
Ok(PyClassInitializer::from_value(self))
fn from(value: T) -> PyClassInitializer<T> {
PyClassInitializer::from_value(value)
}
}
impl<T> IntoInitializer<T> for PyResult<T>
/// An extension of Into which extends the range of possible types from `#[pyclass]`'s `#[new]`.
///
/// In particular it permits for the return type of `#[new]` to be a (SubType, BaseType) pair
/// which will also be initialized.
///
/// It is mainly used in our proc-macro code.
pub trait IntoInitializer<T: PyClass> {
fn into_initializer(self) -> PyClassInitializer<T>;
}
impl<T, U> IntoInitializer<T> for U
where
T: PyClass,
T::BaseType: PyTypeInfo<Initializer = PyNativeTypeInitializer<T::BaseType>>,
U: Into<PyClassInitializer<T>>
{
fn into_initializer(self) -> PyResult<PyClassInitializer<T>> {
self.map(PyClassInitializer::from_value)
fn into_initializer(self) -> PyClassInitializer<T> {
self.into()
}
}
@ -142,31 +145,8 @@ where
B: PyClass + PyTypeInfo<Initializer = PyClassInitializer<B>>,
B::BaseType: PyTypeInfo<Initializer = PyNativeTypeInitializer<B::BaseType>>,
{
fn into_initializer(self) -> PyResult<PyClassInitializer<S>> {
let (sub, base) = self;
Ok(PyClassInitializer::from_value(base).add_subclass(sub))
}
}
impl<S, B> IntoInitializer<S> for PyResult<(S, B)>
where
S: PyClass + PyTypeInfo<BaseType = B>,
B: PyClass + PyTypeInfo<Initializer = PyClassInitializer<B>>,
B::BaseType: PyTypeInfo<Initializer = PyNativeTypeInitializer<B::BaseType>>,
{
fn into_initializer(self) -> PyResult<PyClassInitializer<S>> {
self.map(|(sub, base)| PyClassInitializer::from_value(base).add_subclass(sub))
}
}
impl<T: PyClass> IntoInitializer<T> for PyClassInitializer<T> {
fn into_initializer(self) -> PyResult<PyClassInitializer<T>> {
Ok(self)
}
}
impl<T: PyClass> IntoInitializer<T> for PyResult<PyClassInitializer<T>> {
fn into_initializer(self) -> PyResult<PyClassInitializer<T>> {
self
fn into_initializer(self) -> PyClassInitializer<S> {
let (sub, base_init) = self;
base_init.into_initializer().add_subclass(sub)
}
}