added PyInt for py2
This commit is contained in:
parent
8d4e0204f1
commit
b21ded3aaa
|
@ -75,7 +75,6 @@ pyobject_extract!(py, obj to f32 => {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std;
|
||||
use python::Python;
|
||||
use conversion::ToPyObject;
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ pub use self::bytearray::{PyByteArray};
|
|||
pub use self::tuple::{PyTuple, NoArgs};
|
||||
pub use self::dict::PyDict;
|
||||
pub use self::list::PyList;
|
||||
pub use self::num::PyLong;
|
||||
pub use self::floatob::PyFloat;
|
||||
pub use self::sequence::PySequence;
|
||||
pub use self::slice::PySlice;
|
||||
|
@ -22,6 +21,13 @@ pub use self::string::{PyBytes, PyString};
|
|||
#[cfg(not(Py_3))]
|
||||
pub use self::string2::{PyBytes, PyString};
|
||||
|
||||
#[cfg(Py_3)]
|
||||
pub use self::num3::PyLong;
|
||||
#[cfg(Py_3)]
|
||||
pub use self::num3::PyLong as PyInt;
|
||||
|
||||
#[cfg(not(Py_3))]
|
||||
pub use self::num2::{PyInt, PyLong};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! pyobject_nativetype(
|
||||
|
@ -285,7 +291,6 @@ mod boolobject;
|
|||
mod bytearray;
|
||||
mod tuple;
|
||||
mod list;
|
||||
mod num;
|
||||
mod floatob;
|
||||
mod sequence;
|
||||
mod slice;
|
||||
|
@ -295,6 +300,12 @@ mod set;
|
|||
mod object;
|
||||
pub mod exc;
|
||||
|
||||
#[cfg(Py_3)]
|
||||
mod num3;
|
||||
|
||||
#[cfg(not(Py_3))]
|
||||
mod num2;
|
||||
|
||||
#[cfg(Py_3)]
|
||||
mod string;
|
||||
|
||||
|
|
|
@ -0,0 +1,292 @@
|
|||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
//
|
||||
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
|
||||
|
||||
use std::os::raw::c_long;
|
||||
|
||||
extern crate num_traits;
|
||||
use self::num_traits::cast::cast;
|
||||
|
||||
use ffi;
|
||||
use objects::exc;
|
||||
use objects::PyObject;
|
||||
use pointers::PyPtr;
|
||||
use python::{ToPyPointer, IntoPyPointer, Python};
|
||||
use err::{PyResult, PyErr};
|
||||
use conversion::{ToPyObject, IntoPyObject, FromPyObject};
|
||||
|
||||
/// Represents a Python `int` object.
|
||||
///
|
||||
/// Note that in Python 2.x, `int` and `long` are different types.
|
||||
///
|
||||
/// You can usually avoid directly working with this type
|
||||
/// by using [ToPyObject](trait.ToPyObject.html)
|
||||
/// and [extract](struct.PyObject.html#method.extract)
|
||||
/// with the primitive Rust integer types.
|
||||
pub struct PyInt(PyPtr);
|
||||
|
||||
pyobject_convert!(PyInt);
|
||||
pyobject_nativetype!(PyInt, PyInt_Check, PyInt_Type);
|
||||
|
||||
/// In Python 2.x, represents a Python `long` object.
|
||||
/// Both `PyInt` and `PyLong` refer to the same type on Python 3.x.
|
||||
///
|
||||
/// You can usually avoid directly working with this type
|
||||
/// by using [ToPyObject](trait.ToPyObject.html)
|
||||
/// and [extract](struct.PyObject.html#method.extract)
|
||||
/// with the primitive Rust integer types.
|
||||
pub struct PyLong(PyPtr);
|
||||
|
||||
pyobject_convert!(PyLong);
|
||||
pyobject_nativetype!(PyLong, PyLong_Check, PyLong_Type);
|
||||
|
||||
impl PyInt {
|
||||
/// Creates a new Python 2.7 `int` object.
|
||||
///
|
||||
/// Note: you might want to call `val.to_py_object(py)` instead
|
||||
/// to avoid truncation if the value does not fit into a `c_long`,
|
||||
/// and to make your code compatible with Python 3.x.
|
||||
pub fn new(_py: Python, val: c_long) -> PyInt {
|
||||
unsafe {
|
||||
PyInt(PyPtr::from_owned_ptr_or_panic(ffi::PyLong_FromLong(val)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the value of this integer.
|
||||
///
|
||||
/// Warning: `PyInt::value()` is only supported for Python 2.7 `int` objects,
|
||||
/// but not for `long` objects.
|
||||
/// In almost all cases, you can avoid the distinction between these types
|
||||
/// by simply calling `obj.extract::<i32>(py)`.
|
||||
pub fn value(&self, _py: Python) -> c_long {
|
||||
unsafe { ffi::PyInt_AS_LONG(self.0.as_ptr()) }
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! int_fits_c_long(
|
||||
($rust_type:ty) => (
|
||||
impl ToPyObject for $rust_type {
|
||||
fn to_object(&self, py: Python) -> PyObject {
|
||||
unsafe {
|
||||
PyObject::from_owned_ptr_or_panic(py, ffi::PyInt_FromLong(*self as c_long))
|
||||
}
|
||||
}
|
||||
}
|
||||
impl IntoPyObject for $rust_type {
|
||||
fn into_object(self, py: Python) -> PyObject {
|
||||
unsafe {
|
||||
PyObject::from_owned_ptr_or_panic(py, ffi::PyInt_FromLong(self as c_long))
|
||||
}
|
||||
}
|
||||
}
|
||||
pyobject_extract!(py, obj to $rust_type => {
|
||||
let val = unsafe { ffi::PyLong_AsLong(obj.as_ptr()) };
|
||||
if val == -1 && PyErr::occurred(py) {
|
||||
return Err(PyErr::fetch(py));
|
||||
}
|
||||
match cast::<c_long, $rust_type>(val) {
|
||||
Some(v) => Ok(v),
|
||||
None => Err(overflow_error(py))
|
||||
}
|
||||
});
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
macro_rules! int_fits_larger_int(
|
||||
($rust_type:ty, $larger_type:ty) => (
|
||||
impl ToPyObject for $rust_type {
|
||||
#[inline]
|
||||
fn to_object(&self, py: Python) -> PyObject {
|
||||
(*self as $larger_type).to_object(py)
|
||||
}
|
||||
}
|
||||
impl IntoPyObject for $rust_type {
|
||||
fn into_object(self, py: Python) -> PyObject {
|
||||
(self as $larger_type).into_object(py)
|
||||
}
|
||||
}
|
||||
pyobject_extract!(py, obj to $rust_type => {
|
||||
let val = try!(obj.extract::<$larger_type>(py));
|
||||
match cast::<$larger_type, $rust_type>(val) {
|
||||
Some(v) => Ok(v),
|
||||
None => Err(overflow_error(py))
|
||||
}
|
||||
});
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
fn err_if_invalid_value<'p, T: PartialEq>
|
||||
(py: Python, invalid_value: T, actual_value: T) -> PyResult<T>
|
||||
{
|
||||
if actual_value == invalid_value && PyErr::occurred(py) {
|
||||
Err(PyErr::fetch(py))
|
||||
} else {
|
||||
Ok(actual_value)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! int_convert_u64_or_i64 (
|
||||
($rust_type:ty, $pylong_from_ll_or_ull:expr, $pylong_as_ull_or_ull:expr) => (
|
||||
impl ToPyObject for $rust_type {
|
||||
fn to_object(&self, py: Python) -> PyObject {
|
||||
unsafe {
|
||||
let ptr = match cast::<$rust_type, c_long>(*self) {
|
||||
Some(v) => ffi::PyInt_FromLong(v),
|
||||
None => $pylong_from_ll_or_ull(*self)
|
||||
};
|
||||
PyObject::from_owned_ptr_or_panic(py, ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
impl IntoPyObject for $rust_type {
|
||||
fn into_object(self, py: Python) -> PyObject {
|
||||
unsafe {
|
||||
let ptr = match cast::<$rust_type, c_long>(self) {
|
||||
Some(v) => ffi::PyInt_FromLong(v),
|
||||
None => $pylong_from_ll_or_ull(self)
|
||||
};
|
||||
PyObject::from_owned_ptr_or_panic(py, ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl <'source> FromPyObject<'source> for $rust_type {
|
||||
fn extract(py: Python, obj: &'source PyObject) -> PyResult<$rust_type>
|
||||
{
|
||||
let ptr = obj.as_ptr();
|
||||
unsafe {
|
||||
if ffi::PyLong_Check(ptr) != 0 {
|
||||
err_if_invalid_value(py, !0, $pylong_as_ull_or_ull(ptr))
|
||||
} else if ffi::PyInt_Check(ptr) != 0 {
|
||||
match cast::<c_long, $rust_type>(ffi::PyInt_AS_LONG(ptr)) {
|
||||
Some(v) => Ok(v),
|
||||
None => Err(overflow_error(py))
|
||||
}
|
||||
} else {
|
||||
let num = PyPtr::from_owned_ptr_or_err(py, ffi::PyNumber_Long(ptr))?;
|
||||
err_if_invalid_value(py, !0, $pylong_as_ull_or_ull(num.into_ptr()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
int_fits_c_long!(i8);
|
||||
int_fits_c_long!(u8);
|
||||
int_fits_c_long!(i16);
|
||||
int_fits_c_long!(u16);
|
||||
int_fits_c_long!(i32);
|
||||
|
||||
// If c_long is 64-bits, we can use more types with int_fits_c_long!:
|
||||
#[cfg(all(target_pointer_width="64", not(target_os="windows")))]
|
||||
int_fits_c_long!(u32);
|
||||
#[cfg(any(target_pointer_width="32", target_os="windows"))]
|
||||
int_fits_larger_int!(u32, u64);
|
||||
|
||||
#[cfg(all(target_pointer_width="64", not(target_os="windows")))]
|
||||
int_fits_c_long!(i64);
|
||||
|
||||
// manual implementation for i64 on systems with 32-bit long
|
||||
#[cfg(any(target_pointer_width="32", target_os="windows"))]
|
||||
int_convert_u64_or_i64!(i64, ffi::PyLong_FromLongLong, ffi::PyLong_AsLongLong);
|
||||
|
||||
#[cfg(all(target_pointer_width="64", not(target_os="windows")))]
|
||||
int_fits_c_long!(isize);
|
||||
#[cfg(any(target_pointer_width="32", target_os="windows"))]
|
||||
int_fits_larger_int!(isize, i64);
|
||||
|
||||
int_fits_larger_int!(usize, u64);
|
||||
|
||||
// u64 has a manual implementation as it never fits into signed long
|
||||
int_convert_u64_or_i64!(u64, ffi::PyLong_FromUnsignedLongLong, ffi::PyLong_AsUnsignedLongLong);
|
||||
|
||||
fn overflow_error(py: Python) -> PyErr {
|
||||
PyErr::new_lazy_init(py.get_type::<exc::OverflowError>(), None)
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std;
|
||||
use python::{Python};
|
||||
use conversion::ToPyObject;
|
||||
|
||||
macro_rules! num_to_py_object_and_back (
|
||||
($func_name:ident, $t1:ty, $t2:ty) => (
|
||||
#[test]
|
||||
fn $func_name() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let val = 123 as $t1;
|
||||
let obj = val.to_object(py);
|
||||
assert_eq!(obj.extract::<$t2>(py).unwrap(), val as $t2);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
num_to_py_object_and_back!(to_from_f64, f64, f64);
|
||||
num_to_py_object_and_back!(to_from_f32, f32, f32);
|
||||
num_to_py_object_and_back!(to_from_i8, i8, i8);
|
||||
num_to_py_object_and_back!(to_from_u8, u8, u8);
|
||||
num_to_py_object_and_back!(to_from_i16, i16, i16);
|
||||
num_to_py_object_and_back!(to_from_u16, u16, u16);
|
||||
num_to_py_object_and_back!(to_from_i32, i32, i32);
|
||||
num_to_py_object_and_back!(to_from_u32, u32, u32);
|
||||
num_to_py_object_and_back!(to_from_i64, i64, i64);
|
||||
num_to_py_object_and_back!(to_from_u64, u64, u64);
|
||||
num_to_py_object_and_back!(to_from_isize, isize, isize);
|
||||
num_to_py_object_and_back!(to_from_usize, usize, usize);
|
||||
num_to_py_object_and_back!(float_to_i32, f64, i32);
|
||||
num_to_py_object_and_back!(float_to_u32, f64, u32);
|
||||
num_to_py_object_and_back!(float_to_i64, f64, i64);
|
||||
num_to_py_object_and_back!(float_to_u64, f64, u64);
|
||||
num_to_py_object_and_back!(int_to_float, i32, f64);
|
||||
|
||||
#[test]
|
||||
fn test_u32_max() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let v = std::u32::MAX;
|
||||
let obj = v.to_object(py);
|
||||
assert_eq!(v, obj.extract::<u32>(py).unwrap());
|
||||
assert_eq!(v as u64, obj.extract::<u64>(py).unwrap());
|
||||
assert!(obj.extract::<i32>(py).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_i64_max() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let v = std::i64::MAX;
|
||||
let obj = v.to_object(py);
|
||||
assert_eq!(v, obj.extract::<i64>(py).unwrap());
|
||||
assert_eq!(v as u64, obj.extract::<u64>(py).unwrap());
|
||||
assert!(obj.extract::<u32>(py).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_i64_min() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let v = std::i64::MIN;
|
||||
let obj = v.to_object(py);
|
||||
assert_eq!(v, obj.extract::<i64>(py).unwrap());
|
||||
assert!(obj.extract::<i32>(py).is_err());
|
||||
assert!(obj.extract::<u64>(py).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_u64_max() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let v = std::u64::MAX;
|
||||
let obj = v.to_object(py);
|
||||
println!("{:?}", obj);
|
||||
assert_eq!(v, obj.extract::<u64>(py).unwrap());
|
||||
assert!(obj.extract::<i64>(py).is_err());
|
||||
}
|
||||
}
|
|
@ -110,7 +110,6 @@ macro_rules! int_convert_u64_or_i64 (
|
|||
}
|
||||
impl<'source> FromPyObject<'source> for $rust_type {
|
||||
fn extract(py: Python, ob: &'source PyObject) -> PyResult<$rust_type>
|
||||
//where S: PyTypeInfo
|
||||
{
|
||||
let ptr = ob.as_ptr();
|
||||
unsafe {
|
|
@ -273,7 +273,7 @@ mod test {
|
|||
assert_eq!(false, seq.contains(py, &needle).unwrap());
|
||||
}
|
||||
|
||||
//#[test]
|
||||
#[test]
|
||||
fn test_seq_contains() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
|
|
@ -273,7 +273,7 @@ impl<'p> Python<'p> {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use {Python, PyDict};
|
||||
use objects::{PyBool, PyList, PyLong};
|
||||
use objects::{PyBool, PyList, PyInt};
|
||||
|
||||
#[test]
|
||||
fn test_eval() {
|
||||
|
@ -314,7 +314,7 @@ mod test {
|
|||
fn test_is_subclass() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
assert!(py.is_subclass::<PyBool, PyLong>().unwrap());
|
||||
assert!(py.is_subclass::<PyBool, PyInt>().unwrap());
|
||||
assert!(!py.is_subclass::<PyBool, PyList>().unwrap());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue