diff --git a/crates/vm/src/stdlib/ctypes/array.rs b/crates/vm/src/stdlib/ctypes/array.rs index f31c8284d8b..25708b57f8e 100644 --- a/crates/vm/src/stdlib/ctypes/array.rs +++ b/crates/vm/src/stdlib/ctypes/array.rs @@ -13,6 +13,7 @@ use crate::{ types::{AsBuffer, AsNumber, AsSequence, Constructor, Initializer}, }; use num_traits::{Signed, ToPrimitive}; +use std::borrow::Cow; /// Get itemsize from a PEP 3118 format string /// Extracts the type code (last char after endianness prefix) and returns its size @@ -430,6 +431,18 @@ impl Constructor for PyCArray { } } +impl Initializer for PyCArray { + type Args = FuncArgs; + + fn init(zelf: PyRef, args: Self::Args, vm: &VirtualMachine) -> PyResult<()> { + // Re-initialize array elements when __init__ is called + for (i, value) in args.args.iter().enumerate() { + PyCArray::setitem_by_index(&zelf, i as isize, value.clone(), vm)?; + } + Ok(()) + } +} + impl AsSequence for PyCArray { fn as_sequence() -> &'static PySequenceMethods { use std::sync::LazyLock; @@ -457,7 +470,7 @@ impl AsSequence for PyCArray { #[pyclass( flags(BASETYPE, IMMUTABLETYPE), - with(Constructor, AsSequence, AsBuffer) + with(Constructor, Initializer, AsSequence, AsBuffer) )] impl PyCArray { #[pyclassmethod] @@ -868,16 +881,38 @@ impl PyCArray { }; let mut buffer = buffer_lock.write(); - Self::write_element_to_buffer( - buffer.to_mut(), - final_offset, - element_size, - type_code.as_deref(), - &value, - zelf, - index, - vm, - ) + + // For shared memory (Cow::Borrowed), we need to write directly to the memory + // For owned memory (Cow::Owned), we can write to the owned buffer + match &mut *buffer { + Cow::Borrowed(slice) => { + // SAFETY: For from_buffer, the slice points to writable shared memory. + // Python's from_buffer requires writable buffer, so this is safe. + let ptr = slice.as_ptr() as *mut u8; + let len = slice.len(); + let owned_slice = unsafe { std::slice::from_raw_parts_mut(ptr, len) }; + Self::write_element_to_buffer( + owned_slice, + final_offset, + element_size, + type_code.as_deref(), + &value, + zelf, + index, + vm, + ) + } + Cow::Owned(vec) => Self::write_element_to_buffer( + vec, + final_offset, + element_size, + type_code.as_deref(), + &value, + zelf, + index, + vm, + ), + } } // Array_subscript diff --git a/crates/vm/src/stdlib/ctypes/simple.rs b/crates/vm/src/stdlib/ctypes/simple.rs index 803b38d6e05..fbb17620fe4 100644 --- a/crates/vm/src/stdlib/ctypes/simple.rs +++ b/crates/vm/src/stdlib/ctypes/simple.rs @@ -1085,6 +1085,18 @@ impl Constructor for PyCSimple { } } +impl Initializer for PyCSimple { + type Args = (OptionalArg,); + + fn init(zelf: PyRef, args: Self::Args, vm: &VirtualMachine) -> PyResult<()> { + // If an argument is provided, update the value + if let Some(value) = args.0.into_option() { + PyCSimple::set_value(zelf.into(), value, vm)?; + } + Ok(()) + } +} + // Simple_repr impl Representable for PyCSimple { fn repr_str(zelf: &Py, vm: &VirtualMachine) -> PyResult { @@ -1111,7 +1123,10 @@ impl Representable for PyCSimple { } } -#[pyclass(flags(BASETYPE), with(Constructor, AsBuffer, AsNumber, Representable))] +#[pyclass( + flags(BASETYPE), + with(Constructor, Initializer, AsBuffer, AsNumber, Representable) +)] impl PyCSimple { #[pygetset] fn _b0_(&self) -> Option { @@ -1278,7 +1293,24 @@ impl PyCSimple { // Update buffer when value changes let buffer_bytes = value_to_bytes_endian(&type_code, &content, swapped, vm); - *zelf.0.buffer.write() = std::borrow::Cow::Owned(buffer_bytes); + + // If the buffer is borrowed (from shared memory), write in-place + // Otherwise replace with new owned buffer + let mut buffer = zelf.0.buffer.write(); + match &mut *buffer { + Cow::Borrowed(slice) => { + // SAFETY: For from_buffer, the slice points to writable shared memory. + // Python's from_buffer requires writable buffer, so this is safe. + let ptr = slice.as_ptr() as *mut u8; + let len = slice.len().min(buffer_bytes.len()); + unsafe { + std::ptr::copy_nonoverlapping(buffer_bytes.as_ptr(), ptr, len); + } + } + Cow::Owned(vec) => { + vec.copy_from_slice(&buffer_bytes); + } + } // For c_char_p (type "z"), c_wchar_p (type "Z"), and py_object (type "O"), // keep the reference in _objects