Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
itemsize
  • Loading branch information
youknowone committed Dec 27, 2025
commit 028c05fc17304d4756f564e4233c2df9f096501f
20 changes: 17 additions & 3 deletions crates/derive-impl/src/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ pub(crate) fn impl_pyclass_impl(attr: PunctuatedNestedMeta, item: Item) -> Resul
with_impl,
with_method_defs,
with_slots,
itemsize,
} = extract_impl_attrs(attr, &impl_ty)?;
let payload_ty = attr_payload.unwrap_or(payload_guess);
let method_def = &context.method_items;
Expand All @@ -189,9 +190,17 @@ pub(crate) fn impl_pyclass_impl(attr: PunctuatedNestedMeta, item: Item) -> Resul
#(#class_extensions)*
}
},
parse_quote! {
fn __extend_slots(slots: &mut ::rustpython_vm::types::PyTypeSlots) {
#slots_impl
{
let itemsize_impl = itemsize.as_ref().map(|size| {
quote! {
slots.itemsize = #size;
}
});
parse_quote! {
fn __extend_slots(slots: &mut ::rustpython_vm::types::PyTypeSlots) {
#itemsize_impl
#slots_impl
}
}
},
];
Expand Down Expand Up @@ -1618,6 +1627,7 @@ struct ExtractedImplAttrs {
with_impl: TokenStream,
with_method_defs: Vec<TokenStream>,
with_slots: TokenStream,
itemsize: Option<syn::Expr>,
}

fn extract_impl_attrs(attr: PunctuatedNestedMeta, item: &Ident) -> Result<ExtractedImplAttrs> {
Expand All @@ -1636,6 +1646,7 @@ fn extract_impl_attrs(attr: PunctuatedNestedMeta, item: &Ident) -> Result<Extrac
}
}];
let mut payload = None;
let mut itemsize = None;

for attr in attr {
match attr {
Expand Down Expand Up @@ -1721,6 +1732,8 @@ fn extract_impl_attrs(attr: PunctuatedNestedMeta, item: &Ident) -> Result<Extrac
} else {
bail_span!(value, "payload must be a string literal")
}
} else if path.is_ident("itemsize") {
itemsize = Some(value);
} else {
bail_span!(path, "Unknown pyimpl attribute")
}
Expand All @@ -1741,6 +1754,7 @@ fn extract_impl_attrs(attr: PunctuatedNestedMeta, item: &Ident) -> Result<Extrac
with_slots: quote! {
#(#with_slots)*
},
itemsize,
})
}

Expand Down
1 change: 1 addition & 0 deletions crates/vm/src/builtins/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ impl PyRef<PyBytes> {
}

#[pyclass(
itemsize = 1,
flags(BASETYPE, _MATCH_SELF),
with(
Py,
Expand Down
1 change: 1 addition & 0 deletions crates/vm/src/builtins/int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ impl PyInt {
}

#[pyclass(
itemsize = 4,
flags(BASETYPE, _MATCH_SELF),
with(PyRef, Comparable, Hashable, Constructor, AsNumber, Representable)
)]
Expand Down
11 changes: 2 additions & 9 deletions crates/vm/src/builtins/tuple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,16 +257,9 @@ impl<T> PyTuple<PyRef<T>> {
}

#[pyclass(
itemsize = std::mem::size_of::<crate::PyObjectRef>(),
flags(BASETYPE, SEQUENCE, _MATCH_SELF),
with(
AsMapping,
AsSequence,
Hashable,
Comparable,
Iterable,
Constructor,
Representable
)
with(AsMapping, AsSequence, Hashable, Comparable, Iterable, Constructor, Representable)
)]
impl PyTuple {
#[pymethod]
Expand Down
21 changes: 15 additions & 6 deletions crates/vm/src/builtins/type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -948,6 +948,11 @@ impl PyType {
self.slots.basicsize
}

#[pygetset]
fn __itemsize__(&self) -> usize {
self.slots.itemsize
}

#[pygetset]
pub fn __name__(&self, vm: &VirtualMachine) -> PyStrRef {
self.name_inner(
Expand Down Expand Up @@ -2088,12 +2093,16 @@ fn solid_base<'a>(typ: &'a Py<PyType>, vm: &VirtualMachine) -> &'a Py<PyType> {
vm.ctx.types.object_type
};

// TODO: requires itemsize comparison too
if typ.__basicsize__() != base.__basicsize__() {
typ
} else {
base
}
// Check for extra instance variables (CPython's extra_ivars)
let t_size = typ.__basicsize__();
let b_size = base.__basicsize__();
let t_itemsize = typ.slots.itemsize;
let b_itemsize = base.slots.itemsize;

// Has extra ivars if: sizes differ AND (has items OR t_size > b_size)
let has_extra_ivars = t_size != b_size && (t_itemsize > 0 || b_itemsize > 0 || t_size > b_size);

if has_extra_ivars { typ } else { base }
}

fn best_base<'a>(bases: &'a [PyTypeRef], vm: &VirtualMachine) -> PyResult<&'a Py<PyType>> {
Expand Down
2 changes: 2 additions & 0 deletions crates/vm/src/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ pub trait PyClassDef {
const TP_NAME: &'static str;
const DOC: Option<&'static str> = None;
const BASICSIZE: usize;
const ITEMSIZE: usize = 0;
const UNHASHABLE: bool = false;

// due to restriction of rust trait system, object.__base__ is None
Expand Down Expand Up @@ -210,6 +211,7 @@ pub trait PyClassImpl: PyClassDef {
flags: Self::TP_FLAGS,
name: Self::TP_NAME,
basicsize: Self::BASICSIZE,
itemsize: Self::ITEMSIZE,
doc: Self::DOC,
methods: Self::METHOD_DEFS,
..Default::default()
Expand Down
2 changes: 1 addition & 1 deletion crates/vm/src/types/slot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ pub struct PyTypeSlots {
pub(crate) name: &'static str, // tp_name with <module>.<class> for print, not class name

pub basicsize: usize,
// tp_itemsize
pub itemsize: usize, // tp_itemsize

// Methods to implement standard operations

Expand Down