Skip to content

Module definition abstraction #9

@emmatyping

Description

@emmatyping

Python modules rely on a static definition of a module. To avoid needing to have a static, threadsafe PyObject, I propose we use PyModExport, which is the new way of defining modules, and does not rely on the safety of a static, threadsafe PyObject.

An example of a module definition, taken from the above PEP:

static PyModuleDef_Slot examplemodule_slots[] = {
    {Py_mod_name, "examplemodule"},
    {Py_mod_doc, (char*)examplemodule_doc},
    {Py_mod_methods, examplemodule_methods},
    {Py_mod_state_size, (void*)sizeof(examplemodule_state)},
    {Py_mod_exec, (void*)examplemodule_exec},
    {0}
};

PyMODEXPORT_FUNC
PyModExport_examplemodule(void)
{
    return examplemodule_slots;
}

PyMODEXPORT_FUNC is equivalent to *mut PyModuleDef_Slot.

One design I have in mind is something along the lines of:

pub enum PyModuleDefSlot {
    Name(&'static CStr),
    Doc(&'static CStr),
    MultipleInterpreters(*mut c_void),
    GIL(*mut c_void),
    StateSize(usize),
    // ... etc.
}

pub struct PyModuleDef<const N: usize>(UnsafeCell<[ffi::PyModuleDef_Slot; N]>);

impl<const N: usize> PyModuleDef<N> {
    pub const fn new(slots: [PyModuleDefSlot; N]) -> Self {
        todo!()
    }

    pub fn as_mut_ptr(&'static self) -> *mut PyModuleDef_Slot {
        self.0.get() as *mut PyModuleDef_Slot
    }
}

unsafe impl<const N: usize> Sync for PyModuleDef<N> {}

static MODULE: PyModuleDef<5> = PyModule::new([
    PyModuleDefSlot::Name(c"mymodule"),
    PyModuleDefSlot::Doc(c"An example module for a proof of concept"),
    // etc.
]);

#[unsafe(no_mangle)]
unsafe extern "C" fn PyModExport_mymodule() -> *mut PyModuleDef_Slot {
    MODULE.as_mut_ptr()
}

I think this isn't currently sound because we probably need a thread state-aware lock to prevent races on MODULE.as_mut_ptr()?

We will likely also want a design for specifying methods that are part of the module, which are listed in a static array similar to the PyModExport static.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions