Skip to main content

pyo3/types/
num.rs

1use super::any::PyAnyMethods;
2use crate::{ffi, instance::Bound, IntoPyObject, PyAny, Python};
3#[cfg(RustPython)]
4use crate::{
5    sync::PyOnceLock,
6    types::{PyType, PyTypeMethods},
7    Py,
8};
9use core::convert::Infallible;
10
11/// Represents a Python `int` object.
12///
13/// Values of this type are accessed via PyO3's smart pointers, e.g. as
14/// [`Py<PyInt>`][crate::Py] or [`Bound<'py, PyInt>`][crate::Bound].
15///
16/// You can usually avoid directly working with this type by using
17/// [`IntoPyObject`] and [`extract`](super::PyAnyMethods::extract)
18/// with the primitive Rust integer types.
19#[repr(transparent)]
20pub struct PyInt(PyAny);
21
22#[cfg(not(RustPython))]
23pyobject_native_type_core!(PyInt, pyobject_native_static_type_object!(ffi::PyLong_Type), "builtins", "int", #checkfunction=ffi::PyLong_Check);
24
25#[cfg(RustPython)]
26pyobject_native_type_core!(
27    PyInt,
28    |py| {
29        static TYPE: PyOnceLock<Py<PyType>> = PyOnceLock::new();
30        TYPE.import(py, "builtins", "int").unwrap().as_type_ptr()
31    },
32    "builtins",
33    "int",
34    #checkfunction=ffi::PyLong_Check
35);
36
37impl PyInt {
38    /// Creates a new Python int object.
39    ///
40    /// Panics if out of memory.
41    pub fn new<'a, T>(py: Python<'a>, i: T) -> Bound<'a, PyInt>
42    where
43        T: IntoPyObject<'a, Target = PyInt, Output = Bound<'a, PyInt>, Error = Infallible>,
44    {
45        match T::into_pyobject(i, py) {
46            Ok(v) => v,
47            Err(never) => match never {},
48        }
49    }
50}
51
52macro_rules! int_compare {
53    ($rust_type: ty) => {
54        impl PartialEq<$rust_type> for Bound<'_, PyInt> {
55            #[inline]
56            fn eq(&self, other: &$rust_type) -> bool {
57                if let Ok(value) = self.extract::<$rust_type>() {
58                    value == *other
59                } else {
60                    false
61                }
62            }
63        }
64        impl PartialEq<Bound<'_, PyInt>> for $rust_type {
65            #[inline]
66            fn eq(&self, other: &Bound<'_, PyInt>) -> bool {
67                if let Ok(value) = other.extract::<$rust_type>() {
68                    value == *self
69                } else {
70                    false
71                }
72            }
73        }
74    };
75}
76
77int_compare!(i8);
78int_compare!(u8);
79int_compare!(i16);
80int_compare!(u16);
81int_compare!(i32);
82int_compare!(u32);
83int_compare!(i64);
84int_compare!(u64);
85int_compare!(i128);
86int_compare!(u128);
87int_compare!(isize);
88int_compare!(usize);
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93    use crate::{IntoPyObject, Python};
94
95    #[test]
96    fn test_partial_eq() {
97        Python::attach(|py| {
98            let v_i8 = 123i8;
99            let v_u8 = 123i8;
100            let v_i16 = 123i16;
101            let v_u16 = 123u16;
102            let v_i32 = 123i32;
103            let v_u32 = 123u32;
104            let v_i64 = 123i64;
105            let v_u64 = 123u64;
106            let v_i128 = 123i128;
107            let v_u128 = 123u128;
108            let v_isize = 123isize;
109            let v_usize = 123usize;
110            let obj = 123_i64.into_pyobject(py).unwrap();
111            assert_eq!(v_i8, obj);
112            assert_eq!(obj, v_i8);
113
114            assert_eq!(v_u8, obj);
115            assert_eq!(obj, v_u8);
116
117            assert_eq!(v_i16, obj);
118            assert_eq!(obj, v_i16);
119
120            assert_eq!(v_u16, obj);
121            assert_eq!(obj, v_u16);
122
123            assert_eq!(v_i32, obj);
124            assert_eq!(obj, v_i32);
125
126            assert_eq!(v_u32, obj);
127            assert_eq!(obj, v_u32);
128
129            assert_eq!(v_i64, obj);
130            assert_eq!(obj, v_i64);
131
132            assert_eq!(v_u64, obj);
133            assert_eq!(obj, v_u64);
134
135            assert_eq!(v_i128, obj);
136            assert_eq!(obj, v_i128);
137
138            assert_eq!(v_u128, obj);
139            assert_eq!(obj, v_u128);
140
141            assert_eq!(v_isize, obj);
142            assert_eq!(obj, v_isize);
143
144            assert_eq!(v_usize, obj);
145            assert_eq!(obj, v_usize);
146
147            let big_num = (u8::MAX as u16) + 1;
148            let big_obj = big_num.into_pyobject(py).unwrap();
149
150            for x in 0u8..=u8::MAX {
151                assert_ne!(x, big_obj);
152                assert_ne!(big_obj, x);
153            }
154        });
155    }
156
157    #[test]
158    fn test_display_int() {
159        Python::attach(|py| {
160            let s = PyInt::new(py, 42u8);
161            assert_eq!(format!("{s}"), "42");
162
163            let s = PyInt::new(py, 43i32);
164            assert_eq!(format!("{s}"), "43");
165
166            let s = PyInt::new(py, 44usize);
167            assert_eq!(format!("{s}"), "44");
168        })
169    }
170}