11use crate :: PyObject ;
22use crate :: object:: define_py_check;
33use crate :: pystate:: with_vm;
4- use core:: ffi:: { c_long, c_longlong, c_ulong, c_ulonglong} ;
5- use rustpython_vm:: PyResult ;
6- use rustpython_vm:: builtins:: PyInt ;
4+ use bitflags:: bitflags;
5+ use core:: ffi:: { CStr , c_char, c_double, c_int, c_long, c_longlong, c_ulong, c_ulonglong, c_void} ;
6+ use malachite_bigint:: { BigInt , Sign } ;
7+ use rustpython_vm:: builtins:: { PyInt , try_bigint_to_f64, try_f64_to_bigint} ;
8+ use rustpython_vm:: common:: int:: bytes_to_int;
9+ use rustpython_vm:: protocol:: handle_bytes_to_int_err;
10+ use rustpython_vm:: { AsObject , PyResult , VirtualMachine } ;
711
812define_py_check ! ( fn PyLong_Check , types. int_type) ;
913define_py_check ! ( exact fn PyLong_CheckExact , types. int_type) ;
@@ -38,6 +42,150 @@ pub extern "C" fn PyLong_FromUnsignedLongLong(value: c_ulonglong) -> *mut PyObje
3842 with_vm ( |vm| vm. ctx . new_int ( value) )
3943}
4044
45+ #[ unsafe( no_mangle) ]
46+ pub extern "C" fn PyLong_FromDouble ( value : c_double ) -> * mut PyObject {
47+ with_vm ( |vm| Ok ( vm. ctx . new_bigint ( & try_f64_to_bigint ( value, vm) ?) ) )
48+ }
49+
50+ #[ unsafe( no_mangle) ]
51+ pub extern "C" fn PyLong_FromInt32 ( value : i32 ) -> * mut PyObject {
52+ with_vm ( |vm| vm. ctx . new_int ( value) )
53+ }
54+
55+ #[ unsafe( no_mangle) ]
56+ pub extern "C" fn PyLong_FromInt64 ( value : i64 ) -> * mut PyObject {
57+ with_vm ( |vm| vm. ctx . new_int ( value) )
58+ }
59+
60+ #[ unsafe( no_mangle) ]
61+ pub extern "C" fn PyLong_FromUInt32 ( value : u32 ) -> * mut PyObject {
62+ with_vm ( |vm| vm. ctx . new_int ( value) )
63+ }
64+
65+ #[ unsafe( no_mangle) ]
66+ pub extern "C" fn PyLong_FromUInt64 ( value : u64 ) -> * mut PyObject {
67+ with_vm ( |vm| vm. ctx . new_int ( value) )
68+ }
69+
70+ bitflags ! {
71+ #[ derive( Clone , Copy ) ]
72+ struct AsNativeBytesFlags : c_int {
73+ const BIG_ENDIAN = 0 ;
74+ const LITTLE_ENDIAN = 1 ;
75+ const NATIVE_ENDIAN = 3 ;
76+ const UNSIGNED_BUFFER = 4 ;
77+ const REJECT_NEGATIVE = 8 ;
78+ const ALLOW_INDEX = 16 ;
79+ }
80+ }
81+
82+ impl AsNativeBytesFlags {
83+ #[ inline]
84+ fn is_little_endian ( self ) -> bool {
85+ if self . contains ( Self :: NATIVE_ENDIAN ) {
86+ cfg ! ( target_endian = "little" )
87+ } else {
88+ self . contains ( Self :: LITTLE_ENDIAN )
89+ }
90+ }
91+
92+ fn from_bits_or_default ( vm : & VirtualMachine , raw_flags : c_int ) -> PyResult < Self > {
93+ const PY_ASNATIVEBYTES_DEFAULTS : c_int = -1 ;
94+ if raw_flags == PY_ASNATIVEBYTES_DEFAULTS {
95+ return Ok ( Self :: default ( ) ) ;
96+ } ;
97+
98+ let flags = Self :: from_bits ( raw_flags)
99+ . ok_or_else ( || vm. new_value_error ( "Invalid NativeBytes flags" ) ) ?;
100+ if flags. contains ( Self :: LITTLE_ENDIAN ) & flags. contains ( Self :: NATIVE_ENDIAN ) {
101+ Err ( vm. new_value_error ( "Cannot specify both LITTLE_ENDIAN and NATIVE_ENDIAN" ) )
102+ } else {
103+ Ok ( flags)
104+ }
105+ }
106+ }
107+
108+ impl Default for AsNativeBytesFlags {
109+ fn default ( ) -> Self {
110+ Self :: NATIVE_ENDIAN | Self :: UNSIGNED_BUFFER
111+ }
112+ }
113+
114+ #[ unsafe( no_mangle) ]
115+ pub unsafe extern "C" fn PyLong_FromNativeBytes (
116+ buffer : * const c_void ,
117+ n_bytes : usize ,
118+ flags : c_int ,
119+ ) -> * mut PyObject {
120+ with_vm ( |vm| {
121+ let flags = AsNativeBytesFlags :: from_bits_or_default ( vm, flags) ?;
122+ let little_endian = flags. is_little_endian ( ) ;
123+ let bytes = unsafe { core:: slice:: from_raw_parts ( buffer. cast :: < u8 > ( ) , n_bytes) } ;
124+
125+ let value = if flags. contains ( AsNativeBytesFlags :: UNSIGNED_BUFFER ) {
126+ if little_endian {
127+ BigInt :: from_bytes_le ( Sign :: Plus , bytes)
128+ } else {
129+ BigInt :: from_bytes_be ( Sign :: Plus , bytes)
130+ }
131+ } else if little_endian {
132+ BigInt :: from_signed_bytes_le ( bytes)
133+ } else {
134+ BigInt :: from_signed_bytes_be ( bytes)
135+ } ;
136+
137+ Ok ( vm. ctx . new_bigint ( & value) )
138+ } )
139+ }
140+
141+ #[ unsafe( no_mangle) ]
142+ pub unsafe extern "C" fn PyLong_FromUnsignedNativeBytes (
143+ buffer : * const c_void ,
144+ n_bytes : usize ,
145+ flags : c_int ,
146+ ) -> * mut PyObject {
147+ with_vm ( |vm| {
148+ let flags = AsNativeBytesFlags :: from_bits_or_default ( vm, flags) ?;
149+ let bytes = unsafe { core:: slice:: from_raw_parts ( buffer. cast :: < u8 > ( ) , n_bytes) } ;
150+
151+ let value = if flags. is_little_endian ( ) {
152+ BigInt :: from_bytes_le ( Sign :: Plus , bytes)
153+ } else {
154+ BigInt :: from_bytes_be ( Sign :: Plus , bytes)
155+ } ;
156+
157+ Ok ( vm. ctx . new_bigint ( & value) )
158+ } )
159+ }
160+
161+ #[ unsafe( no_mangle) ]
162+ pub extern "C" fn PyLong_FromVoidPtr ( ptr : * mut c_void ) -> * mut PyObject {
163+ with_vm ( |vm| vm. ctx . new_int ( ptr as usize ) )
164+ }
165+
166+ #[ unsafe( no_mangle) ]
167+ pub unsafe extern "C" fn PyLong_FromString (
168+ str : * const c_char ,
169+ pend : * mut * mut c_char ,
170+ base : c_int ,
171+ ) -> * mut PyObject {
172+ with_vm ( |vm| {
173+ let bytes = unsafe { CStr :: from_ptr ( str) } . to_bytes ( ) ;
174+ let parsed = bytes_to_int ( bytes, base as u32 , vm. state . int_max_str_digits . load ( ) )
175+ . map ( |value| vm. ctx . new_bigint ( & value) ) ;
176+
177+ if let Some ( pend) = unsafe { pend. as_mut ( ) } {
178+ let end_offset = if parsed. is_ok ( ) { bytes. len ( ) } else { 0 } ;
179+ unsafe { * pend = bytes. as_ptr ( ) . add ( end_offset) . cast_mut ( ) . cast ( ) } ;
180+ }
181+
182+ parsed. map_err ( |err| {
183+ let obj = vm. ctx . new_bytes ( bytes. to_vec ( ) ) ;
184+ handle_bytes_to_int_err ( err, obj. as_object ( ) , vm)
185+ } )
186+ } )
187+ }
188+
41189#[ unsafe( no_mangle) ]
42190pub unsafe extern "C" fn PyLong_AsLong ( obj : * mut PyObject ) -> c_long {
43191 with_vm :: < PyResult < c_long > , _ > ( |vm| {
@@ -50,12 +198,173 @@ pub unsafe extern "C" fn PyLong_AsLong(obj: *mut PyObject) -> c_long {
50198 } )
51199}
52200
201+ #[ unsafe( no_mangle) ]
202+ pub unsafe extern "C" fn PyLong_AsDouble ( obj : * mut PyObject ) -> c_double {
203+ with_vm :: < PyResult < c_double > , _ > ( |vm| {
204+ let int = unsafe { & * obj } . try_downcast_ref :: < PyInt > ( vm) ?;
205+ try_bigint_to_f64 ( int. as_bigint ( ) , vm)
206+ } )
207+ }
208+
209+ #[ unsafe( no_mangle) ]
210+ pub unsafe extern "C" fn PyLong_AsInt ( obj : * mut PyObject ) -> c_int {
211+ with_vm :: < PyResult < c_int > , _ > ( |vm| {
212+ unsafe { & * obj }
213+ . to_owned ( )
214+ . try_index ( vm) ?
215+ . as_bigint ( )
216+ . try_into ( )
217+ . map_err ( |_| vm. new_overflow_error ( "Python int too large to convert to C int" ) )
218+ } )
219+ }
220+
221+ #[ unsafe( no_mangle) ]
222+ pub unsafe extern "C" fn PyLong_AsInt32 ( obj : * mut PyObject , out : * mut i32 ) -> c_int {
223+ with_vm ( |vm| {
224+ let value: i32 = unsafe { & * obj }
225+ . to_owned ( )
226+ . try_index ( vm) ?
227+ . as_bigint ( )
228+ . try_into ( )
229+ . map_err ( |_| vm. new_overflow_error ( "Python int too large to convert to int32_t" ) ) ?;
230+ unsafe { * out = value } ;
231+ Ok ( ( ) )
232+ } )
233+ }
234+
235+ #[ unsafe( no_mangle) ]
236+ pub unsafe extern "C" fn PyLong_AsInt64 ( obj : * mut PyObject , out : * mut i64 ) -> c_int {
237+ with_vm ( |vm| {
238+ let value: i64 = unsafe { & * obj }
239+ . to_owned ( )
240+ . try_index ( vm) ?
241+ . as_bigint ( )
242+ . try_into ( )
243+ . map_err ( |_| vm. new_overflow_error ( "Python int too large to convert to int64_t" ) ) ?;
244+ unsafe { * out = value } ;
245+ Ok ( ( ) )
246+ } )
247+ }
248+
249+ #[ unsafe( no_mangle) ]
250+ pub unsafe extern "C" fn PyLong_AsLongLong ( obj : * mut PyObject ) -> c_longlong {
251+ with_vm :: < PyResult < c_longlong > , _ > ( |vm| {
252+ unsafe { & * obj }
253+ . to_owned ( )
254+ . try_index ( vm) ?
255+ . as_bigint ( )
256+ . try_into ( )
257+ . map_err ( |_| vm. new_overflow_error ( "Python int too large to convert to C long long" ) )
258+ } )
259+ }
260+
261+ #[ unsafe( no_mangle) ]
262+ pub unsafe extern "C" fn PyLong_AsSize_t ( obj : * mut PyObject ) -> usize {
263+ with_vm :: < PyResult < usize > , _ > ( |vm| {
264+ let value: usize = unsafe { & * obj }
265+ . try_downcast_ref :: < PyInt > ( vm) ?
266+ . as_bigint ( )
267+ . try_into ( )
268+ . map_err ( |_| vm. new_overflow_error ( "Python int too large to convert to C size_t" ) ) ?;
269+ Ok ( value)
270+ } )
271+ }
272+
273+ #[ unsafe( no_mangle) ]
274+ pub unsafe extern "C" fn PyLong_AsSsize_t ( obj : * mut PyObject ) -> isize {
275+ with_vm :: < PyResult < isize > , _ > ( |vm| {
276+ unsafe { & * obj }
277+ . try_downcast_ref :: < PyInt > ( vm) ?
278+ . as_bigint ( )
279+ . try_into ( )
280+ . map_err ( |_| vm. new_overflow_error ( "Python int too large to convert to C ssize_t" ) )
281+ } )
282+ }
283+
284+ #[ unsafe( no_mangle) ]
285+ pub unsafe extern "C" fn PyLong_AsUInt32 ( obj : * mut PyObject , out : * mut u32 ) -> c_int {
286+ with_vm ( |vm| {
287+ let value: u32 = unsafe { & * obj }
288+ . to_owned ( )
289+ . try_index ( vm) ?
290+ . as_bigint ( )
291+ . try_into ( )
292+ . map_err ( |_| vm. new_overflow_error ( "Python int too large to convert to uint32_t" ) ) ?;
293+ unsafe { * out = value } ;
294+ Ok ( ( ) )
295+ } )
296+ }
297+
298+ #[ unsafe( no_mangle) ]
299+ pub unsafe extern "C" fn PyLong_AsUInt64 ( obj : * mut PyObject , out : * mut u64 ) -> c_int {
300+ with_vm ( |vm| {
301+ let value: u64 = unsafe { & * obj }
302+ . to_owned ( )
303+ . try_index ( vm) ?
304+ . as_bigint ( )
305+ . try_into ( )
306+ . map_err ( |_| vm. new_overflow_error ( "Python int too large to convert to uint64_t" ) ) ?;
307+ unsafe { * out = value } ;
308+ Ok ( ( ) )
309+ } )
310+ }
311+
312+ #[ unsafe( no_mangle) ]
313+ pub unsafe extern "C" fn PyLong_AsUnsignedLong ( obj : * mut PyObject ) -> c_ulong {
314+ with_vm :: < PyResult < c_ulong > , _ > ( |vm| {
315+ unsafe { & * obj }
316+ . try_downcast_ref :: < PyInt > ( vm) ?
317+ . as_bigint ( )
318+ . try_into ( )
319+ . map_err ( |_| {
320+ vm. new_overflow_error ( "Python int too large to convert to C unsigned long" )
321+ } )
322+ } )
323+ }
324+
325+ #[ unsafe( no_mangle) ]
326+ pub unsafe extern "C" fn PyLong_AsUnsignedLongMask ( obj : * mut PyObject ) -> c_ulong {
327+ with_vm :: < PyResult < c_ulong > , _ > ( |vm| {
328+ let int = unsafe { & * obj } . to_owned ( ) . try_index ( vm) ?;
329+ if const { c_ulong:: BITS == 32 } {
330+ Ok ( c_ulong:: from ( int. as_u32_mask ( ) ) )
331+ } else {
332+ Ok ( int. as_u64_mask ( ) as c_ulong )
333+ }
334+ } )
335+ }
336+
337+ #[ unsafe( no_mangle) ]
338+ pub unsafe extern "C" fn PyLong_AsUnsignedLongLongMask ( obj : * mut PyObject ) -> c_ulonglong {
339+ with_vm :: < PyResult < c_ulonglong > , _ > ( |vm| {
340+ let int = unsafe { & * obj } . to_owned ( ) . try_index ( vm) ?;
341+ Ok ( int. as_u64_mask ( ) )
342+ } )
343+ }
344+
345+ #[ unsafe( no_mangle) ]
346+ pub unsafe extern "C" fn PyLong_AsVoidPtr ( obj : * mut PyObject ) -> * mut c_void {
347+ with_vm ( |vm| {
348+ let value = unsafe { & * obj } . try_downcast_ref :: < PyInt > ( vm) ?;
349+
350+ let unsigned: Result < usize , _ > = value. as_bigint ( ) . try_into ( ) ;
351+ if let Ok ( v) = unsigned {
352+ return Ok ( v as * mut c_void ) ;
353+ }
354+ let signed: Result < isize , _ > = value. as_bigint ( ) . try_into ( ) ;
355+ if let Ok ( v) = signed {
356+ return Ok ( ( v as usize ) as * mut c_void ) ;
357+ }
358+
359+ Err ( vm. new_overflow_error ( "int too large to convert to pointer" ) )
360+ } )
361+ }
362+
53363#[ unsafe( no_mangle) ]
54364pub unsafe extern "C" fn PyLong_AsUnsignedLongLong ( obj : * mut PyObject ) -> c_ulonglong {
55365 with_vm :: < PyResult < c_ulonglong > , _ > ( |vm| {
56366 unsafe { & * obj }
57- . to_owned ( )
58- . try_downcast :: < PyInt > ( vm) ?
367+ . try_downcast_ref :: < PyInt > ( vm) ?
59368 . as_bigint ( )
60369 . try_into ( )
61370 . map_err ( |_| {
@@ -86,4 +395,13 @@ mod tests {
86395 assert_eq ! ( number. extract:: <u64 >( ) . unwrap( ) , 123 ) ;
87396 } )
88397 }
398+
399+ #[ test]
400+ fn py_int_u128 ( ) {
401+ Python :: attach ( |py| {
402+ let value = 1u128 << 100 ;
403+ let number = PyInt :: new ( py, value) ;
404+ assert_eq ! ( number. extract:: <u128 >( ) . unwrap( ) , value) ;
405+ } )
406+ }
89407}
0 commit comments