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