1#![allow(clippy::float_cmp)]
20
21use libc::{c_double, c_long};
22use num_traits::cast::cast;
23
24use super::exc;
25use super::object::PyObject;
26use crate::conversion::{FromPyObject, ToPyObject};
27use crate::err::{self, PyErr, PyResult};
28use crate::ffi;
29use crate::python::{PyClone, PyDrop, Python, PythonObject};
30
31#[cfg(feature = "python27-sys")]
43pub struct PyInt(PyObject);
44#[cfg(feature = "python27-sys")]
45pyobject_newtype!(PyInt, PyInt_Check, PyInt_Type);
46
47pub struct PyLong(PyObject);
56pyobject_newtype!(PyLong, PyLong_Check, PyLong_Type);
57
58pub struct PyFloat(PyObject);
65pyobject_newtype!(PyFloat, PyFloat_Check, PyFloat_Type);
66
67#[cfg(feature = "python27-sys")]
68impl PyInt {
69 pub fn new(py: Python, val: c_long) -> PyInt {
75 unsafe { err::cast_from_owned_ptr_or_panic(py, ffi::PyInt_FromLong(val)) }
76 }
77
78 pub fn value(&self, _py: Python) -> c_long {
85 unsafe { ffi::PyInt_AS_LONG(self.0.as_ptr()) }
86 }
87}
88
89impl PyFloat {
90 pub fn new(py: Python, val: c_double) -> PyFloat {
92 unsafe { err::cast_from_owned_ptr_or_panic(py, ffi::PyFloat_FromDouble(val)) }
93 }
94
95 pub fn value(&self, _py: Python) -> c_double {
97 unsafe { ffi::PyFloat_AsDouble(self.0.as_ptr()) }
98 }
99}
100
101macro_rules! int_fits_c_long(
102 ($rust_type:ty) => (
103 #[cfg(feature="python27-sys")]
105 impl ToPyObject for $rust_type {
106 type ObjectType = PyInt;
107
108 fn to_py_object(&self, py: Python) -> PyInt {
109 unsafe {
110 err::cast_from_owned_ptr_or_panic(py,
111 ffi::PyInt_FromLong(*self as c_long))
112 }
113 }
114 }
115
116 #[cfg(feature="python3-sys")]
118 impl ToPyObject for $rust_type {
119 type ObjectType = PyLong;
120
121 fn to_py_object(&self, py: Python) -> PyLong {
122 unsafe {
123 err::cast_from_owned_ptr_or_panic(py,
124 ffi::PyLong_FromLong(*self as c_long))
125 }
126 }
127 }
128
129 extract!(
130 obj to $rust_type;
131 py => {
136 let ptr = obj.as_ptr();
137 let val;
138 unsafe {
139 if ffi::PyLong_Check(ptr) != 0 {
140 val = ffi::PyLong_AsLong(obj.as_ptr());
141 } else {
142 let num = err::result_from_owned_ptr(py, ffi::PyNumber_Index(ptr))?;
143 val = ffi::PyLong_AsLong(num.as_ptr());
144 num.release_ref(py);
145 }
146 };
147 if val == -1 && PyErr::occurred(py) {
148 return Err(PyErr::fetch(py));
149 }
150 match cast::<c_long, $rust_type>(val) {
151 Some(v) => Ok(v),
152 None => Err(overflow_error(py))
153 }
154 }
155 );
156 )
157);
158
159macro_rules! int_fits_larger_int(
160 ($rust_type:ty, $larger_type:ty) => (
161 impl ToPyObject for $rust_type {
164 type ObjectType = <$larger_type as ToPyObject>::ObjectType;
165
166 #[inline]
167 fn to_py_object(&self, py: Python) -> <$larger_type as ToPyObject>::ObjectType {
168 (*self as $larger_type).to_py_object(py)
169 }
170 }
171
172 extract!(
173 obj to $rust_type;
174 py => {
179 let val = obj.extract::<$larger_type>(py)?;
180 match cast::<$larger_type, $rust_type>(val) {
181 Some(v) => Ok(v),
182 None => Err(overflow_error(py))
183 }
184 }
185 );
186 )
187);
188
189fn err_if_invalid_value<T: PartialEq>(
190 py: Python,
191 invalid_value: T,
192 actual_value: T,
193) -> PyResult<T> {
194 if actual_value == invalid_value && PyErr::occurred(py) {
195 Err(PyErr::fetch(py))
196 } else {
197 Ok(actual_value)
198 }
199}
200
201macro_rules! int_convert_u64_or_i64 (
202 ($rust_type:ty, $pylong_from_ll_or_ull:expr, $pylong_as_ull_or_ull:expr) => (
203 impl <'p> ToPyObject for $rust_type {
206 #[cfg(feature="python27-sys")]
207 type ObjectType = PyObject;
208
209 #[cfg(feature="python3-sys")]
210 type ObjectType = PyLong;
211
212 #[cfg(feature="python27-sys")]
213 fn to_py_object(&self, py: Python) -> PyObject {
214 unsafe {
215 let ptr = match cast::<$rust_type, c_long>(*self) {
216 Some(v) => ffi::PyInt_FromLong(v),
217 None => $pylong_from_ll_or_ull(*self)
218 };
219 err::from_owned_ptr_or_panic(py, ptr)
220 }
221 }
222
223 #[cfg(feature="python3-sys")]
224 fn to_py_object(&self, py: Python) -> PyLong {
225 unsafe {
226 err::cast_from_owned_ptr_or_panic(py, $pylong_from_ll_or_ull(*self))
227 }
228 }
229 }
230
231 impl <'s> FromPyObject<'s> for $rust_type {
236 #[cfg(feature="python27-sys")]
237 fn extract(py: Python, obj: &'s PyObject) -> PyResult<$rust_type> {
238 let ptr = obj.as_ptr();
239
240 unsafe {
241 if ffi::PyLong_Check(ptr) != 0 {
242 err_if_invalid_value(py, !0, $pylong_as_ull_or_ull(ptr))
243 } else if ffi::PyInt_Check(ptr) != 0 {
244 match cast::<c_long, $rust_type>(ffi::PyInt_AS_LONG(ptr)) {
245 Some(v) => Ok(v),
246 None => Err(overflow_error(py))
247 }
248 } else {
249 let num = err::result_from_owned_ptr(py, ffi::PyNumber_Index(ptr))?;
250 let res = err_if_invalid_value(py, !0, $pylong_as_ull_or_ull(num.as_ptr()));
251 num.release_ref(py);
252 res
253 }
254 }
255 }
256
257 #[cfg(feature="python3-sys")]
258 fn extract(py: Python, obj: &'s PyObject) -> PyResult<$rust_type> {
259 let ptr = obj.as_ptr();
260 unsafe {
261 if ffi::PyLong_Check(ptr) != 0 {
262 err_if_invalid_value(py, !0, $pylong_as_ull_or_ull(ptr))
263 } else {
264 let num = err::result_from_owned_ptr(py, ffi::PyNumber_Index(ptr))?;
265 let res = err_if_invalid_value(py, !0, $pylong_as_ull_or_ull(num.as_ptr()));
266 num.release_ref(py);
267 res
268 }
269 }
270 }
271 }
272 )
273);
274
275int_fits_c_long!(i8);
276int_fits_c_long!(u8);
277int_fits_c_long!(i16);
278int_fits_c_long!(u16);
279int_fits_c_long!(i32);
280
281#[cfg(all(target_pointer_width = "64", not(target_os = "windows")))]
283int_fits_c_long!(u32);
284#[cfg(any(target_pointer_width = "32", target_os = "windows"))]
285int_fits_larger_int!(u32, u64);
286
287#[cfg(all(target_pointer_width = "64", not(target_os = "windows")))]
288int_fits_c_long!(i64);
289
290#[cfg(any(target_pointer_width = "32", target_os = "windows"))]
292int_convert_u64_or_i64!(i64, ffi::PyLong_FromLongLong, ffi::PyLong_AsLongLong);
293
294#[cfg(all(target_pointer_width = "64", not(target_os = "windows")))]
295int_fits_c_long!(isize);
296#[cfg(any(target_pointer_width = "32", target_os = "windows"))]
297int_fits_larger_int!(isize, i64);
298
299int_fits_larger_int!(usize, u64);
300
301int_convert_u64_or_i64!(
303 u64,
304 ffi::PyLong_FromUnsignedLongLong,
305 ffi::PyLong_AsUnsignedLongLong
306);
307
308impl ToPyObject for f64 {
310 type ObjectType = PyFloat;
311
312 fn to_py_object(&self, py: Python) -> PyFloat {
313 PyFloat::new(py, *self)
314 }
315}
316
317extract!(
318 obj to f64;
319 py => {
321 let v = unsafe { ffi::PyFloat_AsDouble(obj.as_ptr()) };
322 if v == -1.0 && PyErr::occurred(py) {
323 Err(PyErr::fetch(py))
324 } else {
325 Ok(v)
326 }
327 }
328);
329
330fn overflow_error(py: Python) -> PyErr {
331 PyErr::new_lazy_init(py.get_type::<exc::OverflowError>(), None)
332}
333
334impl ToPyObject for f32 {
336 type ObjectType = PyFloat;
337
338 fn to_py_object(&self, py: Python) -> PyFloat {
339 PyFloat::new(py, *self as f64)
340 }
341}
342
343extract!(
344 obj to f32;
345 py => {
350 Ok(obj.extract::<f64>(py)? as f32)
351 }
352);
353
354#[cfg(test)]
355mod test {
356 use crate::exc;
357 use crate::conversion::ToPyObject;
358 use crate::python::{Python, PythonObject};
359
360 macro_rules! num_to_py_object_and_back (
361 ($func_name:ident, $t1:ty, $t2:ty) => (
362 #[test]
363 fn $func_name() {
364 let gil = Python::acquire_gil();
365 let py = gil.python();
366 let val = 123 as $t1;
367 let obj = val.to_py_object(py).into_object();
368 assert_eq!(obj.extract::<$t2>(py).unwrap(), val as $t2);
369 }
370 )
371 );
372
373 num_to_py_object_and_back!(to_from_f64, f64, f64);
374 num_to_py_object_and_back!(to_from_f32, f32, f32);
375 num_to_py_object_and_back!(to_from_i8, i8, i8);
376 num_to_py_object_and_back!(to_from_u8, u8, u8);
377 num_to_py_object_and_back!(to_from_i16, i16, i16);
378 num_to_py_object_and_back!(to_from_u16, u16, u16);
379 num_to_py_object_and_back!(to_from_i32, i32, i32);
380 num_to_py_object_and_back!(to_from_u32, u32, u32);
381 num_to_py_object_and_back!(to_from_i64, i64, i64);
382 num_to_py_object_and_back!(to_from_u64, u64, u64);
383 num_to_py_object_and_back!(to_from_isize, isize, isize);
384 num_to_py_object_and_back!(to_from_usize, usize, usize);
385 num_to_py_object_and_back!(int_to_float, i32, f64);
386
387
388 macro_rules! float_to_int_fails (
389 ($func_name:ident, $t:ty) => (
390 #[test]
391 fn $func_name() {
392 let gil = Python::acquire_gil();
393 let py = gil.python();
394 let obj = (1.0f64).to_py_object(py).into_object();
395 let err = obj.extract::<$t>(py).unwrap_err();
396 assert!(err.matches(py, py.get_type::<exc::TypeError>()));
397 }
398 )
399 );
400 float_to_int_fails!(float_to_i32, i32);
401 float_to_int_fails!(float_to_u32, u32);
402 float_to_int_fails!(float_to_i64, i64);
403 float_to_int_fails!(float_to_u64, u64);
404
405 macro_rules! str_to_int_fails (
406 ($func_name:ident, $t:ty) => (
407 #[test]
408 fn $func_name() {
409 let gil = Python::acquire_gil();
410 let py = gil.python();
411 let obj = "".to_py_object(py).into_object();
413 let err = obj.extract::<$t>(py).unwrap_err();
414 assert!(err.matches(py, py.get_type::<exc::TypeError>()));
415
416 let obj = "1".to_py_object(py).into_object();
418 let err = obj.extract::<$t>(py).unwrap_err();
419 assert!(err.matches(py, py.get_type::<exc::TypeError>()));
420 }
421 )
422 );
423
424 str_to_int_fails!(str_to_i32, i32);
425 str_to_int_fails!(str_to_u32, u32);
426 str_to_int_fails!(str_to_i64, i64);
427 str_to_int_fails!(str_to_u64, u64);
428
429 #[test]
430 fn test_u32_max() {
431 let gil = Python::acquire_gil();
432 let py = gil.python();
433 let v = std::u32::MAX;
434 let obj = v.to_py_object(py).into_object();
435 assert_eq!(v, obj.extract::<u32>(py).unwrap());
436 assert_eq!(v as u64, obj.extract::<u64>(py).unwrap());
437 assert!(obj.extract::<i32>(py).is_err());
438 }
439
440 #[test]
441 fn test_i64_max() {
442 let gil = Python::acquire_gil();
443 let py = gil.python();
444 let v = std::i64::MAX;
445 let obj = v.to_py_object(py).into_object();
446 assert_eq!(v, obj.extract::<i64>(py).unwrap());
447 assert_eq!(v as u64, obj.extract::<u64>(py).unwrap());
448 assert!(obj.extract::<u32>(py).is_err());
449 }
450
451 #[test]
452 fn test_i64_min() {
453 let gil = Python::acquire_gil();
454 let py = gil.python();
455 let v = std::i64::MIN;
456 let obj = v.to_py_object(py).into_object();
457 assert_eq!(v, obj.extract::<i64>(py).unwrap());
458 assert!(obj.extract::<i32>(py).is_err());
459 assert!(obj.extract::<u64>(py).is_err());
460 }
461
462 #[test]
463 fn test_u64_max() {
464 let gil = Python::acquire_gil();
465 let py = gil.python();
466 let v = std::u64::MAX;
467 let obj = v.to_py_object(py).into_object();
468 println!("{:?}", obj);
469 assert_eq!(v, obj.extract::<u64>(py).unwrap());
470 assert!(obj.extract::<i64>(py).is_err());
471 }
472}