Get rid of the pyobject_extract macro

This commit is contained in:
konstin 2018-08-20 22:53:43 +02:00
parent 9cadbd11de
commit db4a2d9017
9 changed files with 93 additions and 86 deletions

View File

@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## Unreleased
### Removed
* The pyobject_extract macro
## [0.4.1] - 2018-08-20
### Fixed

View File

@ -2,7 +2,10 @@
use conversion::{IntoPyObject, PyTryFrom, ToBorrowedObject, ToPyObject};
use ffi;
use object::PyObject;
use objects::PyObjectRef;
use python::{Python, ToPyPointer};
use FromPyObject;
use PyResult;
/// Represents a Python `bool`.
#[repr(transparent)]
@ -68,9 +71,11 @@ impl IntoPyObject for bool {
/// Converts a Python `bool` to a rust `bool`.
///
/// Fails with `TypeError` if the input is not a Python `bool`.
pyobject_extract!(obj to bool => {
Ok(<PyBool as PyTryFrom>::try_from(obj)?.is_true())
});
impl<'source> FromPyObject<'source> for bool {
fn extract(obj: &'source PyObjectRef) -> PyResult<Self> {
Ok(<PyBool as PyTryFrom>::try_from(obj)?.is_true())
}
}
#[cfg(test)]
mod test {
@ -86,7 +91,7 @@ mod test {
assert!(PyBool::new(py, true).is_true());
let t: &PyObjectRef = PyBool::new(py, true).into();
assert_eq!(true, t.extract().unwrap());
assert!(true.to_object(py) == PyBool::new(py, true).into());
assert_eq!(true.to_object(py), PyBool::new(py, true).into());
}
#[test]
@ -96,6 +101,6 @@ mod test {
assert!(!PyBool::new(py, false).is_true());
let t: &PyObjectRef = PyBool::new(py, false).into();
assert_eq!(false, t.extract().unwrap());
assert!(false.to_object(py) == PyBool::new(py, false).into());
assert_eq!(false.to_object(py), PyBool::new(py, false).into());
}
}

View File

@ -2,15 +2,17 @@
//
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
use std::os::raw::c_double;
use conversion::{IntoPyObject, ToPyObject};
use err::PyErr;
use ffi;
use instance::{Py, PyObjectWithToken};
use object::PyObject;
use objectprotocol::ObjectProtocol;
use objects::PyObjectRef;
use python::{Python, ToPyPointer};
use std::os::raw::c_double;
use FromPyObject;
use PyResult;
/// Represents a Python `float` object.
///
@ -40,38 +42,44 @@ impl ToPyObject for f64 {
PyFloat::new(py, *self).into()
}
}
impl IntoPyObject for f64 {
fn into_object(self, py: Python) -> PyObject {
PyFloat::new(py, self).into()
}
}
pyobject_extract!(obj to f64 => {
let v = unsafe { ffi::PyFloat_AsDouble(obj.as_ptr()) };
impl<'source> FromPyObject<'source> for f64 {
fn extract(obj: &'source PyObjectRef) -> PyResult<Self> {
let v = unsafe { ffi::PyFloat_AsDouble(obj.as_ptr()) };
{
if v == -1.0 && PyErr::occurred(obj.py()) {
Err(PyErr::fetch(obj.py()))
} else {
Ok(v)
{
if v == -1.0 && PyErr::occurred(obj.py()) {
Err(PyErr::fetch(obj.py()))
} else {
Ok(v)
}
}
}
});
}
impl ToPyObject for f32 {
fn to_object(&self, py: Python) -> PyObject {
PyFloat::new(py, *self as f64).into()
}
}
impl IntoPyObject for f32 {
fn into_object(self, py: Python) -> PyObject {
PyFloat::new(py, self as f64).into()
}
}
pyobject_extract!(obj to f32 => {
Ok(obj.extract::<f64>()? as f32)
});
impl<'source> FromPyObject<'source> for f32 {
fn extract(obj: &'source PyObjectRef) -> PyResult<Self> {
Ok(obj.extract::<f64>()? as f32)
}
}
#[cfg(test)]
mod test {

View File

@ -175,33 +175,6 @@ macro_rules! pyobject_native_type_convert(
};
);
/// Implements [FromPyObject] and (currently deactivated until it's stabillized) a
/// [TryFrom](std::convert::TryFrom) implementation, given a function body that performs the actual
/// conversion
#[macro_export]
macro_rules! pyobject_extract(
($obj:ident to $t:ty => $body: block) => {
impl<'source> $crate::FromPyObject<'source> for $t
{
fn extract($obj: &'source $crate::PyObjectRef) -> $crate::PyResult<Self>
{
$body
}
}
#[cfg(feature = "try_from")]
impl<'source> ::std::convert::TryFrom<&'source $crate::PyObjectRef> for $t
{
type Error = $crate::PyErr;
fn try_from($obj: &$crate::PyObjectRef) -> Result<Self, $crate::PyErr>
{
$body
}
}
}
);
use ffi;
use python::ToPyPointer;
/// Represents general python instance.

View File

@ -77,16 +77,19 @@ macro_rules! int_fits_c_long(
}
}
}
pyobject_extract!(obj to $rust_type => {
let val = unsafe { ffi::PyLong_AsLong(obj.as_ptr()) };
if val == -1 && PyErr::occurred(obj.py()) {
return Err(PyErr::fetch(obj.py()));
impl<'source> FromPyObject<'source> for $rust_type {
fn extract(obj: &'source PyObjectRef) -> PyResult<Self> {
let val = unsafe { ffi::PyLong_AsLong(obj.as_ptr()) };
if val == -1 && PyErr::occurred(obj.py()) {
return Err(PyErr::fetch(obj.py()));
}
match cast::<c_long, $rust_type>(val) {
Some(v) => Ok(v),
None => Err(exc::OverflowError.into())
}
}
match cast::<c_long, $rust_type>(val) {
Some(v) => Ok(v),
None => Err(exc::OverflowError.into())
}
});
}
)
);

