Skip to content
Merged
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
6 changes: 6 additions & 0 deletions crates/host_env/src/ctypes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1860,6 +1860,12 @@ impl<U: 'static> CallbackThunk<U> {
}
}

/// Borrow the userdata owned by this callback closure.
pub fn userdata(&self) -> &U {
// SAFETY: new stores Box::into_raw here; Drop owns its only reclamation.
unsafe { &*self.userdata_ptr }
}

pub fn code_ptr(&self) -> CodePtr {
self.code_ptr
}
Expand Down
20 changes: 19 additions & 1 deletion crates/vm/src/builtins/type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ unsafe impl crate::object::Traverse for PyType {
self.attributes.traverse(tracer_fn);
if let Some(ext) = self.heaptype_ext.as_ref() {
ext.specialization_cache.traverse(tracer_fn);
ext.type_data.traverse(tracer_fn);
}
}

Expand Down Expand Up @@ -336,6 +337,11 @@ unsafe impl crate::object::Traverse for PyType {
self.attributes.drain_into(out);
if let Some(ext) = self.heaptype_ext.as_ref() {
ext.specialization_cache.clear_into(out);
if let Some(mut data) = ext.type_data.try_write()
&& let Some(data) = data.as_mut()
{
data.clear(out);
}
}
}
}
Expand Down Expand Up @@ -1700,6 +1706,18 @@ impl PyType {
/// Initialize type data for this type. Can only be called once.
/// Returns an error if the type is not a heap type or if data is already initialized.
pub fn init_type_data<T: Any + Send + Sync + 'static>(&self, data: T) -> Result<(), String> {
self.init_type_data_slot(TypeDataSlot::new(data))
}

/// Initialize extension storage with GC traversal and clearing callbacks.
pub fn init_traced_type_data<T: Any + Send + Sync + Traverse>(
&self,
data: T,
) -> Result<(), String> {
self.init_type_data_slot(TypeDataSlot::new_traced(data))
}

fn init_type_data_slot(&self, data: TypeDataSlot) -> Result<(), String> {
let ext = self
.heaptype_ext
.as_ref()
Expand All @@ -1709,7 +1727,7 @@ impl PyType {
if type_data.is_some() {
return Err("Type data already initialized".to_string());
}
*type_data = Some(TypeDataSlot::new(data));
*type_data = Some(data);
Ok(())
}

Expand Down
7 changes: 5 additions & 2 deletions crates/vm/src/stdlib/_ctypes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,11 @@ impl Py<PyType> {
.filter(|info| info.initialized)
}

/// Get _type_ attribute as String (type code like "i", "d", etc.)
/// Get the scalar converter selected when the storage type was initialized.
fn type_code(&self, vm: &VirtualMachine) -> Option<String> {
if let Some(info) = self.stg_info_opt() {
return info.scalar_code.map(|code| code.to_string());
}
self.as_object()
.get_attr("_type_", vm)
.ok()
Expand All @@ -62,7 +65,7 @@ impl Py<PyType> {
} else {
let mut stg = StgInfo::default();
stg.flags |= StgInfoFlags::DICTFLAG_FINAL;
let _ = base.init_type_data(stg);
let _ = base.init_traced_type_data(stg);
}
}
}
Expand Down
13 changes: 12 additions & 1 deletion crates/vm/src/stdlib/_ctypes/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,12 +381,23 @@ impl AsSequence for PyCArrayType {
name = "Array",
base = PyCData,
metaclass = "PyCArrayType",
module = "_ctypes"
module = "_ctypes",
traverse = "manual"
)]
#[derive(Debug)]
#[repr(transparent)]
pub(crate) struct PyCArray(pub PyCData);

// SAFETY: this transparent wrapper owns exactly the references in its base.
unsafe impl crate::object::Traverse for PyCArray {
fn traverse(&self, tracer: &mut crate::object::TraverseFn<'_>) {
self.0.traverse(tracer);
}
fn clear(&mut self, out: &mut Vec<PyObjectRef>) {
self.0.clear(out);
}
}

impl PyCArray {
/// Get the type code of array element type (e.g., "c" for c_char, "u" for c_wchar)
fn get_element_type_code(zelf: &Py<Self>, vm: &VirtualMachine) -> Option<String> {
Expand Down
Loading
Loading