1use crate::ffi_ptr_ext::FfiPtrExt;
2#[cfg(feature = "experimental-inspect")]
3use crate::inspect::types::TypeInfo;
4use crate::types::any::PyAnyMethods;
5use crate::{
6 exceptions, ffi, Bound, FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python,
7 ToPyObject,
8};
9use std::num::{
10 NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
11 NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
12};
13use std::os::raw::c_long;
14
15macro_rules! int_fits_larger_int {
16 ($rust_type:ty, $larger_type:ty) => {
17 impl ToPyObject for $rust_type {
18 #[inline]
19 fn to_object(&self, py: Python<'_>) -> PyObject {
20 (*self as $larger_type).into_py(py)
21 }
22 }
23 impl IntoPy<PyObject> for $rust_type {
24 fn into_py(self, py: Python<'_>) -> PyObject {
25 (self as $larger_type).into_py(py)
26 }
27
28 #[cfg(feature = "experimental-inspect")]
29 fn type_output() -> TypeInfo {
30 <$larger_type>::type_output()
31 }
32 }
33
34 impl FromPyObject<'_> for $rust_type {
35 fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult<Self> {
36 let val: $larger_type = obj.extract()?;
37 <$rust_type>::try_from(val)
38 .map_err(|e| exceptions::PyOverflowError::new_err(e.to_string()))
39 }
40
41 #[cfg(feature = "experimental-inspect")]
42 fn type_input() -> TypeInfo {
43 <$larger_type>::type_input()
44 }
45 }
46 };
47}
48
49macro_rules! extract_int {
50 ($obj:ident, $error_val:expr, $pylong_as:expr) => {
51 extract_int!($obj, $error_val, $pylong_as, false)
52 };
53
54 ($obj:ident, $error_val:expr, $pylong_as:expr, $force_index_call: literal) => {
55 if cfg!(Py_3_10) && !$force_index_call {
61 err_if_invalid_value($obj.py(), $error_val, unsafe { $pylong_as($obj.as_ptr()) })
62 } else if let Ok(long) = $obj.downcast::<crate::types::PyLong>() {
63 err_if_invalid_value($obj.py(), $error_val, unsafe { $pylong_as(long.as_ptr()) })
65 } else {
66 unsafe {
67 let num = ffi::PyNumber_Index($obj.as_ptr()).assume_owned_or_err($obj.py())?;
68 err_if_invalid_value($obj.py(), $error_val, $pylong_as(num.as_ptr()))
69 }
70 }
71 };
72}
73
74macro_rules! int_convert_u64_or_i64 {
75 ($rust_type:ty, $pylong_from_ll_or_ull:expr, $pylong_as_ll_or_ull:expr, $force_index_call:literal) => {
76 impl ToPyObject for $rust_type {
77 #[inline]
78 fn to_object(&self, py: Python<'_>) -> PyObject {
79 unsafe { PyObject::from_owned_ptr(py, $pylong_from_ll_or_ull(*self)) }
80 }
81 }
82 impl IntoPy<PyObject> for $rust_type {
83 #[inline]
84 fn into_py(self, py: Python<'_>) -> PyObject {
85 unsafe { PyObject::from_owned_ptr(py, $pylong_from_ll_or_ull(self)) }
86 }
87
88 #[cfg(feature = "experimental-inspect")]
89 fn type_output() -> TypeInfo {
90 TypeInfo::builtin("int")
91 }
92 }
93 impl FromPyObject<'_> for $rust_type {
94 fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult<$rust_type> {
95 extract_int!(obj, !0, $pylong_as_ll_or_ull, $force_index_call)
96 }
97
98 #[cfg(feature = "experimental-inspect")]
99 fn type_input() -> TypeInfo {
100 Self::type_output()
101 }
102 }
103 };
104}
105
106macro_rules! int_fits_c_long {
107 ($rust_type:ty) => {
108 impl ToPyObject for $rust_type {
109 fn to_object(&self, py: Python<'_>) -> PyObject {
110 unsafe { PyObject::from_owned_ptr(py, ffi::PyLong_FromLong(*self as c_long)) }
111 }
112 }
113 impl IntoPy<PyObject> for $rust_type {
114 fn into_py(self, py: Python<'_>) -> PyObject {
115 unsafe { PyObject::from_owned_ptr(py, ffi::PyLong_FromLong(self as c_long)) }
116 }
117
118 #[cfg(feature = "experimental-inspect")]
119 fn type_output() -> TypeInfo {
120 TypeInfo::builtin("int")
121 }
122 }
123
124 impl<'py> FromPyObject<'py> for $rust_type {
125 fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult<Self> {
126 let val: c_long = extract_int!(obj, -1, ffi::PyLong_AsLong)?;
127 <$rust_type>::try_from(val)
128 .map_err(|e| exceptions::PyOverflowError::new_err(e.to_string()))
129 }
130
131 #[cfg(feature = "experimental-inspect")]
132 fn type_input() -> TypeInfo {
133 Self::type_output()
134 }
135 }
136 };
137}
138
139int_fits_c_long!(i8);
140int_fits_c_long!(u8);
141int_fits_c_long!(i16);
142int_fits_c_long!(u16);
143int_fits_c_long!(i32);
144
145#[cfg(all(target_pointer_width = "64", not(target_os = "windows")))]
147int_fits_c_long!(u32);
148#[cfg(any(target_pointer_width = "32", target_os = "windows"))]
149int_fits_larger_int!(u32, u64);
150
151#[cfg(all(target_pointer_width = "64", not(target_os = "windows")))]
152int_fits_c_long!(i64);
153
154#[cfg(any(target_pointer_width = "32", target_os = "windows"))]
156int_convert_u64_or_i64!(i64, ffi::PyLong_FromLongLong, ffi::PyLong_AsLongLong, false);
157
158#[cfg(all(target_pointer_width = "64", not(target_os = "windows")))]
159int_fits_c_long!(isize);
160#[cfg(any(target_pointer_width = "32", target_os = "windows"))]
161int_fits_larger_int!(isize, i64);
162
163int_fits_larger_int!(usize, u64);
164
165int_convert_u64_or_i64!(
167 u64,
168 ffi::PyLong_FromUnsignedLongLong,
169 ffi::PyLong_AsUnsignedLongLong,
170 true
171);
172
173#[cfg(all(not(Py_LIMITED_API), not(GraalPy)))]
174mod fast_128bit_int_conversion {
175 use super::*;
176
177 macro_rules! int_convert_128 {
179 ($rust_type: ty, $is_signed: literal) => {
180 impl ToPyObject for $rust_type {
181 #[inline]
182 fn to_object(&self, py: Python<'_>) -> PyObject {
183 (*self).into_py(py)
184 }
185 }
186 impl IntoPy<PyObject> for $rust_type {
187 fn into_py(self, py: Python<'_>) -> PyObject {
188 #[cfg(not(Py_3_13))]
189 {
190 let bytes = self.to_le_bytes();
191 unsafe {
192 ffi::_PyLong_FromByteArray(
193 bytes.as_ptr().cast(),
194 bytes.len(),
195 1,
196 $is_signed.into(),
197 )
198 .assume_owned(py)
199 .unbind()
200 }
201 }
202 #[cfg(Py_3_13)]
203 {
204 let bytes = self.to_ne_bytes();
205
206 if $is_signed {
207 unsafe {
208 ffi::PyLong_FromNativeBytes(
209 bytes.as_ptr().cast(),
210 bytes.len(),
211 ffi::Py_ASNATIVEBYTES_NATIVE_ENDIAN,
212 )
213 .assume_owned(py)
214 }
215 } else {
216 unsafe {
217 ffi::PyLong_FromUnsignedNativeBytes(
218 bytes.as_ptr().cast(),
219 bytes.len(),
220 ffi::Py_ASNATIVEBYTES_NATIVE_ENDIAN,
221 )
222 .assume_owned(py)
223 }
224 }
225 .unbind()
226 }
227 }
228
229 #[cfg(feature = "experimental-inspect")]
230 fn type_output() -> TypeInfo {
231 TypeInfo::builtin("int")
232 }
233 }
234
235 impl FromPyObject<'_> for $rust_type {
236 fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult<$rust_type> {
237 let num =
238 unsafe { ffi::PyNumber_Index(ob.as_ptr()).assume_owned_or_err(ob.py())? };
239 let mut buffer = [0u8; std::mem::size_of::<$rust_type>()];
240 #[cfg(not(Py_3_13))]
241 {
242 crate::err::error_on_minusone(ob.py(), unsafe {
243 ffi::_PyLong_AsByteArray(
244 num.as_ptr() as *mut ffi::PyLongObject,
245 buffer.as_mut_ptr(),
246 buffer.len(),
247 1,
248 $is_signed.into(),
249 )
250 })?;
251 Ok(<$rust_type>::from_le_bytes(buffer))
252 }
253 #[cfg(Py_3_13)]
254 {
255 let mut flags = ffi::Py_ASNATIVEBYTES_NATIVE_ENDIAN;
256 if !$is_signed {
257 flags |= ffi::Py_ASNATIVEBYTES_UNSIGNED_BUFFER
258 | ffi::Py_ASNATIVEBYTES_REJECT_NEGATIVE;
259 }
260 let actual_size: usize = unsafe {
261 ffi::PyLong_AsNativeBytes(
262 num.as_ptr(),
263 buffer.as_mut_ptr().cast(),
264 buffer
265 .len()
266 .try_into()
267 .expect("length of buffer fits in Py_ssize_t"),
268 flags,
269 )
270 }
271 .try_into()
272 .map_err(|_| PyErr::fetch(ob.py()))?;
273 if actual_size as usize > buffer.len() {
274 return Err(crate::exceptions::PyOverflowError::new_err(
275 "Python int larger than 128 bits",
276 ));
277 }
278 Ok(<$rust_type>::from_ne_bytes(buffer))
279 }
280 }
281
282 #[cfg(feature = "experimental-inspect")]
283 fn type_input() -> TypeInfo {
284 Self::type_output()
285 }
286 }
287 };
288 }
289
290 int_convert_128!(i128, true);
291 int_convert_128!(u128, false);
292}
293
294#[cfg(any(Py_LIMITED_API, GraalPy))]
296mod slow_128bit_int_conversion {
297 use super::*;
298 const SHIFT: usize = 64;
299
300 macro_rules! int_convert_128 {
302 ($rust_type: ty, $half_type: ty) => {
303 impl ToPyObject for $rust_type {
304 #[inline]
305 fn to_object(&self, py: Python<'_>) -> PyObject {
306 (*self).into_py(py)
307 }
308 }
309
310 impl IntoPy<PyObject> for $rust_type {
311 fn into_py(self, py: Python<'_>) -> PyObject {
312 let lower = (self as u64).into_py(py);
313 let upper = ((self >> SHIFT) as $half_type).into_py(py);
314 let shift = SHIFT.into_py(py);
315 unsafe {
316 let shifted = PyObject::from_owned_ptr(
317 py,
318 ffi::PyNumber_Lshift(upper.as_ptr(), shift.as_ptr()),
319 );
320 PyObject::from_owned_ptr(
321 py,
322 ffi::PyNumber_Or(shifted.as_ptr(), lower.as_ptr()),
323 )
324 }
325 }
326
327 #[cfg(feature = "experimental-inspect")]
328 fn type_output() -> TypeInfo {
329 TypeInfo::builtin("int")
330 }
331 }
332
333 impl FromPyObject<'_> for $rust_type {
334 fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult<$rust_type> {
335 let py = ob.py();
336 unsafe {
337 let lower = err_if_invalid_value(
338 py,
339 -1 as _,
340 ffi::PyLong_AsUnsignedLongLongMask(ob.as_ptr()),
341 )? as $rust_type;
342 let shift = SHIFT.into_py(py);
343 let shifted = PyObject::from_owned_ptr_or_err(
344 py,
345 ffi::PyNumber_Rshift(ob.as_ptr(), shift.as_ptr()),
346 )?;
347 let upper: $half_type = shifted.extract(py)?;
348 Ok((<$rust_type>::from(upper) << SHIFT) | lower)
349 }
350 }
351
352 #[cfg(feature = "experimental-inspect")]
353 fn type_input() -> TypeInfo {
354 Self::type_output()
355 }
356 }
357 };
358 }
359
360 int_convert_128!(i128, i64);
361 int_convert_128!(u128, u64);
362}
363
364fn err_if_invalid_value<T: PartialEq>(
365 py: Python<'_>,
366 invalid_value: T,
367 actual_value: T,
368) -> PyResult<T> {
369 if actual_value == invalid_value {
370 if let Some(err) = PyErr::take(py) {
371 return Err(err);
372 }
373 }
374
375 Ok(actual_value)
376}
377
378macro_rules! nonzero_int_impl {
379 ($nonzero_type:ty, $primitive_type:ty) => {
380 impl ToPyObject for $nonzero_type {
381 fn to_object(&self, py: Python<'_>) -> PyObject {
382 self.get().to_object(py)
383 }
384 }
385
386 impl IntoPy<PyObject> for $nonzero_type {
387 fn into_py(self, py: Python<'_>) -> PyObject {
388 self.get().into_py(py)
389 }
390 }
391
392 impl FromPyObject<'_> for $nonzero_type {
393 fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult<Self> {
394 let val: $primitive_type = obj.extract()?;
395 <$nonzero_type>::try_from(val)
396 .map_err(|_| exceptions::PyValueError::new_err("invalid zero value"))
397 }
398
399 #[cfg(feature = "experimental-inspect")]
400 fn type_input() -> TypeInfo {
401 <$primitive_type>::type_input()
402 }
403 }
404 };
405}
406
407nonzero_int_impl!(NonZeroI8, i8);
408nonzero_int_impl!(NonZeroI16, i16);
409nonzero_int_impl!(NonZeroI32, i32);
410nonzero_int_impl!(NonZeroI64, i64);
411nonzero_int_impl!(NonZeroI128, i128);
412nonzero_int_impl!(NonZeroIsize, isize);
413nonzero_int_impl!(NonZeroU8, u8);
414nonzero_int_impl!(NonZeroU16, u16);
415nonzero_int_impl!(NonZeroU32, u32);
416nonzero_int_impl!(NonZeroU64, u64);
417nonzero_int_impl!(NonZeroU128, u128);
418nonzero_int_impl!(NonZeroUsize, usize);
419
420#[cfg(test)]
421mod test_128bit_integers {
422 use super::*;
423
424 #[cfg(not(target_arch = "wasm32"))]
425 use crate::types::PyDict;
426
427 #[cfg(not(target_arch = "wasm32"))]
428 use crate::types::dict::PyDictMethods;
429
430 #[cfg(not(target_arch = "wasm32"))]
431 use proptest::prelude::*;
432
433 #[cfg(not(target_arch = "wasm32"))]
434 proptest! {
435 #[test]
436 fn test_i128_roundtrip(x: i128) {
437 Python::with_gil(|py| {
438 let x_py = x.into_py(py);
439 let locals = PyDict::new_bound(py);
440 locals.set_item("x_py", x_py.clone_ref(py)).unwrap();
441 py.run_bound(&format!("assert x_py == {}", x), None, Some(&locals)).unwrap();
442 let roundtripped: i128 = x_py.extract(py).unwrap();
443 assert_eq!(x, roundtripped);
444 })
445 }
446
447 #[test]
448 fn test_nonzero_i128_roundtrip(
449 x in any::<i128>()
450 .prop_filter("Values must not be 0", |x| x != &0)
451 .prop_map(|x| NonZeroI128::new(x).unwrap())
452 ) {
453 Python::with_gil(|py| {
454 let x_py = x.into_py(py);
455 let locals = PyDict::new_bound(py);
456 locals.set_item("x_py", x_py.clone_ref(py)).unwrap();
457 py.run_bound(&format!("assert x_py == {}", x), None, Some(&locals)).unwrap();
458 let roundtripped: NonZeroI128 = x_py.extract(py).unwrap();
459 assert_eq!(x, roundtripped);
460 })
461 }
462 }
463
464 #[cfg(not(target_arch = "wasm32"))]
465 proptest! {
466 #[test]
467 fn test_u128_roundtrip(x: u128) {
468 Python::with_gil(|py| {
469 let x_py = x.into_py(py);
470 let locals = PyDict::new_bound(py);
471 locals.set_item("x_py", x_py.clone_ref(py)).unwrap();
472 py.run_bound(&format!("assert x_py == {}", x), None, Some(&locals)).unwrap();
473 let roundtripped: u128 = x_py.extract(py).unwrap();
474 assert_eq!(x, roundtripped);
475 })
476 }
477
478 #[test]
479 fn test_nonzero_u128_roundtrip(
480 x in any::<u128>()
481 .prop_filter("Values must not be 0", |x| x != &0)
482 .prop_map(|x| NonZeroU128::new(x).unwrap())
483 ) {
484 Python::with_gil(|py| {
485 let x_py = x.into_py(py);
486 let locals = PyDict::new_bound(py);
487 locals.set_item("x_py", x_py.clone_ref(py)).unwrap();
488 py.run_bound(&format!("assert x_py == {}", x), None, Some(&locals)).unwrap();
489 let roundtripped: NonZeroU128 = x_py.extract(py).unwrap();
490 assert_eq!(x, roundtripped);
491 })
492 }
493 }
494
495 #[test]
496 fn test_i128_max() {
497 Python::with_gil(|py| {
498 let v = i128::MAX;
499 let obj = v.to_object(py);
500 assert_eq!(v, obj.extract::<i128>(py).unwrap());
501 assert_eq!(v as u128, obj.extract::<u128>(py).unwrap());
502 assert!(obj.extract::<u64>(py).is_err());
503 })
504 }
505
506 #[test]
507 fn test_i128_min() {
508 Python::with_gil(|py| {
509 let v = i128::MIN;
510 let obj = v.to_object(py);
511 assert_eq!(v, obj.extract::<i128>(py).unwrap());
512 assert!(obj.extract::<i64>(py).is_err());
513 assert!(obj.extract::<u128>(py).is_err());
514 })
515 }
516
517 #[test]
518 fn test_u128_max() {
519 Python::with_gil(|py| {
520 let v = u128::MAX;
521 let obj = v.to_object(py);
522 assert_eq!(v, obj.extract::<u128>(py).unwrap());
523 assert!(obj.extract::<i128>(py).is_err());
524 })
525 }
526
527 #[test]
528 fn test_i128_overflow() {
529 Python::with_gil(|py| {
530 let obj = py.eval_bound("(1 << 130) * -1", None, None).unwrap();
531 let err = obj.extract::<i128>().unwrap_err();
532 assert!(err.is_instance_of::<crate::exceptions::PyOverflowError>(py));
533 })
534 }
535
536 #[test]
537 fn test_u128_overflow() {
538 Python::with_gil(|py| {
539 let obj = py.eval_bound("1 << 130", None, None).unwrap();
540 let err = obj.extract::<u128>().unwrap_err();
541 assert!(err.is_instance_of::<crate::exceptions::PyOverflowError>(py));
542 })
543 }
544
545 #[test]
546 fn test_nonzero_i128_max() {
547 Python::with_gil(|py| {
548 let v = NonZeroI128::new(i128::MAX).unwrap();
549 let obj = v.to_object(py);
550 assert_eq!(v, obj.extract::<NonZeroI128>(py).unwrap());
551 assert_eq!(
552 NonZeroU128::new(v.get() as u128).unwrap(),
553 obj.extract::<NonZeroU128>(py).unwrap()
554 );
555 assert!(obj.extract::<NonZeroU64>(py).is_err());
556 })
557 }
558
559 #[test]
560 fn test_nonzero_i128_min() {
561 Python::with_gil(|py| {
562 let v = NonZeroI128::new(i128::MIN).unwrap();
563 let obj = v.to_object(py);
564 assert_eq!(v, obj.extract::<NonZeroI128>(py).unwrap());
565 assert!(obj.extract::<NonZeroI64>(py).is_err());
566 assert!(obj.extract::<NonZeroU128>(py).is_err());
567 })
568 }
569
570 #[test]
571 fn test_nonzero_u128_max() {
572 Python::with_gil(|py| {
573 let v = NonZeroU128::new(u128::MAX).unwrap();
574 let obj = v.to_object(py);
575 assert_eq!(v, obj.extract::<NonZeroU128>(py).unwrap());
576 assert!(obj.extract::<NonZeroI128>(py).is_err());
577 })
578 }
579
580 #[test]
581 fn test_nonzero_i128_overflow() {
582 Python::with_gil(|py| {
583 let obj = py.eval_bound("(1 << 130) * -1", None, None).unwrap();
584 let err = obj.extract::<NonZeroI128>().unwrap_err();
585 assert!(err.is_instance_of::<crate::exceptions::PyOverflowError>(py));
586 })
587 }
588
589 #[test]
590 fn test_nonzero_u128_overflow() {
591 Python::with_gil(|py| {
592 let obj = py.eval_bound("1 << 130", None, None).unwrap();
593 let err = obj.extract::<NonZeroU128>().unwrap_err();
594 assert!(err.is_instance_of::<crate::exceptions::PyOverflowError>(py));
595 })
596 }
597
598 #[test]
599 fn test_nonzero_i128_zero_value() {
600 Python::with_gil(|py| {
601 let obj = py.eval_bound("0", None, None).unwrap();
602 let err = obj.extract::<NonZeroI128>().unwrap_err();
603 assert!(err.is_instance_of::<crate::exceptions::PyValueError>(py));
604 })
605 }
606
607 #[test]
608 fn test_nonzero_u128_zero_value() {
609 Python::with_gil(|py| {
610 let obj = py.eval_bound("0", None, None).unwrap();
611 let err = obj.extract::<NonZeroU128>().unwrap_err();
612 assert!(err.is_instance_of::<crate::exceptions::PyValueError>(py));
613 })
614 }
615}
616
617#[cfg(test)]
618mod tests {
619 use crate::Python;
620 use crate::ToPyObject;
621 use std::num::*;
622
623 #[test]
624 fn test_u32_max() {
625 Python::with_gil(|py| {
626 let v = u32::MAX;
627 let obj = v.to_object(py);
628 assert_eq!(v, obj.extract::<u32>(py).unwrap());
629 assert_eq!(u64::from(v), obj.extract::<u64>(py).unwrap());
630 assert!(obj.extract::<i32>(py).is_err());
631 });
632 }
633
634 #[test]
635 fn test_i64_max() {
636 Python::with_gil(|py| {
637 let v = i64::MAX;
638 let obj = v.to_object(py);
639 assert_eq!(v, obj.extract::<i64>(py).unwrap());
640 assert_eq!(v as u64, obj.extract::<u64>(py).unwrap());
641 assert!(obj.extract::<u32>(py).is_err());
642 });
643 }
644
645 #[test]
646 fn test_i64_min() {
647 Python::with_gil(|py| {
648 let v = i64::MIN;
649 let obj = v.to_object(py);
650 assert_eq!(v, obj.extract::<i64>(py).unwrap());
651 assert!(obj.extract::<i32>(py).is_err());
652 assert!(obj.extract::<u64>(py).is_err());
653 });
654 }
655
656 #[test]
657 fn test_u64_max() {
658 Python::with_gil(|py| {
659 let v = u64::MAX;
660 let obj = v.to_object(py);
661 assert_eq!(v, obj.extract::<u64>(py).unwrap());
662 assert!(obj.extract::<i64>(py).is_err());
663 });
664 }
665
666 macro_rules! test_common (
667 ($test_mod_name:ident, $t:ty) => (
668 mod $test_mod_name {
669 use crate::exceptions;
670 use crate::ToPyObject;
671 use crate::Python;
672
673 #[test]
674 fn from_py_string_type_error() {
675 Python::with_gil(|py| {
676 let obj = ("123").to_object(py);
677 let err = obj.extract::<$t>(py).unwrap_err();
678 assert!(err.is_instance_of::<exceptions::PyTypeError>(py));
679 });
680 }
681
682 #[test]
683 fn from_py_float_type_error() {
684 Python::with_gil(|py| {
685 let obj = (12.3).to_object(py);
686 let err = obj.extract::<$t>(py).unwrap_err();
687 assert!(err.is_instance_of::<exceptions::PyTypeError>(py));});
688 }
689
690 #[test]
691 fn to_py_object_and_back() {
692 Python::with_gil(|py| {
693 let val = 123 as $t;
694 let obj = val.to_object(py);
695 assert_eq!(obj.extract::<$t>(py).unwrap(), val as $t);});
696 }
697 }
698 )
699 );
700
701 test_common!(i8, i8);
702 test_common!(u8, u8);
703 test_common!(i16, i16);
704 test_common!(u16, u16);
705 test_common!(i32, i32);
706 test_common!(u32, u32);
707 test_common!(i64, i64);
708 test_common!(u64, u64);
709 test_common!(isize, isize);
710 test_common!(usize, usize);
711 test_common!(i128, i128);
712 test_common!(u128, u128);
713
714 #[test]
715 fn test_nonzero_u32_max() {
716 Python::with_gil(|py| {
717 let v = NonZeroU32::new(u32::MAX).unwrap();
718 let obj = v.to_object(py);
719 assert_eq!(v, obj.extract::<NonZeroU32>(py).unwrap());
720 assert_eq!(NonZeroU64::from(v), obj.extract::<NonZeroU64>(py).unwrap());
721 assert!(obj.extract::<NonZeroI32>(py).is_err());
722 });
723 }
724
725 #[test]
726 fn test_nonzero_i64_max() {
727 Python::with_gil(|py| {
728 let v = NonZeroI64::new(i64::MAX).unwrap();
729 let obj = v.to_object(py);
730 assert_eq!(v, obj.extract::<NonZeroI64>(py).unwrap());
731 assert_eq!(
732 NonZeroU64::new(v.get() as u64).unwrap(),
733 obj.extract::<NonZeroU64>(py).unwrap()
734 );
735 assert!(obj.extract::<NonZeroU32>(py).is_err());
736 });
737 }
738
739 #[test]
740 fn test_nonzero_i64_min() {
741 Python::with_gil(|py| {
742 let v = NonZeroI64::new(i64::MIN).unwrap();
743 let obj = v.to_object(py);
744 assert_eq!(v, obj.extract::<NonZeroI64>(py).unwrap());
745 assert!(obj.extract::<NonZeroI32>(py).is_err());
746 assert!(obj.extract::<NonZeroU64>(py).is_err());
747 });
748 }
749
750 #[test]
751 fn test_nonzero_u64_max() {
752 Python::with_gil(|py| {
753 let v = NonZeroU64::new(u64::MAX).unwrap();
754 let obj = v.to_object(py);
755 assert_eq!(v, obj.extract::<NonZeroU64>(py).unwrap());
756 assert!(obj.extract::<NonZeroI64>(py).is_err());
757 });
758 }
759
760 macro_rules! test_nonzero_common (
761 ($test_mod_name:ident, $t:ty) => (
762 mod $test_mod_name {
763 use crate::exceptions;
764 use crate::ToPyObject;
765 use crate::Python;
766 use std::num::*;
767
768 #[test]
769 fn from_py_string_type_error() {
770 Python::with_gil(|py| {
771 let obj = ("123").to_object(py);
772 let err = obj.extract::<$t>(py).unwrap_err();
773 assert!(err.is_instance_of::<exceptions::PyTypeError>(py));
774 });
775 }
776
777 #[test]
778 fn from_py_float_type_error() {
779 Python::with_gil(|py| {
780 let obj = (12.3).to_object(py);
781 let err = obj.extract::<$t>(py).unwrap_err();
782 assert!(err.is_instance_of::<exceptions::PyTypeError>(py));});
783 }
784
785 #[test]
786 fn to_py_object_and_back() {
787 Python::with_gil(|py| {
788 let val = <$t>::new(123).unwrap();
789 let obj = val.to_object(py);
790 assert_eq!(obj.extract::<$t>(py).unwrap(), val);});
791 }
792 }
793 )
794 );
795
796 test_nonzero_common!(nonzero_i8, NonZeroI8);
797 test_nonzero_common!(nonzero_u8, NonZeroU8);
798 test_nonzero_common!(nonzero_i16, NonZeroI16);
799 test_nonzero_common!(nonzero_u16, NonZeroU16);
800 test_nonzero_common!(nonzero_i32, NonZeroI32);
801 test_nonzero_common!(nonzero_u32, NonZeroU32);
802 test_nonzero_common!(nonzero_i64, NonZeroI64);
803 test_nonzero_common!(nonzero_u64, NonZeroU64);
804 test_nonzero_common!(nonzero_isize, NonZeroIsize);
805 test_nonzero_common!(nonzero_usize, NonZeroUsize);
806 test_nonzero_common!(nonzero_i128, NonZeroI128);
807 test_nonzero_common!(nonzero_u128, NonZeroU128);
808
809 #[test]
810 fn test_i64_bool() {
811 Python::with_gil(|py| {
812 let obj = true.to_object(py);
813 assert_eq!(1, obj.extract::<i64>(py).unwrap());
814 let obj = false.to_object(py);
815 assert_eq!(0, obj.extract::<i64>(py).unwrap());
816 })
817 }
818
819 #[test]
820 fn test_i64_f64() {
821 Python::with_gil(|py| {
822 let obj = 12.34f64.to_object(py);
823 let err = obj.extract::<i64>(py).unwrap_err();
824 assert!(err.is_instance_of::<crate::exceptions::PyTypeError>(py));
825 let obj = 12f64.to_object(py);
827 let err = obj.extract::<i64>(py).unwrap_err();
828 assert!(err.is_instance_of::<crate::exceptions::PyTypeError>(py));
829 })
830 }
831}