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