Simplify ToPyObject: directly return the object without PyResult

to_py_object should always succeed (modulo out-of-memory)
This commit is contained in:
Daniel Grunwald 2015-04-19 01:07:14 +02:00
parent 1e5605036e
commit fbd60f11f4
9 changed files with 71 additions and 70 deletions

View file

@ -9,14 +9,14 @@ pub trait ToPyObject<'p> {
type ObjectType : PythonObject<'p> = PyObject<'p>; type ObjectType : PythonObject<'p> = PyObject<'p>;
/// Converts self into a python object. /// 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. /// Converts self into a python object.
/// ///
/// May be more efficient than `to_py_object` in some cases because /// May be more efficient than `to_py_object` in some cases because
/// it can move out of the input object. /// it can move out of the input object.
#[inline] #[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 { where Self: Sized {
self.to_py_object(py) 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 /// 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. /// to touch any reference counts when the input object already is a python object.
#[inline] #[inline]
fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> PyResult<'p, R> fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> PyResult<'p, R> { where F: FnOnce(*mut ffi::PyObject) -> R {
let obj = try!(self.to_py_object(py)); let obj = self.to_py_object(py);
f(ToPythonPointer::as_ptr(&obj)) 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 // This allows using existing python objects in code that generically expects a value
// convertible to a python object. // 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>; type ObjectType = PyObject<'p>;
#[inline] #[inline]
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, PyObject<'p>> { fn to_py_object(&self, py: Python<'p>) -> PyObject<'p> {
Ok(self.clone()) self.clone().into_py_object(py)
} }
#[inline] #[inline]
fn into_py_object(self, py: Python<'p>) -> PyResult<'p, PyObject<'p>> { fn into_py_object(self, py: Python<'p>) -> PyObject<'p> {
Ok(self) // 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] #[inline]
fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> PyResult<'p, R> fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> PyResult<'p, R> { where F: FnOnce(*mut ffi::PyObject) -> R {
f(self.as_ptr()) 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 // This allows using existing python objects in code that generically expects a value
// convertible to a python object. // convertible to a python object.
impl <'p, 's, T> ToPyObject<'p> for &'s T where T : ToPyObject<'p> { 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] #[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) (**self).to_py_object(py)
} }
#[inline] #[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) (*self).to_py_object(py)
} }
#[inline] #[inline]
fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> PyResult<'p, R> fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> PyResult<'p, R> { where F: FnOnce(*mut ffi::PyObject) -> R {
(**self).with_borrowed_ptr(py, f) (**self).with_borrowed_ptr(py, f)
} }
} }

View file

@ -87,7 +87,7 @@ impl <'p> PyErr<'p> {
} else { } else {
PyErr { PyErr {
ptype: py.get_type::<exc::TypeError>().into_object(), 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 ptraceback: None
} }
} }

View file

@ -169,15 +169,14 @@ macro_rules! py_func {
let py = $crate::Python::assume_gil_acquired(); let py = $crate::Python::assume_gil_acquired();
let args = $crate::PyObject::from_borrowed_ptr(py, args); let args = $crate::PyObject::from_borrowed_ptr(py, args);
let args: &$crate::PyTuple = $crate::PythonObject::unchecked_downcast_borrow_from(&args); let args: &$crate::PyTuple = $crate::PythonObject::unchecked_downcast_borrow_from(&args);
let result = match $f(py, args) { match $f(py, args) {
Ok(val) => $crate::ToPyObject::into_py_object(val, py), Ok(val) => {
Err(e) => Err(e) let obj = $crate::ToPyObject::into_py_object(val, py);
}; return $crate::ToPythonPointer::steal_ptr(obj);
match result { }
Ok(val) => $crate::ToPythonPointer::steal_ptr(val),
Err(e) => { Err(e) => {
e.restore(); e.restore();
::std::ptr::null_mut() return ::std::ptr::null_mut();
} }
} }
} }

View file

