Implement PyType_FromSpec & PyType_FromMetaclass (#9213)

* Implement `PyType_FromSpec` & `PyType_FromMetaclass`

* Review
This commit is contained in:
Bas Schoenmaeckers authored and GitHub committed 2026-10-19 16:45:53 +00:00
1 parent eb2ffc61dd
commit c08375baeb
2 files changed
+113 -3

No files matched your search

+85 -3
View File
@@ -5,7 +5,8 @@ use crate::pystate::with_vm;
use crate::slots::{PySlot, PySlotKind, PySlotType};
use crate::util::CStrExt;
use crate::util::FfiPtrExt;
use core::ffi::{c_char, c_int, c_ulong, c_void};
use core::ffi::{c_char, c_int, c_uint, c_ulong, c_void};
use core::ptr;
use rustpython_vm::builtins::{PyStr, PyType};
use rustpython_vm::function::{ItemDoc, PyMethodFlags};
use rustpython_vm::types::{AtomicPyTypeFlags, PyTypeFlags, PyTypeSlots, SlotAccessor};
@@ -22,6 +23,15 @@ pub struct PyType_Slot {
pub pfunc: *mut c_void,
}
#[repr(C)]
pub struct PyType_Spec {
pub name: *const c_char,
pub basicsize: c_int,
pub itemsize: c_int,
pub flags: c_uint,
pub slots: *mut PyType_Slot,
}
impl PyType_Slot {
pub(crate) fn iter<'a>(mut slots: *const Self) -> impl Iterator<Item = &'a Self> {
core::iter::from_fn(move || {
@@ -104,11 +114,11 @@ pub unsafe extern "C" fn PyType_GetFullyQualifiedName(ptr: *mut PyTypeObject) ->
#[unsafe(no_mangle)]
pub unsafe extern "C" fn PyType_GetSlot(_ty: *const PyTypeObject, _slot: c_int) -> *mut c_void {
core::ptr::null_mut()
ptr::null_mut()
}
#[unsafe(no_mangle)]
pub extern "C" fn PyType_FromSlots(slots: *const PySlot) -> *mut PyObject {
pub unsafe extern "C" fn PyType_FromSlots(slots: *const PySlot) -> *mut PyObject {
with_vm(|vm| {
let mut name = None;
let mut base = None;
@@ -254,6 +264,78 @@ pub extern "C" fn PyType_FromSlots(slots: *const PySlot) -> *mut PyObject {
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn PyType_FromMetaclass(
metaclass: *mut PyTypeObject,
module: *mut PyObject,
spec: *mut PyType_Spec,
bases: *mut PyObject,
) -> *mut PyObject {
let &PyType_Spec {
name,
basicsize,
itemsize,
flags,
slots: type_slots,
} = unsafe { &*spec };
let mut slots = [PySlot::SLOT_END; 9];
let mut write_slot = {
let mut iter = slots.iter_mut();
move |slot| {
debug_assert!(
iter.len() >= 2,
"PyType_FromMetaclass: last slot is reserved for SLOT_END"
);
let entry = iter
.next()
.expect("Too many slots for PyType_FromMetaclass");
*entry = slot;
}
};
if !bases.is_null() {
write_slot(PySlot::new(49, bases));
}
if !metaclass.is_null() {
write_slot(PySlot::new(107, metaclass));
}
if !module.is_null() {
write_slot(PySlot::new(108, module));
}
write_slot(PySlot::new(95, name.cast_mut()));
write_slot(PySlot::new(96, basicsize as isize));
write_slot(PySlot::new(98, itemsize as isize));
write_slot(PySlot::new(99, flags as u64));
write_slot(PySlot::new(93, type_slots));
unsafe { PyType_FromSlots(slots.as_ptr()) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn PyType_FromModuleAndSpec(
module: *mut PyObject,
spec: *mut PyType_Spec,
bases: *mut PyObject,
) -> *mut PyObject {
unsafe { PyType_FromMetaclass(ptr::null_mut(), module, spec, bases) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn PyType_FromSpecWithBases(
spec: *mut PyType_Spec,
bases: *mut PyObject,
) -> *mut PyObject {
unsafe { PyType_FromMetaclass(ptr::null_mut(), ptr::null_mut(), spec, bases) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn PyType_FromSpec(spec: *mut PyType_Spec) -> *mut PyObject {
unsafe { PyType_FromMetaclass(ptr::null_mut(), ptr::null_mut(), spec, ptr::null_mut()) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn PyObject_GetTypeData(
obj: *mut PyObject,
+28
View File
@@ -20,6 +20,16 @@ impl PySlot {
const SLOT_OPTIONAL: u16 = 0x0001;
const SLOT_STATIC: u16 = 0x0002;
const SLOT_INTPTR: u16 = 0x0004;
pub(crate) const SLOT_END: Self = unsafe { core::mem::zeroed() };
pub(crate) fn new(id: u16, value: impl Into<PySlotValue>) -> Self {
Self {
sl_id: id,
sl_flags: 0,
_reserved: 0,
value: value.into(),
}
}
pub(crate) fn iter<'a>(mut slots: *const Self) -> impl Iterator<Item = &'a Self> {
core::iter::from_fn(move || {
@@ -130,6 +140,24 @@ pub union PySlotValue {
pub sl_uint64: u64,
}
impl<T> From<*mut T> for PySlotValue {
fn from(ptr: *mut T) -> Self {
Self { sl_ptr: ptr.cast() }
}
}
impl From<isize> for PySlotValue {
fn from(size: isize) -> Self {
Self { sl_size: size }
}
}
impl From<u64> for PySlotValue {
fn from(value: u64) -> Self {
Self { sl_uint64: value }
}
}
#[allow(dead_code)]
#[derive(Debug, Copy, Clone)]
pub(crate) enum PySlotModule<'a> {