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