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