View File

@ -2,11 +2,9 @@
//
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
use std::os::raw::{c_long, c_uchar};
extern crate num_traits;
use self::num_traits::cast::cast;
use self::num_traits::cast::cast;
use super::num_common::{err_if_invalid_value, IS_LITTLE_ENDIAN};
use conversion::{FromPyObject, IntoPyObject, ToPyObject};
use err::{PyErr, PyResult};
@ -15,6 +13,8 @@ use instance::PyObjectWithToken;
use object::PyObject;
use objects::{exc, PyObjectRef};
use python::{Python, ToPyPointer};
use std::os::raw::{c_long, c_uchar};
/// Represents a Python `int` object.
///
/// You can usually avoid directly working with this type
@ -26,7 +26,7 @@ pub struct PyLong(PyObject);
pyobject_native_type!(PyLong, ffi::PyLong_Type, ffi::PyLong_Check);
macro_rules! int_fits_c_long(
macro_rules! int_fits_c_long (
($rust_type:ty) => (
impl ToPyObject for $rust_type {
@ -44,23 +44,26 @@ macro_rules! int_fits_c_long(
}
}
}
pyobject_extract!(obj to $rust_type => {
let ptr = obj.as_ptr();
let val = unsafe {
let num = ffi::PyNumber_Index(ptr);
if num.is_null() {
Err(PyErr::fetch(obj.py()))
} else {
let val = err_if_invalid_value(obj.py(), -1, ffi::PyLong_AsLong(num));
ffi::Py_DECREF(num);
val
impl<'source> FromPyObject<'source> for $rust_type {
fn extract(obj: &'source PyObjectRef) -> PyResult<Self> {
let ptr = obj.as_ptr();
let val = unsafe {
let num = ffi::PyNumber_Index(ptr);
if num.is_null() {
Err(PyErr::fetch(obj.py()))
} else {
let val = err_if_invalid_value(obj.py(), -1, ffi::PyLong_AsLong(num));
ffi::Py_DECREF(num);
val
}
}?;
match cast::<c_long, $rust_type>(val) {
Some(v) => Ok(v),
None => Err(exc::OverflowError.into())
}
}?;
match cast::<c_long, $rust_type>(val) {
Some(v) => Ok(v),
None => Err(exc::OverflowError.into())
}
});
}
)
);

View File

@ -30,13 +30,16 @@ macro_rules! int_fits_larger_int(
(self as $larger_type).into_object(py)
}
}
pyobject_extract!(obj to $rust_type => {
let val = try!($crate::objectprotocol::ObjectProtocol::extract::<$larger_type>(obj));
match cast::<$larger_type, $rust_type>(val) {
Some(v) => Ok(v),
None => Err(exc::OverflowError.into())
impl<'source> FromPyObject<'source> for $rust_type {
fn extract(obj: &'source PyObjectRef) -> PyResult<Self> {
let val = try!($crate::objectprotocol::ObjectProtocol::extract::<$larger_type>(obj));
match cast::<$larger_type, $rust_type>(val) {
Some(v) => Ok(v),
None => Err(exc::OverflowError.into())
}
}
});
}
)
);

View File

@ -1,12 +1,11 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use std::borrow::Cow;
use conversion::{IntoPyObject, PyTryFrom, ToPyObject};
use err::PyResult;
use instance::PyObjectWithToken;
use object::PyObject;
use objects::{PyObjectRef, PyString};
use python::Python;
use std::borrow::Cow;
use FromPyObject;
/// Converts Rust `str` to Python object.
/// See `PyString::new` for details on the conversion.
@ -16,6 +15,7 @@ impl ToPyObject for str {
PyString::new(py, self).into()
}
}
impl<'a> IntoPyObject for &'a str {
#[inline]
fn into_object(self, py: Python) -> PyObject {
@ -40,12 +40,14 @@ impl ToPyObject for String {
PyString::new(py, self).into()
}
}
impl IntoPyObject for String {
#[inline]
fn into_object(self, py: Python) -> PyObject {
PyString::new(py, &self).into()
}
}
impl<'a> IntoPyObject for &'a String {
#[inline]
fn into_object(self, py: Python) -> PyObject {
@ -78,6 +80,10 @@ impl<'a> ::FromPyObject<'a> for &'a 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<'source> FromPyObject<'source> for String {
fn extract(obj: &'source PyObjectRef) -> PyResult<Self> {
<PyString as PyTryFrom>::try_from(obj)?
.to_string()
.map(Cow::into_owned)
}
}

View File

@ -31,7 +31,7 @@ fn instance_method() {
member: 42,
token: t,
}).unwrap();
assert!(obj.method().unwrap() == 42);
assert_eq!(obj.method().unwrap(), 42);
let d = PyDict::new(py);
d.set_item("obj", obj).unwrap();
py.run("assert obj.method() == 42", None, Some(d)).unwrap();