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