From 8387932793294206edd367c15cbe95dc9d7667fd Mon Sep 17 00:00:00 2001 From: Yoichi Imai Date: Tue, 26 May 2015 23:44:29 +0900 Subject: [PATCH 1/3] Generalize pylong_as_u64. --- src/objects/num.rs | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/objects/num.rs b/src/objects/num.rs index 58349d4d..d17c98bb 100644 --- a/src/objects/num.rs +++ b/src/objects/num.rs @@ -103,7 +103,7 @@ macro_rules! int_fits_c_long( } } } - + #[cfg(feature="python3-sys")] impl <'p> FromPyObject<'p> for $rust_type { fn from_py_object(s: &PyObject<'p>) -> PyResult<'p, $rust_type> { @@ -172,6 +172,17 @@ int_fits_larger_int!(isize, i64); int_fits_larger_int!(usize, u64); +fn err_if_invalid_value<'p, T: PartialEq, F: Fn() -> T> + (obj: &PyObject<'p>, invalid_value: T, func: F) -> PyResult<'p, T> { + let py = obj.python(); + let v = func(); + if v == invalid_value && PyErr::occurred(py) { + Err(PyErr::fetch(py)) + } else { + Ok(v) + } +} + impl <'p> ToPyObject<'p> for u64 { #[cfg(feature="python27-sys")] type ObjectType = PyObject<'p>; @@ -198,24 +209,15 @@ impl <'p> ToPyObject<'p> for u64 { } } -fn pylong_as_u64<'p>(obj: &PyObject<'p>) -> PyResult<'p, u64> { - let py = obj.python(); - let v = unsafe { ffi::PyLong_AsUnsignedLongLong(obj.as_ptr()) }; - if v == !0 && PyErr::occurred(py) { - Err(PyErr::fetch(py)) - } else { - Ok(v) - } -} - impl <'p> FromPyObject<'p> for u64 { #[cfg(feature="python27-sys")] fn from_py_object(s: &PyObject<'p>) -> PyResult<'p, u64> { let py = s.python(); let ptr = s.as_ptr(); + unsafe { if ffi::PyLong_Check(ptr) != 0 { - pylong_as_u64(s) + err_if_invalid_value(s, !0, || ffi::PyLong_AsUnsignedLongLong(s.as_ptr()) ) } else if ffi::PyInt_Check(ptr) != 0 { match num::traits::cast::(ffi::PyInt_AS_LONG(ptr)) { Some(v) => Ok(v), @@ -223,7 +225,7 @@ impl <'p> FromPyObject<'p> for u64 { } } else { let num = try!(err::result_from_owned_ptr(py, ffi::PyNumber_Long(ptr))); - pylong_as_u64(&num) + err_if_invalid_value(&num, !0, || ffi::PyLong_AsUnsignedLongLong(num.as_ptr()) ) } } } @@ -234,10 +236,10 @@ impl <'p> FromPyObject<'p> for u64 { let ptr = s.as_ptr(); unsafe { if ffi::PyLong_Check(ptr) != 0 { - pylong_as_u64(s) + err_if_invalid_value(s, !0, || ffi::PyLong_AsUnsignedLongLong(s.as_ptr()) ) } else { let num = try!(err::result_from_owned_ptr(py, ffi::PyNumber_Long(ptr))); - pylong_as_u64(&num) + err_if_invalid_value(&num, !0, || ffi::PyLong_AsUnsignedLongLong(num.as_ptr()) ) } } } @@ -340,4 +342,3 @@ mod test { assert!(obj.extract::().is_err()); } } - From e237bdd57fb57e534845c09f6441c7f653e8ca0b Mon Sep 17 00:00:00 2001 From: Yoichi Imai Date: Tue, 26 May 2015 23:48:01 +0900 Subject: [PATCH 2/3] Converting function for i64 on 32bit/non-windows platform. --- src/objects/num.rs | 157 ++++++++++++++++++++++++--------------------- 1 file changed, 83 insertions(+), 74 deletions(-) diff --git a/src/objects/num.rs b/src/objects/num.rs index d17c98bb..5be2b59b 100644 --- a/src/objects/num.rs +++ b/src/objects/num.rs @@ -147,6 +147,84 @@ macro_rules! int_fits_larger_int( ); +fn err_if_invalid_value<'p, T: PartialEq, F: Fn() -> T> + (obj: &PyObject<'p>, invalid_value: T, func: F) -> PyResult<'p, T> { + let py = obj.python(); + let v = func(); + if v == invalid_value && PyErr::occurred(py) { + Err(PyErr::fetch(py)) + } else { + Ok(v) + } +} + +macro_rules! int_convert_u64_or_i64 ( + ($rust_type:ty, $pylong_from_ll_or_ull:expr, $pylong_as_ull_or_ull:expr) => ( + impl <'p> ToPyObject<'p> for $rust_type { + #[cfg(feature="python27-sys")] + type ObjectType = PyObject<'p>; + + #[cfg(feature="python3-sys")] + type ObjectType = PyLong<'p>; + + #[cfg(feature="python27-sys")] + fn to_py_object(&self, py: Python<'p>) -> PyObject<'p> { + unsafe { + let ptr = match num::traits::cast::<$rust_type, c_long>(*self) { + Some(v) => ffi::PyInt_FromLong(v), + None => $pylong_from_ll_or_ull(*self) + }; + err::from_owned_ptr_or_panic(py, ptr) + } + } + + #[cfg(feature="python3-sys")] + fn to_py_object(&self, py: Python<'p>) -> PyLong<'p> { + unsafe { + err::cast_from_owned_ptr_or_panic(py, $pylong_from_ll_or_ull(*self)) + } + } + } + + impl <'p> FromPyObject<'p> for $rust_type { + #[cfg(feature="python27-sys")] + fn from_py_object(s: &PyObject<'p>) -> PyResult<'p, $rust_type> { + let py = s.python(); + let ptr = s.as_ptr(); + + unsafe { + if ffi::PyLong_Check(ptr) != 0 { + err_if_invalid_value(s, !0, || $pylong_as_ull_or_ull(s.as_ptr()) ) + } else if ffi::PyInt_Check(ptr) != 0 { + match num::traits::cast::(ffi::PyInt_AS_LONG(ptr)) { + Some(v) => Ok(v), + None => Err(overflow_error(py)) + } + } else { + let num = try!(err::result_from_owned_ptr(py, ffi::PyNumber_Long(ptr))); + err_if_invalid_value(&num, !0, || $pylong_as_ull_or_ull(num.as_ptr()) ) + } + } + } + + #[cfg(feature="python3-sys")] + fn from_py_object(s: &PyObject<'p>) -> PyResult<'p, $rust_type> { + let py = s.python(); + let ptr = s.as_ptr(); + unsafe { + if ffi::PyLong_Check(ptr) != 0 { + err_if_invalid_value(s, !0, || $pylong_as_ull_or_ull(s.as_ptr()) ) + } else { + let num = try!(err::result_from_owned_ptr(py, ffi::PyNumber_Long(ptr))); + err_if_invalid_value(&num, !0, || $pylong_as_ull_or_ull(num.as_ptr()) ) + } + } + } + } + ) +); + + int_fits_c_long!(i8); int_fits_c_long!(u8); int_fits_c_long!(i16); @@ -161,9 +239,10 @@ int_fits_larger_int!(u32, u64); #[cfg(all(target_pointer_width="64", not(target_os="windows")))] int_fits_c_long!(i64); -// TODO: manual implementation for i64 on systems with 32-bit long -// u64 has a manual implementation as it never fits into signed long +// manual implementation for i64 on systems with 32-bit long +#[cfg(all(target_pointer_width="32", not(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); @@ -172,78 +251,8 @@ int_fits_larger_int!(isize, i64); int_fits_larger_int!(usize, u64); -fn err_if_invalid_value<'p, T: PartialEq, F: Fn() -> T> - (obj: &PyObject<'p>, invalid_value: T, func: F) -> PyResult<'p, T> { - let py = obj.python(); - let v = func(); - if v == invalid_value && PyErr::occurred(py) { - Err(PyErr::fetch(py)) - } else { - Ok(v) - } -} - -impl <'p> ToPyObject<'p> for u64 { - #[cfg(feature="python27-sys")] - type ObjectType = PyObject<'p>; - - #[cfg(feature="python3-sys")] - type ObjectType = PyLong<'p>; - - #[cfg(feature="python27-sys")] - fn to_py_object(&self, py: Python<'p>) -> PyObject<'p> { - unsafe { - let ptr = match num::traits::cast::(*self) { - Some(v) => ffi::PyInt_FromLong(v), - None => ffi::PyLong_FromUnsignedLongLong(*self) - }; - err::from_owned_ptr_or_panic(py, ptr) - } - } - - #[cfg(feature="python3-sys")] - fn to_py_object(&self, py: Python<'p>) -> PyLong<'p> { - unsafe { - err::cast_from_owned_ptr_or_panic(py, ffi::PyLong_FromUnsignedLongLong(*self)) - } - } -} - -impl <'p> FromPyObject<'p> for u64 { - #[cfg(feature="python27-sys")] - fn from_py_object(s: &PyObject<'p>) -> PyResult<'p, u64> { - let py = s.python(); - let ptr = s.as_ptr(); - - unsafe { - if ffi::PyLong_Check(ptr) != 0 { - err_if_invalid_value(s, !0, || ffi::PyLong_AsUnsignedLongLong(s.as_ptr()) ) - } else if ffi::PyInt_Check(ptr) != 0 { - match num::traits::cast::(ffi::PyInt_AS_LONG(ptr)) { - Some(v) => Ok(v), - None => Err(overflow_error(py)) - } - } else { - let num = try!(err::result_from_owned_ptr(py, ffi::PyNumber_Long(ptr))); - err_if_invalid_value(&num, !0, || ffi::PyLong_AsUnsignedLongLong(num.as_ptr()) ) - } - } - } - - #[cfg(feature="python3-sys")] - fn from_py_object(s: &PyObject<'p>) -> PyResult<'p, u64> { - let py = s.python(); - let ptr = s.as_ptr(); - unsafe { - if ffi::PyLong_Check(ptr) != 0 { - err_if_invalid_value(s, !0, || ffi::PyLong_AsUnsignedLongLong(s.as_ptr()) ) - } else { - let num = try!(err::result_from_owned_ptr(py, ffi::PyNumber_Long(ptr))); - err_if_invalid_value(&num, !0, || ffi::PyLong_AsUnsignedLongLong(num.as_ptr()) ) - } - } - } -} +// u64 has a manual implementation as it never fits into signed long +int_convert_u64_or_i64!(u64, ffi::PyLong_FromUnsignedLongLong, ffi::PyLong_AsUnsignedLongLong); impl <'p> ToPyObject<'p> for f64 { type ObjectType = PyFloat<'p>; From 92a30e2c3390fb3911e968d60bd8243481a518e5 Mon Sep 17 00:00:00 2001 From: Yoichi Imai Date: Wed, 27 May 2015 00:17:42 +0900 Subject: [PATCH 3/3] Added tests for i64. --- src/objects/num.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/objects/num.rs b/src/objects/num.rs index 5be2b59b..638cb407 100644 --- a/src/objects/num.rs +++ b/src/objects/num.rs @@ -339,7 +339,29 @@ mod test { assert_eq!(v as u64, obj.extract::().unwrap()); assert!(obj.extract::().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_py_object(py).into_object(); + assert_eq!(v, obj.extract::().unwrap()); + assert_eq!(v as u64, obj.extract::().unwrap()); + assert!(obj.extract::().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_py_object(py).into_object(); + assert_eq!(v, obj.extract::().unwrap()); + assert!(obj.extract::().is_err()); + assert!(obj.extract::().is_err()); + } + #[test] fn test_u64_max() { let gil = Python::acquire_gil();