Simplify ToPyObject: directly return the object without PyResult
to_py_object should always succeed (modulo out-of-memory)
This commit is contained in:
parent
1e5605036e
commit
fbd60f11f4
|
@ -9,14 +9,14 @@ pub trait ToPyObject<'p> {
|
|||
type ObjectType : PythonObject<'p> = PyObject<'p>;
|
||||
|
||||
/// Converts self into a python object.
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, Self::ObjectType>;
|
||||
fn to_py_object(&self, py: Python<'p>) -> Self::ObjectType;
|
||||
|
||||
/// Converts self into a python object.
|
||||
///
|
||||
/// May be more efficient than `to_py_object` in some cases because
|
||||
/// it can move out of the input object.
|
||||
#[inline]
|
||||
fn into_py_object(self, py: Python<'p>) -> PyResult<'p, Self::ObjectType>
|
||||
fn into_py_object(self, py: Python<'p>) -> Self::ObjectType
|
||||
where Self: Sized {
|
||||
self.to_py_object(py)
|
||||
}
|
||||
|
@ -27,9 +27,9 @@ pub trait ToPyObject<'p> {
|
|||
/// May be more efficient than `to_py_object` because it does not need
|
||||
/// to touch any reference counts when the input object already is a python object.
|
||||
#[inline]
|
||||
fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> PyResult<'p, R>
|
||||
where F: FnOnce(*mut ffi::PyObject) -> PyResult<'p, R> {
|
||||
let obj = try!(self.to_py_object(py));
|
||||
fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> R
|
||||
where F: FnOnce(*mut ffi::PyObject) -> R {
|
||||
let obj = self.to_py_object(py);
|
||||
f(ToPythonPointer::as_ptr(&obj))
|
||||
}
|
||||
|
||||
|
@ -62,22 +62,27 @@ pub trait FromPyObject<'p, 's> {
|
|||
// This allows using existing python objects in code that generically expects a value
|
||||
// convertible to a python object.
|
||||
|
||||
impl <'p> ToPyObject<'p> for PyObject<'p> {
|
||||
/// Identity conversion: allows using existing `PyObject` instances where
|
||||
/// `ToPyObject` is expected.
|
||||
impl <'p, 's> ToPyObject<'p> for PyObject<'s> {
|
||||
type ObjectType = PyObject<'p>;
|
||||
|
||||
#[inline]
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, PyObject<'p>> {
|
||||
Ok(self.clone())
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyObject<'p> {
|
||||
self.clone().into_py_object(py)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_py_object(self, py: Python<'p>) -> PyResult<'p, PyObject<'p>> {
|
||||
Ok(self)
|
||||
fn into_py_object(self, py: Python<'p>) -> PyObject<'p> {
|
||||
// Transmute the lifetime.
|
||||
// This is safe, because both lifetime variables represent the same lifetime:
|
||||
// that of the python GIL acquisition.
|
||||
unsafe { std::mem::transmute(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> PyResult<'p, R>
|
||||
where F: FnOnce(*mut ffi::PyObject) -> PyResult<'p, R> {
|
||||
fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> R
|
||||
where F: FnOnce(*mut ffi::PyObject) -> R {
|
||||
f(self.as_ptr())
|
||||
}
|
||||
}
|
||||
|
@ -94,21 +99,21 @@ impl <'p, 's, T> FromPyObject<'p, 's> for T where T: PythonObjectWithCheckedDown
|
|||
// This allows using existing python objects in code that generically expects a value
|
||||
// convertible to a python object.
|
||||
impl <'p, 's, T> ToPyObject<'p> for &'s T where T : ToPyObject<'p> {
|
||||
type ObjectType = <T as ToPyObject<'p>>::ObjectType;
|
||||
type ObjectType = T::ObjectType;
|
||||
|
||||
#[inline]
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, <T as ToPyObject<'p>>::ObjectType> {
|
||||
fn to_py_object(&self, py: Python<'p>) -> T::ObjectType {
|
||||
(**self).to_py_object(py)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_py_object(self, py: Python<'p>) -> PyResult<'p, <T as ToPyObject<'p>>::ObjectType> {
|
||||
fn into_py_object(self, py: Python<'p>) -> T::ObjectType {
|
||||
(*self).to_py_object(py)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> PyResult<'p, R>
|
||||
where F: FnOnce(*mut ffi::PyObject) -> PyResult<'p, R> {
|
||||
fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> R
|
||||
where F: FnOnce(*mut ffi::PyObject) -> R {
|
||||
(**self).with_borrowed_ptr(py, f)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ impl <'p> PyErr<'p> {
|
|||
} else {
|
||||
PyErr {
|
||||
ptype: py.get_type::<exc::TypeError>().into_object(),
|
||||
pvalue: "exceptions must derive from BaseException".to_py_object(py).ok(),
|
||||
pvalue: Some("exceptions must derive from BaseException".to_py_object(py)),
|
||||
ptraceback: None
|
||||
}
|
||||
}
|
||||
|
|
13
src/lib.rs
13
src/lib.rs
|
@ -169,15 +169,14 @@ macro_rules! py_func {
|
|||
let py = $crate::Python::assume_gil_acquired();
|
||||
let args = $crate::PyObject::from_borrowed_ptr(py, args);
|
||||
let args: &$crate::PyTuple = $crate::PythonObject::unchecked_downcast_borrow_from(&args);
|
||||
let result = match $f(py, args) {
|
||||
Ok(val) => $crate::ToPyObject::into_py_object(val, py),
|
||||
Err(e) => Err(e)
|
||||
};
|
||||
match result {
|
||||
Ok(val) => $crate::ToPythonPointer::steal_ptr(val),
|
||||
match $f(py, args) {
|
||||
Ok(val) => {
|
||||
let obj = $crate::ToPyObject::into_py_object(val, py);
|
||||
return $crate::ToPythonPointer::steal_ptr(obj);
|
||||
}
|
||||
Err(e) => {
|
||||
e.restore();
|
||||
::std::ptr::null_mut()
|
||||
return ::std::ptr::null_mut();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,13 +23,13 @@ impl <'p> ToPyObject<'p> for bool {
|
|||
type ObjectType = PyBool<'p>;
|
||||
|
||||
#[inline]
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, PyBool<'p>> {
|
||||
Ok(PyBool::get(py, *self))
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyBool<'p> {
|
||||
PyBool::get(py, *self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> PyResult<'p, R>
|
||||
where F: FnOnce(*mut ffi::PyObject) -> PyResult<'p, R>
|
||||
fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> R
|
||||
where F: FnOnce(*mut ffi::PyObject) -> R
|
||||
{
|
||||
// Avoid unnecessary Py_INCREF/Py_DECREF pair
|
||||
f(unsafe { if *self { ffi::Py_True() } else { ffi::Py_False() } })
|
||||
|
|
|
@ -60,15 +60,15 @@ impl <'p> PyList<'p> {
|
|||
impl <'p, T> ToPyObject<'p> for [T] where T: ToPyObject<'p> {
|
||||
type ObjectType = PyList<'p>;
|
||||
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, PyList<'p>> {
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyList<'p> {
|
||||
unsafe {
|
||||
let ptr = ffi::PyList_New(self.len() as Py_ssize_t);
|
||||
let t = try!(err::result_from_owned_ptr(py, ptr)).unchecked_cast_into::<PyList>();
|
||||
let t = err::cast_from_owned_ptr_or_panic(py, ptr);
|
||||
for (i, e) in self.iter().enumerate() {
|
||||
let obj = try!(e.to_py_object(py));
|
||||
let obj = e.to_py_object(py);
|
||||
ffi::PyList_SET_ITEM(ptr, i as Py_ssize_t, obj.steal_ptr());
|
||||
}
|
||||
Ok(t)
|
||||
t
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ impl <'p> PyModule<'p> {
|
|||
pub fn add<V>(&self, name: &str, value: V) -> PyResult<'p, ()> where V: ToPyObject<'p> {
|
||||
let py = self.python();
|
||||
let name = CString::new(name).unwrap();
|
||||
let value = try!(value.into_py_object(py));
|
||||
let value = value.into_py_object(py);
|
||||
let r = unsafe { ffi::PyModule_AddObject(self.as_ptr(), name.as_ptr(), value.steal_ptr()) };
|
||||
err::error_on_minusone(py, r)
|
||||
}
|
||||
|
|
|
@ -45,10 +45,10 @@ macro_rules! int_fits_c_long(
|
|||
impl <'p> ToPyObject<'p> for $rust_type {
|
||||
type ObjectType = PyInt<'p>;
|
||||
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, PyInt<'p>> {
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyInt<'p> {
|
||||
unsafe {
|
||||
Ok(try!(err::result_from_owned_ptr(py,
|
||||
ffi::PyInt_FromLong(*self as c_long))).unchecked_cast_into::<PyInt>())
|
||||
err::cast_from_owned_ptr_or_panic(py,
|
||||
ffi::PyInt_FromLong(*self as c_long))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ macro_rules! int_fits_larger_int(
|
|||
type ObjectType = <$larger_type as ToPyObject<'p>>::ObjectType;
|
||||
|
||||
#[inline]
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, <$larger_type as ToPyObject<'p>>::ObjectType> {
|
||||
fn to_py_object(&self, py: Python<'p>) -> <$larger_type as ToPyObject<'p>>::ObjectType {
|
||||
(*self as $larger_type).to_py_object(py)
|
||||
}
|
||||
}
|
||||
|
@ -123,13 +123,13 @@ int_fits_larger_int!(usize, u64);
|
|||
impl <'p> ToPyObject<'p> for u64 {
|
||||
type ObjectType = PyObject<'p>;
|
||||
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, PyObject<'p>> {
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyObject<'p> {
|
||||
unsafe {
|
||||
let ptr = match std::num::cast::<u64, c_long>(*self) {
|
||||
Some(v) => ffi::PyInt_FromLong(v),
|
||||
None => ffi::PyLong_FromUnsignedLongLong(*self)
|
||||
};
|
||||
err::result_from_owned_ptr(py, ptr)
|
||||
err::from_owned_ptr_or_panic(py, ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -167,8 +167,8 @@ impl <'p, 's> FromPyObject<'p, 's> for u64 {
|
|||
impl <'p> ToPyObject<'p> for f64 {
|
||||
type ObjectType = PyFloat<'p>;
|
||||
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, PyFloat<'p>> {
|
||||
Ok(PyFloat::new(py, *self))
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyFloat<'p> {
|
||||
PyFloat::new(py, *self)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,8 +191,8 @@ fn overflow_error(py: Python) -> PyErr {
|
|||
impl <'p> ToPyObject<'p> for f32 {
|
||||
type ObjectType = PyFloat<'p>;
|
||||
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, PyFloat<'p>> {
|
||||
Ok(PyFloat::new(py, *self as f64))
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyFloat<'p> {
|
||||
PyFloat::new(py, *self as f64)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,7 +215,7 @@ mod test {
|
|||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let val = 123 as $t1;
|
||||
let obj = val.to_py_object(py).unwrap().into_object();
|
||||
let obj = val.to_py_object(py).into_object();
|
||||
assert_eq!(obj.extract::<$t2>().unwrap(), val as $t2);
|
||||
}
|
||||
)
|
||||
|
@ -244,7 +244,7 @@ mod test {
|
|||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let v = std::u32::MAX;
|
||||
let obj = v.to_py_object(py).unwrap().into_object();
|
||||
let obj = v.to_py_object(py).into_object();
|
||||
assert_eq!(v, obj.extract::<u32>().unwrap());
|
||||
assert_eq!(v as u64, obj.extract::<u64>().unwrap());
|
||||
assert!(obj.extract::<i32>().is_err());
|
||||
|
@ -255,7 +255,7 @@ mod test {
|
|||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let v = std::u64::MAX;
|
||||
let obj = v.to_py_object(py).unwrap().into_object();
|
||||
let obj = v.to_py_object(py).into_object();
|
||||
println!("{:?}", obj);
|
||||
assert_eq!(v, obj.extract::<u64>().unwrap());
|
||||
assert!(obj.extract::<i64>().is_err());
|
||||
|
|
|
@ -74,16 +74,11 @@ impl <'p> PyUnicode<'p> {
|
|||
impl <'p> ToPyObject<'p> for str {
|
||||
type ObjectType = PyObject<'p>;
|
||||
|
||||
fn to_py_object(&self, py : Python<'p>) -> PyResult<'p, PyObject<'p>> {
|
||||
let ptr = self.as_ptr() as *const c_char;
|
||||
let len = self.len() as ffi::Py_ssize_t;
|
||||
unsafe {
|
||||
let obj = if self.is_ascii() {
|
||||
ffi::PyString_FromStringAndSize(ptr, len)
|
||||
} else {
|
||||
ffi::PyUnicode_FromStringAndSize(ptr, len)
|
||||
};
|
||||
err::result_from_owned_ptr(py, obj)
|
||||
fn to_py_object(&self, py : Python<'p>) -> PyObject<'p> {
|
||||
if self.is_ascii() {
|
||||
PyString::new(py, self).into_object()
|
||||
} else {
|
||||
PyUnicode::new(py, self).into_object()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +89,7 @@ impl <'p> ToPyObject<'p> for str {
|
|||
impl <'p, 'a> ToPyObject<'p> for &'a str {
|
||||
type ObjectType = PyObject<'p>;
|
||||
|
||||
fn to_py_object(&self, py : Python<'p>) -> PyResult<'p, PyObject<'p>> {
|
||||
fn to_py_object(&self, py : Python<'p>) -> PyObject<'p> {
|
||||
(**self).to_py_object(py)
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +137,7 @@ fn test_non_bmp() {
|
|||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let s = "\u{1F30F}";
|
||||
let py_string = s.to_py_object(py).unwrap();
|
||||
let py_string = s.to_py_object(py);
|
||||
assert_eq!(s, py_string.extract::<Cow<str>>().unwrap());
|
||||
}
|
||||
|
||||
|
|
|
@ -79,23 +79,25 @@ impl<'p, 'a> std::iter::IntoIterator for &'a PyTuple<'p> {
|
|||
fn wrong_tuple_length<'p>(t: &PyTuple<'p>, expected_length: usize) -> PyErr<'p> {
|
||||
let py = t.python();
|
||||
let msg = format!("Expected tuple of length {}, but got tuple of length {}.", expected_length, t.len());
|
||||
PyErr::new_lazy_init(py.get_type::<exc::ValueError>(), msg.to_py_object(py).ok())
|
||||
PyErr::new_lazy_init(py.get_type::<exc::ValueError>(), Some(msg.to_py_object(py)))
|
||||
}
|
||||
|
||||
macro_rules! id (($a:expr) => ($a));
|
||||
|
||||
macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+} => (
|
||||
impl <'p, $($T: ToPyObject<'p>),+> ToPyObject<'p> for ($($T,)+) {
|
||||
type ObjectType = PyTuple<'p>;
|
||||
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, PyTuple<'p>> {
|
||||
Ok(PyTuple::new(py, &[
|
||||
$(try!(self.$n.to_py_object(py)).into_object(),)+
|
||||
]))
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyTuple<'p> {
|
||||
PyTuple::new(py, &[
|
||||
$(id!(self.$n.to_py_object(py)).into_object(),)+
|
||||
])
|
||||
}
|
||||
|
||||
fn into_py_object(self, py: Python<'p>) -> PyResult<'p, PyTuple<'p>> {
|
||||
Ok(PyTuple::new(py, &[
|
||||
$(try!(self.$n.into_py_object(py)).into_object(),)+
|
||||
]))
|
||||
fn into_py_object(self, py: Python<'p>) -> PyTuple<'p> {
|
||||
PyTuple::new(py, &[
|
||||
$(id!(self.$n.into_py_object(py)).into_object(),)+
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,8 +136,8 @@ pub struct NoArgs;
|
|||
impl <'p> ToPyObject<'p> for NoArgs {
|
||||
type ObjectType = PyTuple<'p>;
|
||||
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, PyTuple<'p>> {
|
||||
Ok(PyTuple::empty(py))
|
||||
fn to_py_object(&self, py: Python<'p>) -> PyTuple<'p> {
|
||||
PyTuple::empty(py)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue