1 | #[cfg (feature = "experimental-inspect" )] |
2 | use crate::inspect::types::TypeInfo; |
3 | use crate::{ |
4 | exceptions, ffi, FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject, |
5 | }; |
6 | use std::num::{ |
7 | NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, |
8 | NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, |
9 | }; |
10 | use std::os::raw::c_long; |
11 | |
12 | macro_rules! int_fits_larger_int { |
13 | ($rust_type:ty, $larger_type:ty) => { |
14 | impl ToPyObject for $rust_type { |
15 | #[inline] |
16 | fn to_object(&self, py: Python<'_>) -> PyObject { |
17 | (*self as $larger_type).into_py(py) |
18 | } |
19 | } |
20 | impl IntoPy<PyObject> for $rust_type { |
21 | fn into_py(self, py: Python<'_>) -> PyObject { |
22 | (self as $larger_type).into_py(py) |
23 | } |
24 | |
25 | #[cfg(feature = "experimental-inspect" )] |
26 | fn type_output() -> TypeInfo { |
27 | <$larger_type>::type_output() |
28 | } |
29 | } |
30 | |
31 | impl<'source> FromPyObject<'source> for $rust_type { |
32 | fn extract(obj: &'source PyAny) -> PyResult<Self> { |
33 | let val: $larger_type = obj.extract()?; |
34 | <$rust_type>::try_from(val) |
35 | .map_err(|e| exceptions::PyOverflowError::new_err(e.to_string())) |
36 | } |
37 | |
38 | #[cfg(feature = "experimental-inspect" )] |
39 | fn type_input() -> TypeInfo { |
40 | <$larger_type>::type_input() |
41 | } |
42 | } |
43 | }; |
44 | } |
45 | |
46 | macro_rules! int_convert_u64_or_i64 { |
47 | ($rust_type:ty, $pylong_from_ll_or_ull:expr, $pylong_as_ll_or_ull:expr) => { |
48 | impl ToPyObject for $rust_type { |
49 | #[inline] |
50 | fn to_object(&self, py: Python<'_>) -> PyObject { |
51 | unsafe { PyObject::from_owned_ptr(py, $pylong_from_ll_or_ull(*self)) } |
52 | } |
53 | } |
54 | impl IntoPy<PyObject> for $rust_type { |
55 | #[inline] |
56 | fn into_py(self, py: Python<'_>) -> PyObject { |
57 | unsafe { PyObject::from_owned_ptr(py, $pylong_from_ll_or_ull(self)) } |
58 | } |
59 | |
60 | #[cfg(feature = "experimental-inspect" )] |
61 | fn type_output() -> TypeInfo { |
62 | TypeInfo::builtin("int" ) |
63 | } |
64 | } |
65 | impl<'source> FromPyObject<'source> for $rust_type { |
66 | fn extract(ob: &'source PyAny) -> PyResult<$rust_type> { |
67 | let ptr = ob.as_ptr(); |
68 | unsafe { |
69 | let num = ffi::PyNumber_Index(ptr); |
70 | if num.is_null() { |
71 | Err(PyErr::fetch(ob.py())) |
72 | } else { |
73 | let result = err_if_invalid_value(ob.py(), !0, $pylong_as_ll_or_ull(num)); |
74 | ffi::Py_DECREF(num); |
75 | result |
76 | } |
77 | } |
78 | } |
79 | |
80 | #[cfg(feature = "experimental-inspect" )] |
81 | fn type_input() -> TypeInfo { |
82 | Self::type_output() |
83 | } |
84 | } |
85 | }; |
86 | } |
87 | |
88 | macro_rules! int_fits_c_long { |
89 | ($rust_type:ty) => { |
90 | impl ToPyObject for $rust_type { |
91 | fn to_object(&self, py: Python<'_>) -> PyObject { |
92 | unsafe { PyObject::from_owned_ptr(py, ffi::PyLong_FromLong(*self as c_long)) } |
93 | } |
94 | } |
95 | impl IntoPy<PyObject> for $rust_type { |
96 | fn into_py(self, py: Python<'_>) -> PyObject { |
97 | unsafe { PyObject::from_owned_ptr(py, ffi::PyLong_FromLong(self as c_long)) } |
98 | } |
99 | |
100 | #[cfg(feature = "experimental-inspect" )] |
101 | fn type_output() -> TypeInfo { |
102 | TypeInfo::builtin("int" ) |
103 | } |
104 | } |
105 | |
106 | impl<'source> FromPyObject<'source> for $rust_type { |
107 | fn extract(obj: &'source PyAny) -> PyResult<Self> { |
108 | let ptr = obj.as_ptr(); |
109 | let val = unsafe { |
110 | let num = ffi::PyNumber_Index(ptr); |
111 | if num.is_null() { |
112 | Err(PyErr::fetch(obj.py())) |
113 | } else { |
114 | let val = err_if_invalid_value(obj.py(), -1, ffi::PyLong_AsLong(num)); |
115 | ffi::Py_DECREF(num); |
116 | val |
117 | } |
118 | }?; |
119 | <$rust_type>::try_from(val) |
120 | .map_err(|e| exceptions::PyOverflowError::new_err(e.to_string())) |
121 | } |
122 | |
123 | #[cfg(feature = "experimental-inspect" )] |
124 | fn type_input() -> TypeInfo { |
125 | Self::type_output() |
126 | } |
127 | } |
128 | }; |
129 | } |
130 | |
131 | int_fits_c_long!(i8); |
132 | int_fits_c_long!(u8); |
133 | int_fits_c_long!(i16); |
134 | int_fits_c_long!(u16); |
135 | int_fits_c_long!(i32); |
136 | |
137 | // If c_long is 64-bits, we can use more types with int_fits_c_long!: |
138 | #[cfg (all(target_pointer_width = "64" , not(target_os = "windows" )))] |
139 | int_fits_c_long!(u32); |
140 | #[cfg (any(target_pointer_width = "32" , target_os = "windows" ))] |
141 | int_fits_larger_int!(u32, u64); |
142 | |
143 | #[cfg (all(target_pointer_width = "64" , not(target_os = "windows" )))] |
144 | int_fits_c_long!(i64); |
145 | |
146 | // manual implementation for i64 on systems with 32-bit long |
147 | #[cfg (any(target_pointer_width = "32" , target_os = "windows" ))] |
148 | int_convert_u64_or_i64!(i64, ffi::PyLong_FromLongLong, ffi::PyLong_AsLongLong); |
149 | |
150 | #[cfg (all(target_pointer_width = "64" , not(target_os = "windows" )))] |
151 | int_fits_c_long!(isize); |
152 | #[cfg (any(target_pointer_width = "32" , target_os = "windows" ))] |
153 | int_fits_larger_int!(isize, i64); |
154 | |
155 | int_fits_larger_int!(usize, u64); |
156 | |
157 | // u64 has a manual implementation as it never fits into signed long |
158 | int_convert_u64_or_i64!( |
159 | u64, |
160 | ffi::PyLong_FromUnsignedLongLong, |
161 | ffi::PyLong_AsUnsignedLongLong |
162 | ); |
163 | |
164 | #[cfg (not(Py_LIMITED_API))] |
165 | mod fast_128bit_int_conversion { |
166 | use super::*; |
167 | |
168 | // for 128bit Integers |
169 | macro_rules! int_convert_128 { |
170 | ($rust_type: ty, $is_signed: expr) => { |
171 | impl ToPyObject for $rust_type { |
172 | #[inline] |
173 | fn to_object(&self, py: Python<'_>) -> PyObject { |
174 | (*self).into_py(py) |
175 | } |
176 | } |
177 | impl IntoPy<PyObject> for $rust_type { |
178 | fn into_py(self, py: Python<'_>) -> PyObject { |
179 | // Always use little endian |
180 | let bytes = self.to_le_bytes(); |
181 | unsafe { |
182 | PyObject::from_owned_ptr( |
183 | py, |
184 | ffi::_PyLong_FromByteArray( |
185 | bytes.as_ptr() as *const std::os::raw::c_uchar, |
186 | bytes.len(), |
187 | 1, |
188 | $is_signed, |
189 | ), |
190 | ) |
191 | } |
192 | } |
193 | |
194 | #[cfg(feature = "experimental-inspect" )] |
195 | fn type_output() -> TypeInfo { |
196 | TypeInfo::builtin("int" ) |
197 | } |
198 | } |
199 | |
200 | impl<'source> FromPyObject<'source> for $rust_type { |
201 | fn extract(ob: &'source PyAny) -> PyResult<$rust_type> { |
202 | let num = unsafe { |
203 | PyObject::from_owned_ptr_or_err(ob.py(), ffi::PyNumber_Index(ob.as_ptr()))? |
204 | }; |
205 | let mut buffer = [0; std::mem::size_of::<$rust_type>()]; |
206 | crate::err::error_on_minusone(ob.py(), unsafe { |
207 | ffi::_PyLong_AsByteArray( |
208 | num.as_ptr() as *mut ffi::PyLongObject, |
209 | buffer.as_mut_ptr(), |
210 | buffer.len(), |
211 | 1, |
212 | $is_signed, |
213 | ) |
214 | })?; |
215 | Ok(<$rust_type>::from_le_bytes(buffer)) |
216 | } |
217 | |
218 | #[cfg(feature = "experimental-inspect" )] |
219 | fn type_input() -> TypeInfo { |
220 | Self::type_output() |
221 | } |
222 | } |
223 | }; |
224 | } |
225 | |
226 | int_convert_128!(i128, 1); |
227 | int_convert_128!(u128, 0); |
228 | } |
229 | |
230 | // For ABI3 we implement the conversion manually. |
231 | #[cfg (Py_LIMITED_API)] |
232 | mod slow_128bit_int_conversion { |
233 | use super::*; |
234 | const SHIFT: usize = 64; |
235 | |
236 | // for 128bit Integers |
237 | macro_rules! int_convert_128 { |
238 | ($rust_type: ty, $half_type: ty) => { |
239 | impl ToPyObject for $rust_type { |
240 | #[inline] |
241 | fn to_object(&self, py: Python<'_>) -> PyObject { |
242 | (*self).into_py(py) |
243 | } |
244 | } |
245 | |
246 | impl IntoPy<PyObject> for $rust_type { |
247 | fn into_py(self, py: Python<'_>) -> PyObject { |
248 | let lower = (self as u64).into_py(py); |
249 | let upper = ((self >> SHIFT) as $half_type).into_py(py); |
250 | let shift = SHIFT.into_py(py); |
251 | unsafe { |
252 | let shifted = PyObject::from_owned_ptr( |
253 | py, |
254 | ffi::PyNumber_Lshift(upper.as_ptr(), shift.as_ptr()), |
255 | ); |
256 | PyObject::from_owned_ptr( |
257 | py, |
258 | ffi::PyNumber_Or(shifted.as_ptr(), lower.as_ptr()), |
259 | ) |
260 | } |
261 | } |
262 | |
263 | #[cfg(feature = "experimental-inspect" )] |
264 | fn type_output() -> TypeInfo { |
265 | TypeInfo::builtin("int" ) |
266 | } |
267 | } |
268 | |
269 | impl<'source> FromPyObject<'source> for $rust_type { |
270 | fn extract(ob: &'source PyAny) -> PyResult<$rust_type> { |
271 | let py = ob.py(); |
272 | unsafe { |
273 | let lower = err_if_invalid_value( |
274 | py, |
275 | -1 as _, |
276 | ffi::PyLong_AsUnsignedLongLongMask(ob.as_ptr()), |
277 | )? as $rust_type; |
278 | let shift = SHIFT.into_py(py); |
279 | let shifted = PyObject::from_owned_ptr_or_err( |
280 | py, |
281 | ffi::PyNumber_Rshift(ob.as_ptr(), shift.as_ptr()), |
282 | )?; |
283 | let upper: $half_type = shifted.extract(py)?; |
284 | Ok((<$rust_type>::from(upper) << SHIFT) | lower) |
285 | } |
286 | } |
287 | |
288 | #[cfg(feature = "experimental-inspect" )] |
289 | fn type_input() -> TypeInfo { |
290 | Self::type_output() |
291 | } |
292 | } |
293 | }; |
294 | } |
295 | |
296 | int_convert_128!(i128, i64); |
297 | int_convert_128!(u128, u64); |
298 | } |
299 | |
300 | fn err_if_invalid_value<T: PartialEq>( |
301 | py: Python<'_>, |
302 | invalid_value: T, |
303 | actual_value: T, |
304 | ) -> PyResult<T> { |
305 | if actual_value == invalid_value { |
306 | if let Some(err: PyErr) = PyErr::take(py) { |
307 | return Err(err); |
308 | } |
309 | } |
310 | |
311 | Ok(actual_value) |
312 | } |
313 | |
314 | macro_rules! nonzero_int_impl { |
315 | ($nonzero_type:ty, $primitive_type:ty) => { |
316 | impl ToPyObject for $nonzero_type { |
317 | fn to_object(&self, py: Python<'_>) -> PyObject { |
318 | self.get().to_object(py) |
319 | } |
320 | } |
321 | |
322 | impl IntoPy<PyObject> for $nonzero_type { |
323 | fn into_py(self, py: Python<'_>) -> PyObject { |
324 | self.get().into_py(py) |
325 | } |
326 | } |
327 | |
328 | impl<'source> FromPyObject<'source> for $nonzero_type { |
329 | fn extract(obj: &'source PyAny) -> PyResult<Self> { |
330 | let val: $primitive_type = obj.extract()?; |
331 | <$nonzero_type>::try_from(val) |
332 | .map_err(|_| exceptions::PyValueError::new_err("invalid zero value" )) |
333 | } |
334 | |
335 | #[cfg(feature = "experimental-inspect" )] |
336 | fn type_input() -> TypeInfo { |
337 | <$primitive_type>::type_input() |
338 | } |
339 | } |
340 | }; |
341 | } |
342 | |
343 | nonzero_int_impl!(NonZeroI8, i8); |
344 | nonzero_int_impl!(NonZeroI16, i16); |
345 | nonzero_int_impl!(NonZeroI32, i32); |
346 | nonzero_int_impl!(NonZeroI64, i64); |
347 | nonzero_int_impl!(NonZeroI128, i128); |
348 | nonzero_int_impl!(NonZeroIsize, isize); |
349 | nonzero_int_impl!(NonZeroU8, u8); |
350 | nonzero_int_impl!(NonZeroU16, u16); |
351 | nonzero_int_impl!(NonZeroU32, u32); |
352 | nonzero_int_impl!(NonZeroU64, u64); |
353 | nonzero_int_impl!(NonZeroU128, u128); |
354 | nonzero_int_impl!(NonZeroUsize, usize); |
355 | |
356 | #[cfg (test)] |
357 | mod test_128bit_integers { |
358 | use super::*; |
359 | #[cfg (not(target_arch = "wasm32" ))] |
360 | use crate::types::PyDict; |
361 | |
362 | #[cfg (not(target_arch = "wasm32" ))] |
363 | use proptest::prelude::*; |
364 | |
365 | #[cfg (not(target_arch = "wasm32" ))] |
366 | proptest! { |
367 | #[test] |
368 | fn test_i128_roundtrip(x: i128) { |
369 | Python::with_gil(|py| { |
370 | let x_py = x.into_py(py); |
371 | let locals = PyDict::new(py); |
372 | locals.set_item("x_py" , x_py.clone_ref(py)).unwrap(); |
373 | py.run(&format!("assert x_py == {}" , x), None, Some(locals)).unwrap(); |
374 | let roundtripped: i128 = x_py.extract(py).unwrap(); |
375 | assert_eq!(x, roundtripped); |
376 | }) |
377 | } |
378 | |
379 | #[test] |
380 | fn test_nonzero_i128_roundtrip( |
381 | x in any::<i128>() |
382 | .prop_filter("Values must not be 0" , |x| x != &0) |
383 | .prop_map(|x| NonZeroI128::new(x).unwrap()) |
384 | ) { |
385 | Python::with_gil(|py| { |
386 | let x_py = x.into_py(py); |
387 | let locals = PyDict::new(py); |
388 | locals.set_item("x_py" , x_py.clone_ref(py)).unwrap(); |
389 | py.run(&format!("assert x_py == {}" , x), None, Some(locals)).unwrap(); |
390 | let roundtripped: NonZeroI128 = x_py.extract(py).unwrap(); |
391 | assert_eq!(x, roundtripped); |
392 | }) |
393 | } |
394 | } |
395 | |
396 | #[cfg (not(target_arch = "wasm32" ))] |
397 | proptest! { |
398 | #[test] |
399 | fn test_u128_roundtrip(x: u128) { |
400 | Python::with_gil(|py| { |
401 | let x_py = x.into_py(py); |
402 | let locals = PyDict::new(py); |
403 | locals.set_item("x_py" , x_py.clone_ref(py)).unwrap(); |
404 | py.run(&format!("assert x_py == {}" , x), None, Some(locals)).unwrap(); |
405 | let roundtripped: u128 = x_py.extract(py).unwrap(); |
406 | assert_eq!(x, roundtripped); |
407 | }) |
408 | } |
409 | |
410 | #[test] |
411 | fn test_nonzero_u128_roundtrip( |
412 | x in any::<u128>() |
413 | .prop_filter("Values must not be 0" , |x| x != &0) |
414 | .prop_map(|x| NonZeroU128::new(x).unwrap()) |
415 | ) { |
416 | Python::with_gil(|py| { |
417 | let x_py = x.into_py(py); |
418 | let locals = PyDict::new(py); |
419 | locals.set_item("x_py" , x_py.clone_ref(py)).unwrap(); |
420 | py.run(&format!("assert x_py == {}" , x), None, Some(locals)).unwrap(); |
421 | let roundtripped: NonZeroU128 = x_py.extract(py).unwrap(); |
422 | assert_eq!(x, roundtripped); |
423 | }) |
424 | } |
425 | } |
426 | |
427 | #[test ] |
428 | fn test_i128_max() { |
429 | Python::with_gil(|py| { |
430 | let v = std::i128::MAX; |
431 | let obj = v.to_object(py); |
432 | assert_eq!(v, obj.extract::<i128>(py).unwrap()); |
433 | assert_eq!(v as u128, obj.extract::<u128>(py).unwrap()); |
434 | assert!(obj.extract::<u64>(py).is_err()); |
435 | }) |
436 | } |
437 | |
438 | #[test ] |
439 | fn test_i128_min() { |
440 | Python::with_gil(|py| { |
441 | let v = std::i128::MIN; |
442 | let obj = v.to_object(py); |
443 | assert_eq!(v, obj.extract::<i128>(py).unwrap()); |
444 | assert!(obj.extract::<i64>(py).is_err()); |
445 | assert!(obj.extract::<u128>(py).is_err()); |
446 | }) |
447 | } |
448 | |
449 | #[test ] |
450 | fn test_u128_max() { |
451 | Python::with_gil(|py| { |
452 | let v = std::u128::MAX; |
453 | let obj = v.to_object(py); |
454 | assert_eq!(v, obj.extract::<u128>(py).unwrap()); |
455 | assert!(obj.extract::<i128>(py).is_err()); |
456 | }) |
457 | } |
458 | |
459 | #[test ] |
460 | fn test_i128_overflow() { |
461 | Python::with_gil(|py| { |
462 | let obj = py.eval("(1 << 130) * -1" , None, None).unwrap(); |
463 | let err = obj.extract::<i128>().unwrap_err(); |
464 | assert!(err.is_instance_of::<crate::exceptions::PyOverflowError>(py)); |
465 | }) |
466 | } |
467 | |
468 | #[test ] |
469 | fn test_u128_overflow() { |
470 | Python::with_gil(|py| { |
471 | let obj = py.eval("1 << 130" , None, None).unwrap(); |
472 | let err = obj.extract::<u128>().unwrap_err(); |
473 | assert!(err.is_instance_of::<crate::exceptions::PyOverflowError>(py)); |
474 | }) |
475 | } |
476 | |
477 | #[test ] |
478 | fn test_nonzero_i128_max() { |
479 | Python::with_gil(|py| { |
480 | let v = NonZeroI128::new(std::i128::MAX).unwrap(); |
481 | let obj = v.to_object(py); |
482 | assert_eq!(v, obj.extract::<NonZeroI128>(py).unwrap()); |
483 | assert_eq!( |
484 | NonZeroU128::new(v.get() as u128).unwrap(), |
485 | obj.extract::<NonZeroU128>(py).unwrap() |
486 | ); |
487 | assert!(obj.extract::<NonZeroU64>(py).is_err()); |
488 | }) |
489 | } |
490 | |
491 | #[test ] |
492 | fn test_nonzero_i128_min() { |
493 | Python::with_gil(|py| { |
494 | let v = NonZeroI128::new(std::i128::MIN).unwrap(); |
495 | let obj = v.to_object(py); |
496 | assert_eq!(v, obj.extract::<NonZeroI128>(py).unwrap()); |
497 | assert!(obj.extract::<NonZeroI64>(py).is_err()); |
498 | assert!(obj.extract::<NonZeroU128>(py).is_err()); |
499 | }) |
500 | } |
501 | |
502 | #[test ] |
503 | fn test_nonzero_u128_max() { |
504 | Python::with_gil(|py| { |
505 | let v = NonZeroU128::new(std::u128::MAX).unwrap(); |
506 | let obj = v.to_object(py); |
507 | assert_eq!(v, obj.extract::<NonZeroU128>(py).unwrap()); |
508 | assert!(obj.extract::<NonZeroI128>(py).is_err()); |
509 | }) |
510 | } |
511 | |
512 | #[test ] |
513 | fn test_nonzero_i128_overflow() { |
514 | Python::with_gil(|py| { |
515 | let obj = py.eval("(1 << 130) * -1" , None, None).unwrap(); |
516 | let err = obj.extract::<NonZeroI128>().unwrap_err(); |
517 | assert!(err.is_instance_of::<crate::exceptions::PyOverflowError>(py)); |
518 | }) |
519 | } |
520 | |
521 | #[test ] |
522 | fn test_nonzero_u128_overflow() { |
523 | Python::with_gil(|py| { |
524 | let obj = py.eval("1 << 130" , None, None).unwrap(); |
525 | let err = obj.extract::<NonZeroU128>().unwrap_err(); |
526 | assert!(err.is_instance_of::<crate::exceptions::PyOverflowError>(py)); |
527 | }) |
528 | } |
529 | |
530 | #[test ] |
531 | fn test_nonzero_i128_zero_value() { |
532 | Python::with_gil(|py| { |
533 | let obj = py.eval("0" , None, None).unwrap(); |
534 | let err = obj.extract::<NonZeroI128>().unwrap_err(); |
535 | assert!(err.is_instance_of::<crate::exceptions::PyValueError>(py)); |
536 | }) |
537 | } |
538 | |
539 | #[test ] |
540 | fn test_nonzero_u128_zero_value() { |
541 | Python::with_gil(|py| { |
542 | let obj = py.eval("0" , None, None).unwrap(); |
543 | let err = obj.extract::<NonZeroU128>().unwrap_err(); |
544 | assert!(err.is_instance_of::<crate::exceptions::PyValueError>(py)); |
545 | }) |
546 | } |
547 | } |
548 | |
549 | #[cfg (test)] |
550 | mod tests { |
551 | use crate::Python; |
552 | use crate::ToPyObject; |
553 | use std::num::*; |
554 | |
555 | #[test ] |
556 | fn test_u32_max() { |
557 | Python::with_gil(|py| { |
558 | let v = std::u32::MAX; |
559 | let obj = v.to_object(py); |
560 | assert_eq!(v, obj.extract::<u32>(py).unwrap()); |
561 | assert_eq!(u64::from(v), obj.extract::<u64>(py).unwrap()); |
562 | assert!(obj.extract::<i32>(py).is_err()); |
563 | }); |
564 | } |
565 | |
566 | #[test ] |
567 | fn test_i64_max() { |
568 | Python::with_gil(|py| { |
569 | let v = std::i64::MAX; |
570 | let obj = v.to_object(py); |
571 | assert_eq!(v, obj.extract::<i64>(py).unwrap()); |
572 | assert_eq!(v as u64, obj.extract::<u64>(py).unwrap()); |
573 | assert!(obj.extract::<u32>(py).is_err()); |
574 | }); |
575 | } |
576 | |
577 | #[test ] |
578 | fn test_i64_min() { |
579 | Python::with_gil(|py| { |
580 | let v = std::i64::MIN; |
581 | let obj = v.to_object(py); |
582 | assert_eq!(v, obj.extract::<i64>(py).unwrap()); |
583 | assert!(obj.extract::<i32>(py).is_err()); |
584 | assert!(obj.extract::<u64>(py).is_err()); |
585 | }); |
586 | } |
587 | |
588 | #[test ] |
589 | fn test_u64_max() { |
590 | Python::with_gil(|py| { |
591 | let v = std::u64::MAX; |
592 | let obj = v.to_object(py); |
593 | assert_eq!(v, obj.extract::<u64>(py).unwrap()); |
594 | assert!(obj.extract::<i64>(py).is_err()); |
595 | }); |
596 | } |
597 | |
598 | macro_rules! test_common ( |
599 | ($test_mod_name:ident, $t:ty) => ( |
600 | mod $test_mod_name { |
601 | use crate::exceptions; |
602 | use crate::ToPyObject; |
603 | use crate::Python; |
604 | |
605 | #[test] |
606 | fn from_py_string_type_error() { |
607 | Python::with_gil(|py| { |
608 | let obj = ("123" ).to_object(py); |
609 | let err = obj.extract::<$t>(py).unwrap_err(); |
610 | assert!(err.is_instance_of::<exceptions::PyTypeError>(py)); |
611 | }); |
612 | } |
613 | |
614 | #[test] |
615 | fn from_py_float_type_error() { |
616 | Python::with_gil(|py| { |
617 | let obj = (12.3).to_object(py); |
618 | let err = obj.extract::<$t>(py).unwrap_err(); |
619 | assert!(err.is_instance_of::<exceptions::PyTypeError>(py));}); |
620 | } |
621 | |
622 | #[test] |
623 | fn to_py_object_and_back() { |
624 | Python::with_gil(|py| { |
625 | let val = 123 as $t; |
626 | let obj = val.to_object(py); |
627 | assert_eq!(obj.extract::<$t>(py).unwrap(), val as $t);}); |
628 | } |
629 | } |
630 | ) |
631 | ); |
632 | |
633 | test_common!(i8, i8); |
634 | test_common!(u8, u8); |
635 | test_common!(i16, i16); |
636 | test_common!(u16, u16); |
637 | test_common!(i32, i32); |
638 | test_common!(u32, u32); |
639 | test_common!(i64, i64); |
640 | test_common!(u64, u64); |
641 | test_common!(isize, isize); |
642 | test_common!(usize, usize); |
643 | test_common!(i128, i128); |
644 | test_common!(u128, u128); |
645 | |
646 | #[test ] |
647 | fn test_nonzero_u32_max() { |
648 | Python::with_gil(|py| { |
649 | let v = NonZeroU32::new(std::u32::MAX).unwrap(); |
650 | let obj = v.to_object(py); |
651 | assert_eq!(v, obj.extract::<NonZeroU32>(py).unwrap()); |
652 | assert_eq!(NonZeroU64::from(v), obj.extract::<NonZeroU64>(py).unwrap()); |
653 | assert!(obj.extract::<NonZeroI32>(py).is_err()); |
654 | }); |
655 | } |
656 | |
657 | #[test ] |
658 | fn test_nonzero_i64_max() { |
659 | Python::with_gil(|py| { |
660 | let v = NonZeroI64::new(std::i64::MAX).unwrap(); |
661 | let obj = v.to_object(py); |
662 | assert_eq!(v, obj.extract::<NonZeroI64>(py).unwrap()); |
663 | assert_eq!( |
664 | NonZeroU64::new(v.get() as u64).unwrap(), |
665 | obj.extract::<NonZeroU64>(py).unwrap() |
666 | ); |
667 | assert!(obj.extract::<NonZeroU32>(py).is_err()); |
668 | }); |
669 | } |
670 | |
671 | #[test ] |
672 | fn test_nonzero_i64_min() { |
673 | Python::with_gil(|py| { |
674 | let v = NonZeroI64::new(std::i64::MIN).unwrap(); |
675 | let obj = v.to_object(py); |
676 | assert_eq!(v, obj.extract::<NonZeroI64>(py).unwrap()); |
677 | assert!(obj.extract::<NonZeroI32>(py).is_err()); |
678 | assert!(obj.extract::<NonZeroU64>(py).is_err()); |
679 | }); |
680 | } |
681 | |
682 | #[test ] |
683 | fn test_nonzero_u64_max() { |
684 | Python::with_gil(|py| { |
685 | let v = NonZeroU64::new(std::u64::MAX).unwrap(); |
686 | let obj = v.to_object(py); |
687 | assert_eq!(v, obj.extract::<NonZeroU64>(py).unwrap()); |
688 | assert!(obj.extract::<NonZeroI64>(py).is_err()); |
689 | }); |
690 | } |
691 | |
692 | macro_rules! test_nonzero_common ( |
693 | ($test_mod_name:ident, $t:ty) => ( |
694 | mod $test_mod_name { |
695 | use crate::exceptions; |
696 | use crate::ToPyObject; |
697 | use crate::Python; |
698 | use std::num::*; |
699 | |
700 | #[test] |
701 | fn from_py_string_type_error() { |
702 | Python::with_gil(|py| { |
703 | let obj = ("123" ).to_object(py); |
704 | let err = obj.extract::<$t>(py).unwrap_err(); |
705 | assert!(err.is_instance_of::<exceptions::PyTypeError>(py)); |
706 | }); |
707 | } |
708 | |
709 | #[test] |
710 | fn from_py_float_type_error() { |
711 | Python::with_gil(|py| { |
712 | let obj = (12.3).to_object(py); |
713 | let err = obj.extract::<$t>(py).unwrap_err(); |
714 | assert!(err.is_instance_of::<exceptions::PyTypeError>(py));}); |
715 | } |
716 | |
717 | #[test] |
718 | fn to_py_object_and_back() { |
719 | Python::with_gil(|py| { |
720 | let val = <$t>::new(123).unwrap(); |
721 | let obj = val.to_object(py); |
722 | assert_eq!(obj.extract::<$t>(py).unwrap(), val);}); |
723 | } |
724 | } |
725 | ) |
726 | ); |
727 | |
728 | test_nonzero_common!(nonzero_i8, NonZeroI8); |
729 | test_nonzero_common!(nonzero_u8, NonZeroU8); |
730 | test_nonzero_common!(nonzero_i16, NonZeroI16); |
731 | test_nonzero_common!(nonzero_u16, NonZeroU16); |
732 | test_nonzero_common!(nonzero_i32, NonZeroI32); |
733 | test_nonzero_common!(nonzero_u32, NonZeroU32); |
734 | test_nonzero_common!(nonzero_i64, NonZeroI64); |
735 | test_nonzero_common!(nonzero_u64, NonZeroU64); |
736 | test_nonzero_common!(nonzero_isize, NonZeroIsize); |
737 | test_nonzero_common!(nonzero_usize, NonZeroUsize); |
738 | test_nonzero_common!(nonzero_i128, NonZeroI128); |
739 | test_nonzero_common!(nonzero_u128, NonZeroU128); |
740 | } |
741 | |