@ -23,13 +23,13 @@ impl <'p> ToPyObject<'p> for bool {
type ObjectType = PyBool<'p>; type ObjectType = PyBool<'p>;
#[inline] #[inline]
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, PyBool<'p>> { fn to_py_object(&self, py: Python<'p>) -> PyBool<'p> {
Ok(PyBool::get(py, *self)) PyBool::get(py, *self)
} }
#[inline] #[inline]
fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> PyResult<'p, R> fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> PyResult<'p, R> where F: FnOnce(*mut ffi::PyObject) -> R
{ {
// Avoid unnecessary Py_INCREF/Py_DECREF pair // Avoid unnecessary Py_INCREF/Py_DECREF pair
f(unsafe { if *self { ffi::Py_True() } else { ffi::Py_False() } }) f(unsafe { if *self { ffi::Py_True() } else { ffi::Py_False() } })

View file

@ -60,15 +60,15 @@ impl <'p> PyList<'p> {
impl <'p, T> ToPyObject<'p> for [T] where T: ToPyObject<'p> { impl <'p, T> ToPyObject<'p> for [T] where T: ToPyObject<'p> {
type ObjectType = PyList<'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 { unsafe {
let ptr = ffi::PyList_New(self.len() as Py_ssize_t); 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() { 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()); ffi::PyList_SET_ITEM(ptr, i as Py_ssize_t, obj.steal_ptr());
} }
Ok(t) t
} }
} }
} }

View file

@ -87,7 +87,7 @@ impl <'p> PyModule<'p> {
pub fn add<V>(&self, name: &str, value: V) -> PyResult<'p, ()> where V: ToPyObject<'p> { pub fn add<V>(&self, name: &str, value: V) -> PyResult<'p, ()> where V: ToPyObject<'p> {
let py = self.python(); let py = self.python();
let name = CString::new(name).unwrap(); 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()) }; let r = unsafe { ffi::PyModule_AddObject(self.as_ptr(), name.as_ptr(), value.steal_ptr()) };
err::error_on_minusone(py, r) err::error_on_minusone(py, r)
} }

View file

@ -45,10 +45,10 @@ macro_rules! int_fits_c_long(
impl <'p> ToPyObject<'p> for $rust_type { impl <'p> ToPyObject<'p> for $rust_type {
type ObjectType = PyInt<'p>; 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 { unsafe {
Ok(try!(err::result_from_owned_ptr(py, err::cast_from_owned_ptr_or_panic(py,
ffi::PyInt_FromLong(*self as c_long))).unchecked_cast_into::<PyInt>()) 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; type ObjectType = <$larger_type as ToPyObject<'p>>::ObjectType;
#[inline] #[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) (*self as $larger_type).to_py_object(py)
} }
} }
@ -123,13 +123,13 @@ int_fits_larger_int!(usize, u64);
impl <'p> ToPyObject<'p> for u64 { impl <'p> ToPyObject<'p> for u64 {
type ObjectType = PyObject<'p>; 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 { unsafe {
let ptr = match std::num::cast::<u64, c_long>(*self) { let ptr = match std::num::cast::<u64, c_long>(*self) {
Some(v) => ffi::PyInt_FromLong(v), Some(v) => ffi::PyInt_FromLong(v),
None => ffi::PyLong_FromUnsignedLongLong(*self) 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 { impl <'p> ToPyObject<'p> for f64 {
type ObjectType = PyFloat<'p>; type ObjectType = PyFloat<'p>;
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, PyFloat<'p>> { fn to_py_object(&self, py: Python<'p>) -> PyFloat<'p> {
Ok(PyFloat::new(py, *self)) PyFloat::new(py, *self)
} }
} }
@ -191,8 +191,8 @@ fn overflow_error(py: Python) -> PyErr {
impl <'p> ToPyObject<'p> for f32 { impl <'p> ToPyObject<'p> for f32 {
type ObjectType = PyFloat<'p>; type ObjectType = PyFloat<'p>;
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, PyFloat<'p>> { fn to_py_object(&self, py: Python<'p>) -> PyFloat<'p> {
Ok(PyFloat::new(py, *self as f64)) PyFloat::new(py, *self as f64)
} }
} }
@ -215,7 +215,7 @@ mod test {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let val = 123 as $t1; 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); assert_eq!(obj.extract::<$t2>().unwrap(), val as $t2);
} }
) )
@ -244,7 +244,7 @@ mod test {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let v = std::u32::MAX; 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, obj.extract::<u32>().unwrap());
assert_eq!(v as u64, obj.extract::<u64>().unwrap()); assert_eq!(v as u64, obj.extract::<u64>().unwrap());
assert!(obj.extract::<i32>().is_err()); assert!(obj.extract::<i32>().is_err());
@ -255,7 +255,7 @@ mod test {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let v = std::u64::MAX; 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); println!("{:?}", obj);
assert_eq!(v, obj.extract::<u64>().unwrap()); assert_eq!(v, obj.extract::<u64>().unwrap());
assert!(obj.extract::<i64>().is_err()); assert!(obj.extract::<i64>().is_err());

