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>;
/// 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)
}
}

View file

@ -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
}
}

View file

@ -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();
}
}
}

View file

@ -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() } })

View file

@ -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
}
}
}

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> {
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)
}

View file

@ -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());

View file

@ -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());
}

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> {
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)
}
}