GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Add more int functions to the c-api · RustPython/RustPython@2a94827

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • crates
    • capi/src
      • longobject.rs
      • util.rs
    • vm/src/builtins
      • int.rs
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎crates/capi/src/longobject.rs‎

Copy file name to clipboardExpand all lines: crates/capi/src/longobject.rs
+230-5Lines changed: 230 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
use crate::PyObject;
22
use crate::object::define_py_check;
33
use 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 core::ffi::{CStr, c_char, c_double, c_int, c_long, c_longlong, c_ulong, c_ulonglong, c_void};
5+
use rustpython_vm::builtins::{PyInt, try_bigint_to_f64, try_f64_to_bigint};
6+
use rustpython_vm::common::int::bytes_to_int;
7+
use rustpython_vm::protocol::handle_bytes_to_int_err;
8+
use rustpython_vm::{AsObject, PyResult};
79

810
define_py_check!(fn PyLong_Check, types.int_type);
911
define_py_check!(exact fn PyLong_CheckExact, types.int_type);
@@ -38,6 +40,59 @@ pub extern "C" fn PyLong_FromUnsignedLongLong(value: c_ulonglong) -> *mut PyObje
3840
with_vm(|vm| vm.ctx.new_int(value))
3941
}
4042

43+
#[unsafe(no_mangle)]
44+
pub extern "C" fn PyLong_FromDouble(value: c_double) -> *mut PyObject {
45+
with_vm(|vm| Ok(vm.ctx.new_bigint(&try_f64_to_bigint(value, vm)?)))
46+
}
47+
48+
#[unsafe(no_mangle)]
49+
pub extern "C" fn PyLong_FromInt32(value: i32) -> *mut PyObject {
50+
with_vm(|vm| vm.ctx.new_int(value))
51+
}
52+
53+
#[unsafe(no_mangle)]
54+
pub extern "C" fn PyLong_FromInt64(value: i64) -> *mut PyObject {
55+
with_vm(|vm| vm.ctx.new_int(value))
56+
}
57+
58+
#[unsafe(no_mangle)]
59+
pub extern "C" fn PyLong_FromUInt32(value: u32) -> *mut PyObject {
60+
with_vm(|vm| vm.ctx.new_int(value))
61+
}
62+
63+
#[unsafe(no_mangle)]
64+
pub extern "C" fn PyLong_FromUInt64(value: u64) -> *mut PyObject {
65+
with_vm(|vm| vm.ctx.new_int(value))
66+
}
67+
68+
#[unsafe(no_mangle)]
69+
pub extern "C" fn PyLong_FromVoidPtr(ptr: *mut c_void) -> *mut PyObject {
70+
with_vm(|vm| vm.ctx.new_int(ptr as usize))
71+
}
72+
73+
#[unsafe(no_mangle)]
74+
pub unsafe extern "C" fn PyLong_FromString(
75+
str: *const c_char,
76+
pend: *mut *mut c_char,
77+
base: c_int,
78+
) -> *mut PyObject {
79+
with_vm(|vm| {
80+
let bytes = unsafe { CStr::from_ptr(str) }.to_bytes();
81+
let parsed = bytes_to_int(bytes, base as u32, vm.state.int_max_str_digits.load())
82+
.map(|value| vm.ctx.new_bigint(&value));
83+
84+
if let Some(pend) = unsafe { pend.as_mut() } {
85+
let end_offset = if parsed.is_ok() { bytes.len() } else { 0 };
86+
unsafe { *pend = bytes.as_ptr().add(end_offset).cast_mut().cast() };
87+
}
88+
89+
parsed.map_err(|err| {
90+
let obj = vm.ctx.new_bytes(bytes.to_vec());
91+
handle_bytes_to_int_err(err, obj.as_object(), vm)
92+
})
93+
})
94+
}
95+
4196
#[unsafe(no_mangle)]
4297
pub unsafe extern "C" fn PyLong_AsLong(obj: *mut PyObject) -> c_long {
4398
with_vm::<PyResult<c_long>, _>(|vm| {
@@ -50,12 +105,173 @@ pub unsafe extern "C" fn PyLong_AsLong(obj: *mut PyObject) -> c_long {
50105
})
51106
}
52107

108+
#[unsafe(no_mangle)]
109+
pub unsafe extern "C" fn PyLong_AsDouble(obj: *mut PyObject) -> c_double {
110+
with_vm::<PyResult<c_double>, _>(|vm| {
111+
let int = unsafe { &*obj }.try_downcast_ref::<PyInt>(vm)?;
112+
try_bigint_to_f64(int.as_bigint(), vm)
113+
})
114+
}
115+
116+
#[unsafe(no_mangle)]
117+
pub unsafe extern "C" fn PyLong_AsInt(obj: *mut PyObject) -> c_int {
118+
with_vm::<PyResult<c_int>, _>(|vm| {
119+
unsafe { &*obj }
120+
.to_owned()
121+
.try_index(vm)?
122+
.as_bigint()
123+
.try_into()
124+
.map_err(|_| vm.new_overflow_error("Python int too large to convert to C int"))
125+
})
126+
}
127+
128+
#[unsafe(no_mangle)]
129+
pub unsafe extern "C" fn PyLong_AsInt32(obj: *mut PyObject, out: *mut i32) -> c_int {
130+
with_vm(|vm| {
131+
let value: i32 = unsafe { &*obj }
132+
.to_owned()
133+
.try_index(vm)?
134+
.as_bigint()
135+
.try_into()
136+
.map_err(|_| vm.new_overflow_error("Python int too large to convert to int32_t"))?;
137+
unsafe { *out = value };
138+
Ok(())
139+
})
140+
}
141+
142+
#[unsafe(no_mangle)]
143+
pub unsafe extern "C" fn PyLong_AsInt64(obj: *mut PyObject, out: *mut i64) -> c_int {
144+
with_vm(|vm| {
145+
let value: i64 = unsafe { &*obj }
146+
.to_owned()
147+
.try_index(vm)?
148+
.as_bigint()
149+
.try_into()
150+
.map_err(|_| vm.new_overflow_error("Python int too large to convert to int64_t"))?;
151+
unsafe { *out = value };
152+
Ok(())
153+
})
154+
}
155+
156+
#[unsafe(no_mangle)]
157+
pub unsafe extern "C" fn PyLong_AsLongLong(obj: *mut PyObject) -> c_longlong {
158+
with_vm::<PyResult<c_longlong>, _>(|vm| {
159+
unsafe { &*obj }
160+
.to_owned()
161+
.try_index(vm)?
162+
.as_bigint()
163+
.try_into()
164+
.map_err(|_| vm.new_overflow_error("Python int too large to convert to C long long"))
165+
})
166+
}
167+
168+
#[unsafe(no_mangle)]
169+
pub unsafe extern "C" fn PyLong_AsSize_t(obj: *mut PyObject) -> usize {
170+
with_vm::<PyResult<usize>, _>(|vm| {
171+
let value: usize = unsafe { &*obj }
172+
.try_downcast_ref::<PyInt>(vm)?
173+
.as_bigint()
174+
.try_into()
175+
.map_err(|_| vm.new_overflow_error("Python int too large to convert to C size_t"))?;
176+
Ok(value)
177+
})
178+
}
179+
180+
#[unsafe(no_mangle)]
181+
pub unsafe extern "C" fn PyLong_AsSsize_t(obj: *mut PyObject) -> isize {
182+
with_vm::<PyResult<isize>, _>(|vm| {
183+
unsafe { &*obj }
184+
.try_downcast_ref::<PyInt>(vm)?
185+
.as_bigint()
186+
.try_into()
187+
.map_err(|_| vm.new_overflow_error("Python int too large to convert to C ssize_t"))
188+
})
189+
}
190+
191+
#[unsafe(no_mangle)]
192+
pub unsafe extern "C" fn PyLong_AsUInt32(obj: *mut PyObject, out: *mut u32) -> c_int {
193+
with_vm(|vm| {
194+
let value: u32 = unsafe { &*obj }
195+
.to_owned()
196+
.try_index(vm)?
197+
.as_bigint()
198+
.try_into()
199+
.map_err(|_| vm.new_overflow_error("Python int too large to convert to uint32_t"))?;
200+
unsafe { *out = value };
201+
Ok(())
202+
})
203+
}
204+
205+
#[unsafe(no_mangle)]
206+
pub unsafe extern "C" fn PyLong_AsUInt64(obj: *mut PyObject, out: *mut u64) -> c_int {
207+
with_vm(|vm| {
208+
let value: u64 = unsafe { &*obj }
209+
.to_owned()
210+
.try_index(vm)?
211+
.as_bigint()
212+
.try_into()
213+
.map_err(|_| vm.new_overflow_error("Python int too large to convert to uint64_t"))?;
214+
unsafe { *out = value };
215+
Ok(())
216+
})
217+
}
218+
219+
#[unsafe(no_mangle)]
220+
pub unsafe extern "C" fn PyLong_AsUnsignedLong(obj: *mut PyObject) -> c_ulong {
221+
with_vm::<PyResult<c_ulong>, _>(|vm| {
222+
unsafe { &*obj }
223+
.try_downcast_ref::<PyInt>(vm)?
224+
.as_bigint()
225+
.try_into()
226+
.map_err(|_| {
227+
vm.new_overflow_error("Python int too large to convert to C unsigned long")
228+
})
229+
})
230+
}
231+
232+
#[unsafe(no_mangle)]
233+
pub unsafe extern "C" fn PyLong_AsUnsignedLongMask(obj: *mut PyObject) -> c_ulong {
234+
with_vm::<PyResult<c_ulong>, _>(|vm| {
235+
let int = unsafe { &*obj }.to_owned().try_index(vm)?;
236+
if const { c_ulong::BITS == 32 } {
237+
Ok(c_ulong::from(int.as_u32_mask()))
238+
} else {
239+
Ok(int.as_u64_mask() as c_ulong)
240+
}
241+
})
242+
}
243+
244+
#[unsafe(no_mangle)]
245+
pub unsafe extern "C" fn PyLong_AsUnsignedLongLongMask(obj: *mut PyObject) -> c_ulonglong {
246+
with_vm::<PyResult<c_ulonglong>, _>(|vm| {
247+
let int = unsafe { &*obj }.to_owned().try_index(vm)?;
248+
Ok(int.as_u64_mask())
249+
})
250+
}
251+
252+
#[unsafe(no_mangle)]
253+
pub unsafe extern "C" fn PyLong_AsVoidPtr(obj: *mut PyObject) -> *mut c_void {
254+
with_vm(|vm| {
255+
let value = unsafe { &*obj }.try_downcast_ref::<PyInt>(vm)?;
256+
257+
let unsigned: Result<usize, _> = value.as_bigint().try_into();
258+
if let Ok(v) = unsigned {
259+
return Ok(v as *mut c_void);
260+
}
261+
let signed: Result<isize, _> = value.as_bigint().try_into();
262+
if let Ok(v) = signed {
263+
return Ok((v as usize) as *mut c_void);
264+
}
265+
266+
Err(vm.new_overflow_error("int too large to convert to pointer"))
267+
})
268+
}
269+
53270
#[unsafe(no_mangle)]
54271
pub unsafe extern "C" fn PyLong_AsUnsignedLongLong(obj: *mut PyObject) -> c_ulonglong {
55272
with_vm::<PyResult<c_ulonglong>, _>(|vm| {
56273
unsafe { &*obj }
57-
.to_owned()
58-
.try_downcast::<PyInt>(vm)?
274+
.try_downcast_ref::<PyInt>(vm)?
59275
.as_bigint()
60276
.try_into()
61277
.map_err(|_| {
@@ -86,4 +302,13 @@ mod tests {
86302
assert_eq!(number.extract::<u64>().unwrap(), 123);
87303
})
88304
}
305+
306+
#[test]
307+
fn py_int_u128() {
308+
Python::attach(|py| {
309+
let value = 1u128 << 100;
310+
let number = PyInt::new(py, value);
311+
assert_eq!(number.extract::<u128>().unwrap(), value);
312+
})
313+
}
89314
}
Collapse file

‎crates/capi/src/util.rs‎

Copy file name to clipboardExpand all lines: crates/capi/src/util.rs
+81-2Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::PyObject;
22
use core::convert::Infallible;
3-
use core::ffi::{c_char, c_double, c_int, c_long, c_ulonglong, c_void};
3+
use core::ffi::{c_char, c_double, c_int, c_long, c_ulong, c_void};
44
use rustpython_vm::{PyObjectRef, PyRef, PyResult, VirtualMachine};
55

66
pub(crate) trait FfiResult<Output = Self> {
@@ -101,6 +101,31 @@ impl FfiResult<isize> for usize {
101101
}
102102
}
103103

104+
#[cfg(not(windows))]
105+
impl FfiResult for c_int {
106+
const ERR_VALUE: Self = -1;
107+
108+
fn into_output(self, _vm: &VirtualMachine) -> Self {
109+
self
110+
}
111+
}
112+
113+
impl FfiResult for usize {
114+
const ERR_VALUE: Self = Self::MAX;
115+
116+
fn into_output(self, _vm: &VirtualMachine) -> Self {
117+
self
118+
}
119+
}
120+
121+
impl FfiResult for isize {
122+
const ERR_VALUE: Self = -1;
123+
124+
fn into_output(self, _vm: &VirtualMachine) -> Self {
125+
self
126+
}
127+
}
128+
104129
impl FfiResult for c_long {
105130
const ERR_VALUE: Self = -1;
106131

@@ -109,7 +134,25 @@ impl FfiResult for c_long {
109134
}
110135
}
111136

112-
impl FfiResult for c_ulonglong {
137+
impl FfiResult for c_ulong {
138+
const ERR_VALUE: Self = Self::MAX;
139+
140+
fn into_output(self, _vm: &VirtualMachine) -> Self {
141+
self
142+
}
143+
}
144+
145+
#[cfg(windows)]
146+
impl FfiResult for core::ffi::c_longlong {
147+
const ERR_VALUE: Self = -1;
148+
149+
fn into_output(self, _vm: &VirtualMachine) -> Self {
150+
self
151+
}
152+
}
153+
154+
#[cfg(windows)]
155+
impl FfiResult for core::ffi::c_ulonglong {
113156
const ERR_VALUE: Self = Self::MAX;
114157

115158
fn into_output(self, _vm: &VirtualMachine) -> Self {
@@ -159,3 +202,39 @@ where
159202
)
160203
}
161204
}
205+
206+
#[cfg(test)]
207+
mod tests {
208+
use super::*;
209+
use core::any::type_name;
210+
use core::ffi::{c_longlong, c_ulonglong};
211+
use core::fmt::Debug;
212+
213+
#[test]
214+
fn ffi_result_err_value() {
215+
fn assert_error_value<T, Output>(value: Output)
216+
where
217+
T: FfiResult<Output> + 'static,
218+
Output: PartialEq + Debug,
219+
{
220+
assert_eq!(value, T::ERR_VALUE, "{}", type_name::<T>(),);
221+
}
222+
223+
assert_error_value::<(), _>(());
224+
assert_error_value::<(), c_int>(-1);
225+
226+
assert_error_value::<isize, _>(-1);
227+
assert_error_value::<usize, _>(usize::MAX);
228+
assert_error_value::<usize, isize>(-1);
229+
assert_error_value::<c_int, _>(-1); // i32
230+
assert_error_value::<c_long, _>(-1); //Windows i32, unix i64
231+
assert_error_value::<c_ulong, _>(c_ulong::MAX); // Windows u32, unix u64
232+
assert_error_value::<c_longlong, _>(-1); // i64
233+
assert_error_value::<c_ulonglong, _>(c_ulonglong::MAX); // u64
234+
assert_error_value::<c_double, _>(-1.0);
235+
assert_error_value::<bool, _>(-1);
236+
237+
assert_error_value::<PyResult<c_int>, _>(-1);
238+
assert_error_value::<PyResult<usize>, _>(usize::MAX);
239+
}
240+
}

0 commit comments

Comments
0 (0)
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.