Skip to content

Commit 79ac3ca

Browse files
committed
implement more of the concrete object layer
1 parent c2d7732 commit 79ac3ca

File tree

8 files changed

+234
-8
lines changed

8 files changed

+234
-8
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

capi/Cargo.toml

+14-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,20 @@ crate-type = ["cdylib"]
1515

1616
[dependencies]
1717
malachite-bigint = { workspace = true }
18+
num-complex = { workspace = true }
19+
1820
rustpython-common = { workspace = true }
1921
rustpython-vm = { workspace = true }
2022

21-
[lints]
22-
workspace = true
23+
[lints.rust]
24+
unsafe_code = "allow"
25+
unsafe_op_in_unsafe_fn = "deny"
26+
elided_lifetimes_in_paths = "warn"
27+
28+
[lints.clippy]
29+
perf = "warn"
30+
style = "warn"
31+
complexity = "warn"
32+
suspicious = "warn"
33+
correctness = "warn"
34+
missing_safety_doc = "allow"

capi/src/bool.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// https://docs.python.org/3/c-api/bool.html
2+
3+
use std::ffi;
4+
5+
use rustpython_vm::{PyObject, PyObjectRef};
6+
7+
// TODO: Everything else
8+
9+
#[unsafe(export_name = "PyBool_FromLong")]
10+
pub unsafe extern "C" fn bool_from_long(value: ffi::c_long) -> *mut PyObject {
11+
let vm = crate::get_vm();
12+
Into::<PyObjectRef>::into(vm.ctx.new_bool(value != 0))
13+
.into_raw()
14+
.as_ptr()
15+
}

capi/src/complex.rs

