drop RefFromPyObject; allow mut refs #106
This commit is contained in:
parent
35e91a5cd1
commit
324a6b2697
|
@ -1,7 +1,13 @@
|
|||
Changes
|
||||
-------
|
||||
|
||||
0.2.4 (2018-01-xx)
|
||||
0.2.4 (2018-01-19)
|
||||
|
||||
* Allow to get mutable ref from PyObject #106
|
||||
|
||||
* Drop `RefFromPyObject` trait
|
||||
|
||||
* Add Python::register_any() method
|
||||
|
||||
* Fix impl `FromPyObject` for `Py<T>`
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "pyo3"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
description = "Bindings to Python interpreter"
|
||||
authors = ["PyO3 Project and Contributors"]
|
||||
readme = "README.md"
|
||||
|
@ -19,11 +19,11 @@ appveyor = { repository = "PyO3/pyo3" }
|
|||
codecov = { repository = "PyO3/pyo3", branch = "master", service = "github" }
|
||||
|
||||
[dependencies]
|
||||
log = "0.3"
|
||||
log = "0.4"
|
||||
libc = "0.2"
|
||||
spin = "0.4.6"
|
||||
num-traits = "0.1"
|
||||
pyo3cls = { path = "pyo3cls", version = "0.2" }
|
||||
pyo3cls = { path = "pyo3cls", version = "^0.2.1" }
|
||||
|
||||
[build-dependencies]
|
||||
regex = "0.2"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "pyo3cls"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
description = "Proc macros for PyO3 package"
|
||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3"]
|
||||
homepage = "https://github.com/pyo3/pyo3"
|
||||
|
|
|
@ -462,119 +462,52 @@ fn impl_arg_param(arg: &FnArg, spec: &FnSpec, body: &Tokens, idx: usize) -> Toke
|
|||
syn::Ident::from("None").to_tokens(&mut default);
|
||||
}
|
||||
|
||||
if arg.reference {
|
||||
quote! {
|
||||
quote! {
|
||||
match
|
||||
match _iter.next().unwrap().as_ref() {
|
||||
Some(obj) => {
|
||||
if obj.is_none() {
|
||||
let #arg_name = #default;
|
||||
#body
|
||||
} else {
|
||||
match _pyo3::RefFromPyObject::with_extracted(
|
||||
obj, |#name| {
|
||||
let #arg_name = Some(#name);
|
||||
#body
|
||||
})
|
||||
{
|
||||
Ok(v) => v,
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
},
|
||||
None => {
|
||||
let #arg_name = #default;
|
||||
#body
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
match
|
||||
match _iter.next().unwrap().as_ref() {
|
||||
Some(_obj) => {
|
||||
if _obj.is_none() {
|
||||
Ok(#default)
|
||||
} else {
|
||||
match _obj.extract() {
|
||||
Ok(_obj) => Ok(Some(_obj)),
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
},
|
||||
None => Ok(#default) }
|
||||
{
|
||||
Ok(#arg_name) => #body,
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let Some(default) = spec.default_value(name) {
|
||||
if arg.reference {
|
||||
quote! {
|
||||
match _iter.next().unwrap().as_ref() {
|
||||
Some(_obj) => {
|
||||
if _obj.is_none() {
|
||||
let #arg_name = #default;
|
||||
#body
|
||||
} else {
|
||||
match _pyo3::RefFromPyObject::with_extracted(
|
||||
_obj, |#arg_name| {
|
||||
#body
|
||||
})
|
||||
{
|
||||
Ok(v) => v,
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
},
|
||||
None => {
|
||||
let #arg_name = #default;
|
||||
#body
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
match match _iter.next().unwrap().as_ref() {
|
||||
Some(_obj) => {
|
||||
if _obj.is_none() {
|
||||
Ok(#default)
|
||||
} else {
|
||||
match _obj.extract() {
|
||||
Ok(_obj) => Ok(_obj),
|
||||
Err(e) => Err(e),
|
||||
Ok(_obj) => Ok(Some(_obj)),
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
},
|
||||
None => Ok(#default)
|
||||
} {
|
||||
Ok(#arg_name) => #body,
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
None => Ok(#default) }
|
||||
{
|
||||
Ok(#arg_name) => #body,
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
} else if let Some(default) = spec.default_value(name) {
|
||||
quote! {
|
||||
match match _iter.next().unwrap().as_ref() {
|
||||
Some(_obj) => {
|
||||
if _obj.is_none() {
|
||||
Ok(#default)
|
||||
} else {
|
||||
match _obj.extract() {
|
||||
Ok(_obj) => Ok(_obj),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
},
|
||||
None => Ok(#default)
|
||||
} {
|
||||
Ok(#arg_name) => #body,
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if arg.reference {
|
||||
quote! {
|
||||
match _pyo3::RefFromPyObject::with_extracted(
|
||||
_iter.next().unwrap().as_ref().unwrap(), |#arg_name| {
|
||||
#body
|
||||
})
|
||||
{
|
||||
Ok(v) => v,
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
match _iter.next().unwrap().as_ref().unwrap().extract()
|
||||
{
|
||||
Ok(#arg_name) => {
|
||||
#body
|
||||
}
|
||||
Err(e) => Err(e)
|
||||
quote! {
|
||||
match _iter.next().unwrap().as_ref().unwrap().extract() {
|
||||
Ok(#arg_name) => {
|
||||
#body
|
||||
}
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,6 @@ impl<T> ToBorrowedObject for T where T: ToPyObject {
|
|||
pub trait IntoPyObject {
|
||||
|
||||
/// Converts self into a Python object. (Consumes self)
|
||||
#[inline]
|
||||
fn into_object(self, py: Python) -> PyObject;
|
||||
}
|
||||
|
||||
|
@ -86,25 +85,6 @@ pub trait FromPyObject<'source> : Sized {
|
|||
fn extract(ob: &'source PyObjectRef) -> PyResult<Self>;
|
||||
}
|
||||
|
||||
pub trait RefFromPyObject {
|
||||
fn with_extracted<F, R>(ob: &PyObjectRef, f: F) -> PyResult<R>
|
||||
where F: FnOnce(&Self) -> R;
|
||||
}
|
||||
|
||||
impl <T: ?Sized> RefFromPyObject for T
|
||||
where for<'a> &'a T: FromPyObject<'a> + Sized
|
||||
{
|
||||
#[inline]
|
||||
fn with_extracted<F, R>(obj: &PyObjectRef, f: F) -> PyResult<R>
|
||||
where F: FnOnce(&Self) -> R
|
||||
{
|
||||
match FromPyObject::extract(obj) {
|
||||
Ok(val) => Ok(f(val)),
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Identity conversion: allows using existing `PyObject` instances where
|
||||
/// `T: ToPyObject` is expected.
|
||||
impl <'a, T: ?Sized> ToPyObject for &'a T where T: ToPyObject {
|
||||
|
@ -115,7 +95,6 @@ impl <'a, T: ?Sized> ToPyObject for &'a T where T: ToPyObject {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// `Option::Some<T>` is converted like `T`.
|
||||
/// `Option::None` is converted to Python `None`.
|
||||
impl <T> ToPyObject for Option<T> where T: ToPyObject {
|
||||
|
@ -127,6 +106,7 @@ impl <T> ToPyObject for Option<T> where T: ToPyObject {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoPyObject for Option<T> where T: IntoPyObject {
|
||||
|
||||
fn into_object(self, py: Python) -> PyObject {
|
||||
|
@ -158,8 +138,7 @@ impl<'a, T> IntoPyObject for &'a T where T: ToPyPointer
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T> IntoPyObject for &'a mut T where T: ToPyPointer
|
||||
{
|
||||
impl<'a, T> IntoPyObject for &'a mut T where T: ToPyPointer {
|
||||
#[inline]
|
||||
fn into_object<'p>(self, py: Python) -> PyObject {
|
||||
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
|
||||
|
@ -171,16 +150,24 @@ impl<'a, T> FromPyObject<'a> for &'a T
|
|||
where T: PyTypeInfo
|
||||
{
|
||||
#[inline]
|
||||
default fn extract(ob: &'a PyObjectRef) -> PyResult<&'a T>
|
||||
{
|
||||
default fn extract(ob: &'a PyObjectRef) -> PyResult<&'a T> {
|
||||
Ok(T::try_from(ob)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'source, T> FromPyObject<'source> for Option<T> where T: FromPyObject<'source>
|
||||
/// Extract mutable reference to instance from `PyObject`
|
||||
impl<'a, T> FromPyObject<'a> for &'a mut T
|
||||
where T: PyTypeInfo
|
||||
{
|
||||
fn extract(obj: &'source PyObjectRef) -> PyResult<Self>
|
||||
{
|
||||
#[inline]
|
||||
default fn extract(ob: &'a PyObjectRef) -> PyResult<&'a mut T> {
|
||||
Ok(T::try_from_mut(ob)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> FromPyObject<'a> for Option<T> where T: FromPyObject<'a>
|
||||
{
|
||||
fn extract(obj: &'a PyObjectRef) -> PyResult<Self> {
|
||||
if obj.as_ptr() == unsafe { ffi::Py_None() } {
|
||||
Ok(None)
|
||||
} else {
|
||||
|
@ -192,7 +179,6 @@ impl<'source, T> FromPyObject<'source> for Option<T> where T: FromPyObject<'sour
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// Trait implemented by Python object types that allow a checked downcast.
|
||||
/// This trait is similar to `std::convert::TryInto`
|
||||
pub trait PyTryInto<T>: Sized {
|
||||
|
@ -232,8 +218,8 @@ pub trait PyTryFrom: Sized {
|
|||
}
|
||||
|
||||
// TryFrom implies TryInto
|
||||
impl<U> PyTryInto<U> for PyObjectRef where U: PyTryFrom
|
||||
{
|
||||
impl<U> PyTryInto<U> for PyObjectRef where U: PyTryFrom {
|
||||
|
||||
type Error = U::Error;
|
||||
|
||||
fn try_into(&self) -> Result<&U, U::Error> {
|
||||
|
@ -251,9 +237,8 @@ impl<U> PyTryInto<U> for PyObjectRef where U: PyTryFrom
|
|||
}
|
||||
|
||||
|
||||
impl<T> PyTryFrom for T
|
||||
where T: PyTypeInfo
|
||||
{
|
||||
impl<T> PyTryFrom for T where T: PyTypeInfo {
|
||||
|
||||
type Error = PyDowncastError;
|
||||
|
||||
fn try_from(value: &PyObjectRef) -> Result<&T, Self::Error> {
|
||||
|
|
|
@ -164,7 +164,7 @@ pub use typeob::{PyTypeInfo, PyRawObject, PyObjectAlloc};
|
|||
pub use python::{Python, ToPyPointer, IntoPyPointer, IntoPyDictPointer};
|
||||
pub use pythonrun::{GILGuard, GILPool, prepare_freethreaded_python, prepare_pyo3_library};
|
||||
pub use instance::{PyToken, PyObjectWithToken, AsPyRef, Py, PyNativeType};
|
||||
pub use conversion::{FromPyObject, RefFromPyObject, PyTryFrom, PyTryInto,
|
||||
pub use conversion::{FromPyObject, PyTryFrom, PyTryInto,
|
||||
ToPyObject, ToBorrowedObject, IntoPyObject, IntoPyTuple};
|
||||
pub mod class;
|
||||
pub use class::*;
|
||||
|
|
|
@ -5,8 +5,8 @@ use err::PyResult;
|
|||
use python::Python;
|
||||
use object::PyObject;
|
||||
use objects::{PyObjectRef, PyString};
|
||||
use objectprotocol::ObjectProtocol;
|
||||
use conversion::{ToPyObject, IntoPyObject, RefFromPyObject, PyTryFrom};
|
||||
use instance::PyObjectWithToken;
|
||||
use conversion::{ToPyObject, IntoPyObject, PyTryFrom};
|
||||
|
||||
/// Converts Rust `str` to Python object.
|
||||
/// See `PyString::new` for details on the conversion.
|
||||
|
@ -55,25 +55,29 @@ impl<'a> IntoPyObject for &'a String {
|
|||
|
||||
/// Allows extracting strings from Python objects.
|
||||
/// Accepts Python `str` and `unicode` objects.
|
||||
impl<'source> ::FromPyObject<'source> for Cow<'source, str>
|
||||
{
|
||||
fn extract(ob: &'source PyObjectRef) -> PyResult<Self>
|
||||
{
|
||||
impl<'source> ::FromPyObject<'source> for Cow<'source, str> {
|
||||
fn extract(ob: &'source PyObjectRef) -> PyResult<Self> {
|
||||
PyString::try_from(ob)?.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows extracting strings from Python objects.
|
||||
/// Accepts Python `str` and `unicode` objects.
|
||||
impl<'a> ::FromPyObject<'a> for &'a str {
|
||||
fn extract(ob: &'a PyObjectRef) -> PyResult<Self> {
|
||||
let s: Cow<'a, str> = ::FromPyObject::extract(ob)?;
|
||||
match s {
|
||||
Cow::Borrowed(r) => Ok(r),
|
||||
Cow::Owned(r) => {
|
||||
let r = ob.py().register_any(r);
|
||||
Ok(r.as_str())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows extracting strings from Python objects.
|
||||
/// Accepts Python `str` and `unicode` objects.
|
||||
pyobject_extract!(obj to String => {
|
||||
<PyString as PyTryFrom>::try_from(obj)?.to_string().map(Cow::into_owned)
|
||||
});
|
||||
|
||||
impl RefFromPyObject for str {
|
||||
fn with_extracted<F, R>(obj: &PyObjectRef, f: F) -> PyResult<R>
|
||||
where F: FnOnce(&str) -> R
|
||||
{
|
||||
let s = try!(obj.extract::<Cow<str>>());
|
||||
Ok(f(&s))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,5 +21,5 @@ pub use err::{PyErr, PyErrValue, PyResult, PyDowncastError, PyErrArguments};
|
|||
pub use pythonrun::GILGuard;
|
||||
pub use typeob::PyRawObject;
|
||||
pub use instance::{PyToken, PyObjectWithToken, AsPyRef, Py, PyNativeType};
|
||||
pub use conversion::{FromPyObject, RefFromPyObject, PyTryFrom, PyTryInto,
|
||||
pub use conversion::{FromPyObject, PyTryFrom, PyTryInto,
|
||||
ToPyObject, ToBorrowedObject, IntoPyObject, IntoPyTuple};
|
||||
|
|
|
@ -391,6 +391,13 @@ impl<'p> Python<'p> {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
/// Pass value owneship to `Python` object and get reference back.
|
||||
/// Value get cleaned up on the GIL release.
|
||||
pub fn register_any<T: 'static>(self, ob: T) -> &'p T {
|
||||
unsafe { pythonrun::register_any(ob) }
|
||||
}
|
||||
|
||||
/// Release PyObject reference.
|
||||
#[inline]
|
||||
pub fn release<T>(self, ob: T) where T: IntoPyPointer {
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
//
|
||||
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
|
||||
|
||||
use std::{sync, rc, marker, mem};
|
||||
use std::{any, sync, rc, marker, mem};
|
||||
use spin;
|
||||
|
||||
use ffi;
|
||||
|
@ -113,16 +110,18 @@ struct ReleasePool {
|
|||
owned: Vec<*mut ffi::PyObject>,
|
||||
borrowed: Vec<*mut ffi::PyObject>,
|
||||
pointers: *mut Vec<*mut ffi::PyObject>,
|
||||
obj: Vec<Box<any::Any>>,
|
||||
p: spin::Mutex<*mut Vec<*mut ffi::PyObject>>,
|
||||
}
|
||||
|
||||
impl ReleasePool {
|
||||
fn new() -> ReleasePool {
|
||||
ReleasePool {
|
||||
owned: Vec::with_capacity(250),
|
||||
borrowed: Vec::with_capacity(250),
|
||||
pointers: Box::into_raw(Box::new(Vec::with_capacity(250))),
|
||||
p: spin::Mutex::new(Box::into_raw(Box::new(Vec::with_capacity(250)))),
|
||||
owned: Vec::with_capacity(256),
|
||||
borrowed: Vec::with_capacity(256),
|
||||
pointers: Box::into_raw(Box::new(Vec::with_capacity(256))),
|
||||
obj: Vec::with_capacity(8),
|
||||
p: spin::Mutex::new(Box::into_raw(Box::new(Vec::with_capacity(256)))),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,6 +164,8 @@ impl ReleasePool {
|
|||
if pointers {
|
||||
self.release_pointers();
|
||||
}
|
||||
|
||||
self.obj.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,6 +207,14 @@ impl Drop for GILPool {
|
|||
}
|
||||
}
|
||||
|
||||
pub unsafe fn register_any<'p, T: 'static>(obj: T) -> &'p T
|
||||
{
|
||||
let pool: &'static mut ReleasePool = &mut *POOL;
|
||||
|
||||
pool.obj.push(Box::new(obj));
|
||||
pool.obj.last().unwrap().as_ref().downcast_ref::<T>().unwrap()
|
||||
}
|
||||
|
||||
pub unsafe fn register_pointer(obj: *mut ffi::PyObject)
|
||||
{
|
||||
let pool: &'static mut ReleasePool = &mut *POOL;
|
||||
|
|
|
@ -1411,3 +1411,37 @@ fn inheritance_with_new_methods_with_drop() {
|
|||
assert!(drop_called1.load(Ordering::Relaxed));
|
||||
assert!(drop_called2.load(Ordering::Relaxed));
|
||||
}
|
||||
|
||||
|
||||
#[py::class]
|
||||
struct MutRefArg {
|
||||
n: i32,
|
||||
token: PyToken,
|
||||
}
|
||||
|
||||
#[py::methods]
|
||||
impl MutRefArg {
|
||||
|
||||
fn get(&self) -> PyResult<i32> {
|
||||
Ok(self.n)
|
||||
}
|
||||
fn set_other(&self, other: &mut MutRefArg) -> PyResult<()> {
|
||||
other.n = 100;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mut_ref_arg() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let inst1 = py.init(|t| MutRefArg{token: t, n: 0}).unwrap();
|
||||
let inst2 = py.init(|t| MutRefArg{token: t, n: 0}).unwrap();
|
||||
|
||||
let d = PyDict::new(py);
|
||||
d.set_item("inst1", &inst1).unwrap();
|
||||
d.set_item("inst2", &inst2).unwrap();
|
||||
|
||||
py.run("inst1.set_other(inst2)", None, Some(d)).unwrap();
|
||||
assert_eq!(inst2.as_ref(py).n, 100);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue