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