Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 17 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions crates/capi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "rustpython-capi"
description = "Minimal CPython C-API compatibility exports for RustPython"
version.workspace = true
authors.workspace = true
edition.workspace = true
rust-version.workspace = true
repository.workspace = true
license.workspace = true

[lib]
crate-type = ["staticlib"]

[dependencies]
rustpython-vm = { workspace = true, features = ["threading"]}

[lints]
workspace = true
16 changes: 16 additions & 0 deletions crates/capi/src/bytesobject.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use core::ffi::c_char;
use core::ptr;

use crate::PyObject;

#[unsafe(no_mangle)]
pub extern "C" fn PyBytes_Size(_bytes: *mut PyObject) -> isize {
crate::log_stub("PyBytes_Size");
0
}

#[unsafe(no_mangle)]
pub extern "C" fn PyBytes_AsString(_bytes: *mut PyObject) -> *mut c_char {
crate::log_stub("PyBytes_AsString");
ptr::null_mut()
}
9 changes: 9 additions & 0 deletions crates/capi/src/import.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use core::ptr;

use crate::PyObject;

#[unsafe(no_mangle)]
pub extern "C" fn PyImport_Import(_name: *mut PyObject) -> *mut PyObject {
crate::log_stub("PyImport_Import");
ptr::null_mut()
}
20 changes: 20 additions & 0 deletions crates/capi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
pub use rustpython_vm::PyObject;

extern crate alloc;

pub mod bytesobject;
pub mod import;
pub mod longobject;
pub mod object;
pub mod pyerrors;
pub mod pylifecycle;
pub mod pystate;
pub mod refcount;
pub mod traceback;
pub mod tupleobject;
pub mod unicodeobject;

#[inline]
pub(crate) fn log_stub(name: &str) {
eprintln!("[rustpython-capi stub] {name} called");
}
65 changes: 65 additions & 0 deletions crates/capi/src/longobject.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use core::ffi::{c_long, c_longlong, c_ulong, c_ulonglong};
use core::ptr;

use crate::PyObject;
use crate::pystate::with_vm;
use rustpython_vm::PyObjectRef;
use rustpython_vm::builtins::PyInt;

#[unsafe(no_mangle)]
pub extern "C" fn PyLong_FromLong(value: c_long) -> *mut PyObject {
with_vm(|vm| {
let obj: PyObjectRef = vm.ctx.new_int(value).into();
obj.into_raw().as_ptr()
})
}

#[unsafe(no_mangle)]
pub extern "C" fn PyLong_FromLongLong(_value: c_longlong) -> *mut PyObject {
crate::log_stub("PyLong_FromLongLong");
ptr::null_mut()
}

#[unsafe(no_mangle)]
pub extern "C" fn PyLong_FromSsize_t(_value: isize) -> *mut PyObject {
crate::log_stub("PyLong_FromSsize_t");
ptr::null_mut()
}

#[unsafe(no_mangle)]
pub extern "C" fn PyLong_FromSize_t(_value: usize) -> *mut PyObject {
crate::log_stub("PyLong_FromSize_t");
ptr::null_mut()
}

#[unsafe(no_mangle)]
pub extern "C" fn PyLong_FromUnsignedLong(_value: c_ulong) -> *mut PyObject {
crate::log_stub("PyLong_FromUnsignedLong");
ptr::null_mut()
}

#[unsafe(no_mangle)]
pub extern "C" fn PyLong_FromUnsignedLongLong(_value: c_ulonglong) -> *mut PyObject {
crate::log_stub("PyLong_FromUnsignedLongLong");
ptr::null_mut()
}

#[unsafe(no_mangle)]
pub extern "C" fn PyLong_AsLong(obj: *mut PyObject) -> c_long {
if obj.is_null() {
panic!("PyLong_AsLong called with null object");
}

with_vm(|_vm| {
// SAFETY: non-null checked above; caller promises a valid PyObject pointer.
let obj_ref = unsafe { &*obj };
let int_obj = obj_ref
.downcast_ref::<PyInt>()
.expect("PyLong_AsLong currently only accepts int instances");

int_obj
.as_bigint()
.try_into()
.expect("PyLong_AsLong: value out of range for c_long")
})
}
145 changes: 145 additions & 0 deletions crates/capi/src/object.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
use core::ffi::c_ulong;

use crate::PyObject;
use rustpython_vm::builtins::PyType;
use rustpython_vm::{AsObject, Context, Py};
use std::sync::LazyLock;

pub struct PyTypeObject {
ty: LazyLock<&'static Py<PyType>>,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will cause significant performance draw down.
PyType also already has flags inside.
Will you create all the new type wrapper for every static types? That will not work.

flags: c_ulong,
}

impl PyTypeObject {
const fn new(f: fn() -> &'static Py<PyType>, flags: c_ulong) -> PyTypeObject {
PyTypeObject {
ty: LazyLock::new(f),
flags,
}
}
}

