Skip to content

Commit

Permalink
Merge pull request #173 from kngwyu/128bitInt
Browse files Browse the repository at this point in the history
Add 128bit integer support
  • Loading branch information
konstin committed Jun 6, 2018
2 parents 97688cb + 66183d4 commit 4fc52cf
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 192 deletions.
43 changes: 18 additions & 25 deletions src/ffi2/longobject.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use std::os::raw::{c_void, c_char, c_int, c_long, c_ulong, c_longlong, c_ulonglong, c_double};
use std::os::raw::{
c_void, c_char, c_int, c_long, c_ulong, c_longlong, c_ulonglong, c_double, c_uchar
};
use libc::size_t;
use ffi2::pyport::Py_ssize_t;
use ffi2::object::*;

//enum PyLongObject { /* representation hidden */ }

pub enum PyLongObject {}

#[cfg_attr(windows, link(name="pythonXY"))] extern "C" {
pub static mut PyLong_Type: PyTypeObject;
Expand Down Expand Up @@ -58,26 +59,18 @@ pub unsafe fn PyLong_CheckExact(op : *mut PyObject) -> c_int {

pub fn PyLong_GetInfo() -> *mut PyObject;

/*
pub fn _PyLong_AsInt(arg1: *mut PyObject) -> c_int;
pub fn _PyLong_Frexp(a: *mut PyLongObject, e: *mut Py_ssize_t)
-> c_double;
pub fn _PyLong_Sign(v: *mut PyObject) -> c_int;
pub fn _PyLong_NumBits(v: *mut PyObject) -> size_t;
pub fn _PyLong_FromByteArray(bytes: *const c_uchar, n: size_t,
little_endian: c_int,
is_signed: c_int) -> *mut PyObject;
pub fn _PyLong_AsByteArray(v: *mut PyLongObject,
bytes: *mut c_uchar, n: size_t,
little_endian: c_int,
is_signed: c_int) -> c_int;
pub fn _PyLong_Format(aa: *mut PyObject, base: c_int,
addL: c_int, newstyle: c_int)
-> *mut PyObject;
pub fn _PyLong_FormatAdvanced(obj: *mut PyObject,
format_spec: *mut c_char,
format_spec_len: Py_ssize_t)
-> *mut PyObject;*/
}
pub fn _PyLong_FromByteArray(
bytes: *const c_uchar,
n: size_t,
little_endian: c_int,
is_signed: c_int,
) -> *mut PyObject;

pub fn _PyLong_AsByteArray(
v: *mut PyLongObject,
bytes: *const c_uchar,
n: size_t,
little_endian: c_int,
is_signed: c_int,
) -> c_int;
}
22 changes: 21 additions & 1 deletion src/ffi3/longobject.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use libc::size_t;
use std::os::raw::{c_void, c_char, c_int, c_long, c_ulong, c_longlong, c_ulonglong, c_double};
use std::os::raw::{
c_void, c_char, c_int, c_long, c_ulong, c_longlong, c_ulonglong, c_double, c_uchar
};
use ffi3::object::*;
use ffi3::pyport::Py_ssize_t;

Expand Down Expand Up @@ -59,3 +61,21 @@ pub unsafe fn PyLong_CheckExact(op : *mut PyObject) -> c_int {
-> c_long;
}

#[cfg(not(Py_LIMITED_API))]
#[cfg_attr(windows, link(name = "pythonXY"))]
extern "C" {
pub fn _PyLong_FromByteArray(
bytes: *const c_uchar,
n: size_t,
little_endian: c_int,
is_signed: c_int,
) -> *mut PyObject;

pub fn _PyLong_AsByteArray(
v: *mut PyLongObject,
bytes: *const c_uchar,
n: size_t,
little_endian: c_int,
is_signed: c_int,
) -> c_int;
}
3 changes: 3 additions & 0 deletions src/objects/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,9 @@ mod stringutils;
mod set;
pub mod exc;

#[macro_use]
mod num_common;

#[cfg(Py_3)]
mod num3;

Expand Down
87 changes: 6 additions & 81 deletions src/objects/num2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython

use std::os::raw::c_long;
use std::os::raw::{c_long, c_uchar};