View file

@ -74,16 +74,11 @@ impl <'p> PyUnicode<'p> {
impl <'p> ToPyObject<'p> for str { impl <'p> ToPyObject<'p> for str {
type ObjectType = PyObject<'p>; 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> {
let ptr = self.as_ptr() as *const c_char; if self.is_ascii() {
let len = self.len() as ffi::Py_ssize_t; PyString::new(py, self).into_object()
unsafe { } else {
let obj = if self.is_ascii() { PyUnicode::new(py, self).into_object()
ffi::PyString_FromStringAndSize(ptr, len)
} else {
ffi::PyUnicode_FromStringAndSize(ptr, len)
};
err::result_from_owned_ptr(py, obj)
} }
} }
} }
@ -94,7 +89,7 @@ impl <'p> ToPyObject<'p> for str {
impl <'p, 'a> ToPyObject<'p> for &'a str { impl <'p, 'a> ToPyObject<'p> for &'a str {
type ObjectType = PyObject<'p>; 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) (**self).to_py_object(py)
} }
} }
@ -142,7 +137,7 @@ fn test_non_bmp() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let s = "\u{1F30F}"; 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()); assert_eq!(s, py_string.extract::<Cow<str>>().unwrap());
} }

View file

@ -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> { fn wrong_tuple_length<'p>(t: &PyTuple<'p>, expected_length: usize) -> PyErr<'p> {
let py = t.python(); let py = t.python();
let msg = format!("Expected tuple of length {}, but got tuple of length {}.", expected_length, t.len()); 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)),+} => ( macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+} => (
impl <'p, $($T: ToPyObject<'p>),+> ToPyObject<'p> for ($($T,)+) { impl <'p, $($T: ToPyObject<'p>),+> ToPyObject<'p> for ($($T,)+) {
type ObjectType = PyTuple<'p>; type ObjectType = PyTuple<'p>;
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, PyTuple<'p>> { fn to_py_object(&self, py: Python<'p>) -> PyTuple<'p> {
Ok(PyTuple::new(py, &[ PyTuple::new(py, &[
$(try!(self.$n.to_py_object(py)).into_object(),)+ $(id!(self.$n.to_py_object(py)).into_object(),)+
])) ])
} }
fn into_py_object(self, py: Python<'p>) -> PyResult<'p, PyTuple<'p>> { fn into_py_object(self, py: Python<'p>) -> PyTuple<'p> {
Ok(PyTuple::new(py, &[ PyTuple::new(py, &[
$(try!(self.$n.into_py_object(py)).into_object(),)+ $(id!(self.$n.into_py_object(py)).into_object(),)+
])) ])
} }
} }
@ -134,8 +136,8 @@ pub struct NoArgs;
impl <'p> ToPyObject<'p> for NoArgs { impl <'p> ToPyObject<'p> for NoArgs {
type ObjectType = PyTuple<'p>; type ObjectType = PyTuple<'p>;
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, PyTuple<'p>> { fn to_py_object(&self, py: Python<'p>) -> PyTuple<'p> {
Ok(PyTuple::empty(py)) PyTuple::empty(py)
} }
} }