const PY_TPFLAGS_HAVE_STACKLESS_EXTENSION: c_ulong = 0;
const PY_TPFLAGS_HAVE_VERSION_TAG: c_ulong = 1 << 18;
const PY_TPFLAGS_DEFAULT: c_ulong =
PY_TPFLAGS_HAVE_STACKLESS_EXTENSION | PY_TPFLAGS_HAVE_VERSION_TAG;
const PY_TPFLAGS_IMMUTABLETYPE: c_ulong = 1 << 8;
const PY_TPFLAGS_BASETYPE: c_ulong = 1 << 10;
const PY_TPFLAGS_LONG_SUBCLASS: c_ulong = 1 << 24;
const PY_TPFLAGS_TUPLE_SUBCLASS: c_ulong = 1 << 26;
const PY_TPFLAGS_UNICODE_SUBCLASS: c_ulong = 1 << 28;
const PY_TPFLAGS_TYPE_SUBCLASS: c_ulong = 1 << 31;

#[unsafe(no_mangle)]
pub static mut PyType_Type: PyTypeObject = PyTypeObject::new(
|| {
let zoo = &Context::genesis().types;
zoo.type_type
},
PY_TPFLAGS_DEFAULT | PY_TPFLAGS_IMMUTABLETYPE | PY_TPFLAGS_BASETYPE | PY_TPFLAGS_TYPE_SUBCLASS,
);

#[unsafe(no_mangle)]
pub static mut PyLong_Type: PyTypeObject = PyTypeObject::new(
|| {
let zoo = &Context::genesis().types;
zoo.int_type
},
PY_TPFLAGS_DEFAULT | PY_TPFLAGS_IMMUTABLETYPE | PY_TPFLAGS_BASETYPE | PY_TPFLAGS_LONG_SUBCLASS,
);

#[unsafe(no_mangle)]
pub static mut PyTuple_Type: PyTypeObject = PyTypeObject::new(
|| {
let zoo = &Context::genesis().types;
zoo.tuple_type
},
PY_TPFLAGS_DEFAULT | PY_TPFLAGS_IMMUTABLETYPE | PY_TPFLAGS_BASETYPE | PY_TPFLAGS_TUPLE_SUBCLASS,
);

#[unsafe(no_mangle)]
pub static mut PyUnicode_Type: PyTypeObject = PyTypeObject::new(
|| {
let zoo = &Context::genesis().types;
zoo.str_type
},
PY_TPFLAGS_DEFAULT
| PY_TPFLAGS_IMMUTABLETYPE
| PY_TPFLAGS_BASETYPE
| PY_TPFLAGS_UNICODE_SUBCLASS,
);

#[unsafe(no_mangle)]
pub extern "C" fn Py_TYPE(op: *mut PyObject) -> *mut PyTypeObject {
if op.is_null() {
return std::ptr::null_mut();
}

unsafe {
let ty = (*op).class();
if ty.is(*PyType_Type.ty) {
&raw mut PyType_Type
} else if ty.is(*PyLong_Type.ty) {
&raw mut PyLong_Type
} else if ty.is(*PyTuple_Type.ty) {
&raw mut PyTuple_Type
} else if ty.is(*PyUnicode_Type.ty) {
&raw mut PyUnicode_Type
} else {
todo!("Unsupported type: {:?}", ty.name());
}
}
}

#[unsafe(no_mangle)]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub extern "C" fn PyType_GetFlags(ty: *mut PyTypeObject) -> c_ulong {
if ty.is_null() {
panic!("PyType_GetFlags called with null type pointer");
}

// SAFETY: caller guarantees this is a valid exported type object pointer.
unsafe { (*ty).flags }
}

#[unsafe(no_mangle)]
pub extern "C" fn PyType_GetName(_ty: *mut PyTypeObject) -> *mut PyObject {
crate::log_stub("PyType_GetName");
std::ptr::null_mut()
}

#[unsafe(no_mangle)]
pub extern "C" fn PyType_GetQualName(_ty: *mut PyTypeObject) -> *mut PyObject {
crate::log_stub("PyType_GetQualName");
std::ptr::null_mut()
}

#[unsafe(no_mangle)]
pub extern "C" fn PyObject_CallNoArgs(_callable: *mut PyObject) -> *mut PyObject {
crate::log_stub("PyObject_CallNoArgs");
std::ptr::null_mut()
}

#[unsafe(no_mangle)]
pub extern "C" fn PyObject_GetAttr(_obj: *mut PyObject, _name: *mut PyObject) -> *mut PyObject {
crate::log_stub("PyObject_GetAttr");
std::ptr::null_mut()
}

#[unsafe(no_mangle)]
pub extern "C" fn PyObject_Repr(_obj: *mut PyObject) -> *mut PyObject {
crate::log_stub("PyObject_Repr");
std::ptr::null_mut()
}

#[unsafe(no_mangle)]
pub extern "C" fn PyObject_Str(_obj: *mut PyObject) -> *mut PyObject {
crate::log_stub("PyObject_Str");
std::ptr::null_mut()
}

#[unsafe(no_mangle)]
pub extern "C" fn Py_GetConstantBorrowed(_constant_id: core::ffi::c_uint) -> *mut PyObject {
crate::log_stub("Py_GetConstantBorrowed");
std::ptr::null_mut()
}
Loading
Loading