+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
// https://docs.python.org/3/c-api/complex.html
2+
3+
use std::ffi;
4+
5+
use rustpython_vm::{PyObject, PyObjectRef, builtins::PyComplex};
6+
7+
#[repr(C)]
8+
#[derive(Debug, Copy, Clone)]
9+
pub struct CPyComplex {
10+
pub real: ffi::c_double,
11+
pub imag: ffi::c_double,
12+
}
13+
14+
impl From<CPyComplex> for PyComplex {
15+
fn from(value: CPyComplex) -> Self {
16+
PyComplex::new(num_complex::Complex64::new(value.real, value.imag))
17+
}
18+
}
19+
20+
impl From<CPyComplex> for num_complex::Complex64 {
21+
fn from(value: CPyComplex) -> Self {
22+
num_complex::Complex64::new(value.real, value.imag)
23+
}
24+
}
25+
26+
impl From<PyComplex> for CPyComplex {
27+
fn from(value: PyComplex) -> Self {
28+
let complex = value.to_complex();
29+
CPyComplex {
30+
real: complex.re,
31+
imag: complex.im,
32+
}
33+
}
34+
}
35+
36+
impl From<num_complex::Complex64> for CPyComplex {
37+
fn from(value: num_complex::Complex64) -> Self {
38+
CPyComplex {
39+
real: value.re,
40+
imag: value.im,
41+
}
42+
}
43+
}
44+
45+
// Associated functions for CPyComplex
46+
// Always convert to PyComplex to do operations
47+
48+
#[unsafe(export_name = "_Py_c_sum")]
49+
pub unsafe extern "C" fn c_sum(a: *const CPyComplex, b: *const CPyComplex) -> CPyComplex {
50+
let a: PyComplex = unsafe { *a }.into();
51+
let b: PyComplex = unsafe { *b }.into();
52+
(a.to_complex() + b.to_complex()).into()
53+
}
54+
55+
#[unsafe(export_name = "_Py_c_diff")]
56+
pub unsafe extern "C" fn c_diff(a: *const CPyComplex, b: *const CPyComplex) -> CPyComplex {
57+
let a: PyComplex = unsafe { *a }.into();
58+
let b: PyComplex = unsafe { *b }.into();
59+
(a.to_complex() - b.to_complex()).into()
60+
}
61+
62+
#[unsafe(export_name = "_Py_c_neg")]
63+
pub unsafe extern "C" fn c_neg(a: *const CPyComplex) -> CPyComplex {
64+
let a: PyComplex = unsafe { *a }.into();
65+
(-a.to_complex()).into()
66+
}
67+
68+
#[unsafe(export_name = "_Py_c_prod")]
69+
pub unsafe extern "C" fn c_prod(a: *const CPyComplex, b: *const CPyComplex) -> CPyComplex {
70+
let a: PyComplex = unsafe { *a }.into();
71+
let b: PyComplex = unsafe { *b }.into();
72+
(a.to_complex() * b.to_complex()).into()
73+
}
74+
75+
#[unsafe(export_name = "_Py_c_quot")]
76+
pub unsafe extern "C" fn c_quot(a: *const CPyComplex, b: *const CPyComplex) -> CPyComplex {
77+
let a: PyComplex = unsafe { *a }.into();
78+
let b: PyComplex = unsafe { *b }.into();
79+
(a.to_complex() / b.to_complex()).into()
80+
}
81+
82+
#[unsafe(export_name = "_Py_c_pow")]
83+
pub unsafe extern "C" fn c_pow(a: *const CPyComplex, b: *const CPyComplex) -> CPyComplex {
84+
let a: PyComplex = unsafe { *a }.into();
85+
let b: PyComplex = unsafe { *b }.into();
86+
(a.to_complex() * b.to_complex()).into()
87+
}
88+
89+
#[unsafe(export_name = "PyComplex_FromCComplex")]
90+
pub unsafe extern "C" fn complex_from_ccomplex(value: CPyComplex) -> *mut PyObject {
91+
let vm = crate::get_vm();
92+
Into::<PyObjectRef>::into(vm.ctx.new_complex(value.into()))
93+
.into_raw()
94+
.as_ptr()
95+
}
96+
97+
#[unsafe(export_name = "PyComplex_FromDoubles")]
98+
pub unsafe extern "C" fn complex_from_doubles(
99+
real: ffi::c_double,
100+
imag: ffi::c_double,
101+
) -> *mut PyObject {
102+
let vm = crate::get_vm();
103+
Into::<PyObjectRef>::into(vm.ctx.new_complex(num_complex::Complex64::new(real, imag)))
104+
.into_raw()
105+
.as_ptr()
106+
}
107+
108+
#[unsafe(export_name = "PyComplex_RealAsDouble")]
109+
pub unsafe extern "C" fn complex_real_as_double(value: *mut PyObject) -> ffi::c_double {
110+
let vm = crate::get_vm();
111+
let value = crate::cast_obj_ptr(value).unwrap();
112+
let (complex, _) = value.try_complex(&vm).unwrap().unwrap();
113+
complex.re
114+
}
115+
116+
#[unsafe(export_name = "PyComplex_ImagAsDouble")]
117+
pub unsafe extern "C" fn complex_imag_as_double(value: *mut PyObject) -> ffi::c_double {
118+
let vm = crate::get_vm();
119+
let value = crate::cast_obj_ptr(value).unwrap();
120+
let (complex, _) = value.try_complex(&vm).unwrap().unwrap();
121+
complex.im
122+
}
123+
124+
#[unsafe(export_name = "PyComplex_AsCComplex")]
125+
pub unsafe extern "C" fn complex_as_ccomplex(value: *mut PyObject) -> CPyComplex {
126+
let vm = crate::get_vm();
127+
let value = crate::cast_obj_ptr(value).unwrap();
128+
let (complex, _) = value.try_complex(&vm).unwrap().unwrap();
129+
complex.into()
130+
}

capi/src/float.rs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// https://docs.python.org/3/c-api/float.html
2+
3+
use std::ffi;
4+
5+
use rustpython_vm::{PyObject, PyObjectRef};
6+
7+
/// Returns null if the string is not a valid float.
8+
#[unsafe(export_name = "PyFloat_FromString")]
9+
pub unsafe extern "C" fn float_from_string(value: *const ffi::c_char) -> *mut PyObject {
10+
let vm = crate::get_vm();
11+
let value_str = unsafe { std::ffi::CStr::from_ptr(value).to_str().unwrap() };
12+
match value_str.parse::<f64>() {
13+
Ok(value) => Into::<PyObjectRef>::into(vm.ctx.new_float(value))
14+
.into_raw()
15+
.as_ptr(),
16+
Err(_) => std::ptr::null_mut(),
17+
}
18+
}
19+
20+
#[unsafe(export_name = "PyFloat_FromDouble")]
21+
pub unsafe extern "C" fn float_from_double(value: ffi::c_double) -> *mut PyObject {
22+
let vm = crate::get_vm();
23+
Into::<PyObjectRef>::into(vm.ctx.new_float(value))
24+
.into_raw()
25+
.as_ptr()
26+
}