extern crate num_traits;
use self::num_traits::cast::cast;
Expand All @@ -14,6 +14,7 @@ use err::{PyResult, PyErr};
use instance::{Py, PyObjectWithToken};
use objects::{exc, PyObjectRef};
use conversion::{ToPyObject, IntoPyObject, FromPyObject};
use super::num_common::{err_if_invalid_value, IS_LITTLE_ENDIAN};

/// Represents a Python `int` object.
///
Expand Down Expand Up @@ -90,41 +91,6 @@ macro_rules! int_fits_c_long(
)
);


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!(obj to $rust_type => {
let val = try!($crate::ObjectProtocol::extract::<$larger_type>(obj));
match cast::<$larger_type, $rust_type>(val) {
Some(v) => Ok(v),
None => Err(exc::OverflowError.into())
}
});
)
);


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 {
Expand Down Expand Up @@ -174,7 +140,6 @@ macro_rules! int_convert_u64_or_i64 (
)
);


int_fits_c_long!(i8);
int_fits_c_long!(u8);
int_fits_c_long!(i16);
Expand Down Expand Up @@ -204,10 +169,11 @@ 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);

int_convert_bignum!(i128, 16, IS_LITTLE_ENDIAN, 1);
int_convert_bignum!(u128, 16, IS_LITTLE_ENDIAN, 0);

#[cfg(test)]
mod test {
use std;
use python::{Python};
use conversion::ToPyObject;

Expand Down Expand Up @@ -236,52 +202,11 @@ mod test {
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!(to_from_i128, i128, i128);
num_to_py_object_and_back!(to_from_u128, u128, u128);
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);
assert_eq!(v, obj.extract::<u64>(py).unwrap());
assert!(obj.extract::<i64>(py).is_err());
}
}
95 changes: 10 additions & 85 deletions src/objects/num3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython

use std::os::raw::c_long;
use std::os::raw::{c_long, c_uchar};

extern crate num_traits;
use self::num_traits::cast::cast;
Expand All @@ -14,7 +14,7 @@ use err::{PyResult, PyErr};
use objects::{exc, PyObjectRef};
use instance::PyObjectWithToken;
use conversion::{ToPyObject, IntoPyObject, FromPyObject};

use super::num_common::{err_if_invalid_value, IS_LITTLE_ENDIAN};
/// Represents a Python `int` object.
///
/// You can usually avoid directly working with this type
Expand All @@ -25,7 +25,6 @@ pub struct PyLong(PyObject);

pyobject_native_type!(PyLong, PyLong_Type, PyLong_Check);


macro_rules! int_fits_c_long(
($rust_type:ty) => (
impl ToPyObject for $rust_type {
Expand Down Expand Up @@ -64,43 +63,6 @@ macro_rules! int_fits_c_long(
)
);


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).into_object(py)
}
}
impl IntoPyObject for $rust_type {
fn into_object(self, py: Python) -> PyObject {
(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())
}
});
)
);



#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
fn err_if_invalid_value<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_ll_or_ull:expr) => (
impl ToPyObject for $rust_type {
Expand Down Expand Up @@ -138,7 +100,6 @@ macro_rules! int_convert_u64_or_i64 (
)
);


int_fits_c_long!(i8);
int_fits_c_long!(u8);
int_fits_c_long!(i16);
Expand Down Expand Up @@ -168,10 +129,13 @@ 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);

#[cfg(not(Py_LIMITED_API))]
int_convert_bignum!(i128, 16, IS_LITTLE_ENDIAN, 1);
#[cfg(not(Py_LIMITED_API))]
int_convert_bignum!(u128, 16, IS_LITTLE_ENDIAN, 0);

#[cfg(test)]
mod test {
use std;
use python::Python;
use conversion::ToPyObject;

Expand Down Expand Up @@ -224,47 +188,8 @@ mod test {
test_common!(u64, u64);
test_common!(isize, isize);
test_common!(usize, usize);

#[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);
assert_eq!(v, obj.extract::<u64>(py).unwrap());
assert!(obj.extract::<i64>(py).is_err());
}
#[cfg(not(Py_LIMITED_API))]
test_common!(i128, i128);
#[cfg(not(Py_LIMITED_API))]
test_common!(u128, u128);
}
Loading

0 comments on commit 4fc52cf

Please sign in to comment.