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