capi/src/int.rs

+33-2
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,47 @@
1+
// https://docs.python.org/3/c-api/long.html
2+
3+
use std::ffi;
4+
15
use rustpython_vm::{PyObject, PyObjectRef};
26

37
#[unsafe(export_name = "PyLong_FromLong")]
4-
pub unsafe extern "C" fn long_from_long(value: i64) -> *mut PyObject {
8+
pub unsafe extern "C" fn long_from_long(value: ffi::c_long) -> *mut PyObject {
59
let vm = crate::get_vm();
610
Into::<PyObjectRef>::into(vm.ctx.new_int(value))
711
.into_raw()
812
.as_ptr()
913
}
1014

1115
#[unsafe(export_name = "PyLong_FromUnsignedLong")]
12-
pub unsafe extern "C" fn long_from_unsigned_long(value: u64) -> *mut PyObject {
16+
pub unsafe extern "C" fn long_from_unsigned_long(value: ffi::c_ulong) -> *mut PyObject {
17+
let vm = crate::get_vm();
18+
Into::<PyObjectRef>::into(vm.ctx.new_int(value))
19+
.into_raw()
20+
.as_ptr()
21+
}
22+
23+
// TODO: PyLong_FromSsize_t
24+
// TODO: PyLong_FromSize_t
25+
#[unsafe(export_name = "PyLong_FromLongLong")]
26+
pub unsafe extern "C" fn long_from_long_long(value: ffi::c_longlong) -> *mut PyObject {
27+
let vm = crate::get_vm();
28+
Into::<PyObjectRef>::into(vm.ctx.new_int(value))
29+
.into_raw()
30+
.as_ptr()
31+
}
32+
33+
#[unsafe(export_name = "PyLong_FromUnsignedLongLong")]
34+
pub unsafe extern "C" fn long_from_unsigned_long_long(value: ffi::c_ulonglong) -> *mut PyObject {
35+
let vm = crate::get_vm();
36+
Into::<PyObjectRef>::into(vm.ctx.new_int(value))
37+
.into_raw()
38+
.as_ptr()
39+
}
40+
41+
#[unsafe(export_name = "PyLong_FromDouble")]
42+
pub unsafe extern "C" fn long_from_double(value: ffi::c_double) -> *mut PyObject {
1343
let vm = crate::get_vm();
44+
let value = value as i64;
1445
Into::<PyObjectRef>::into(vm.ctx.new_int(value))
1546
.into_raw()
1647
.as_ptr()

capi/src/lib.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
use std::{cell::RefCell, ffi, sync::Arc};
22

3-
use rustpython_vm as vm;
3+
use rustpython_vm::{self as vm, PyObject, PyObjectRef};
44

5-
mod error;
6-
mod int;
7-
mod tuple;
5+
pub mod bool;
6+
pub mod complex;
7+
pub mod error;
8+
pub mod float;
9+
pub mod int;
10+
pub mod tuple;
811

912
thread_local! {
1013
pub static VM: RefCell<Option<Arc<vm::VirtualMachine>>> = const { RefCell::new(None) };
@@ -14,6 +17,10 @@ fn get_vm() -> Arc<vm::VirtualMachine> {
1417
VM.with(|vm| vm.borrow().as_ref().unwrap().clone())
1518
}
1619

20+
fn cast_obj_ptr(obj: *mut PyObject) -> Option<PyObjectRef> {
21+
Some(unsafe { PyObjectRef::from_raw(std::ptr::NonNull::new(obj)?) })
22+
}
23+
1724
#[repr(C)]
1825
pub enum PyStatusType {
1926
PyStatusTypeOk = 0,

vm/src/builtins/complex.rs

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ pub struct PyComplex {
2828
}
2929

3030
impl PyComplex {
31+
pub fn new(value: Complex64) -> Self {
32+
PyComplex { value }
33+
}
34+
3135
pub fn to_complex64(self) -> Complex64 {
3236
self.value
3337
}

0 commit comments

Comments
 (0)