mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 10:44:36 +08:00
Make class.slots completely immutable
This commit is contained in:
13 files changed
+262
-153
No files matched your search
+163
-75
@@ -16,9 +16,63 @@ use syn_ext::ext::*;
|
||||
struct ImplContext {
|
||||
impl_extend_items: ItemNursery,
|
||||
getset_items: GetSetNursery,
|
||||
extend_slots_items: ItemNursery,
|
||||
errors: Vec<syn::Error>,
|
||||
}
|
||||
|
||||
fn extract_items_into_context<'a, Item>(
|
||||
context: &mut ImplContext,
|
||||
items: impl Iterator<Item = &'a mut Item>,
|
||||
) where
|
||||
Item: ItemLike + ToTokens + GetIdent + syn_ext::ext::ItemAttrExt + 'a,
|
||||
{
|
||||
for item in items {
|
||||
let r = item.try_split_attr_mut(|attrs, item| {
|
||||
let (pyitems, cfgs) = attrs_to_content_items(&attrs, new_impl_item::<Item>)?;
|
||||
for pyitem in pyitems.iter().rev() {
|
||||
let r = pyitem.gen_impl_item(ImplItemArgs::<Item> {
|
||||
item,
|
||||
attrs,
|
||||
context,
|
||||
cfgs: cfgs.as_slice(),
|
||||
});
|
||||
context.errors.ok_or_push(r);
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
context.errors.ok_or_push(r);
|
||||
}
|
||||
context.errors.ok_or_push(context.getset_items.validate());
|
||||
}
|
||||
|
||||
fn raw_extend_methods<T: syn::parse::Parse>(context: &ImplContext) -> impl Iterator<Item = T> {
|
||||
let getset_impl = &context.getset_items;
|
||||
let extend_impl = &context.impl_extend_items;
|
||||
let slots_impl = &context.extend_slots_items;
|
||||
macro_rules! iter_chain {
|
||||
($($it:expr),*$(,)?) => {
|
||||
std::iter::empty()
|
||||
$(.chain(std::iter::once($it)))*
|
||||
};
|
||||
}
|
||||
iter_chain![
|
||||
parse_quote! {
|
||||
fn __extend_py_class(
|
||||
ctx: &::rustpython_vm::pyobject::PyContext,
|
||||
class: &::rustpython_vm::obj::objtype::PyClassRef,
|
||||
) {
|
||||
#getset_impl
|
||||
#extend_impl
|
||||
}
|
||||
},
|
||||
parse_quote! {
|
||||
fn __extend_slots(slots: &mut ::rustpython_vm::slots::PyClassSlots) {
|
||||
#slots_impl
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
pub(crate) fn impl_pyimpl(
|
||||
attr: AttributeArgs,
|
||||
item: Item,
|
||||
@@ -26,80 +80,55 @@ pub(crate) fn impl_pyimpl(
|
||||
let mut context = ImplContext::default();
|
||||
let mut tokens = match item {
|
||||
Item::Impl(mut imp) => {
|
||||
for item in imp.items.iter_mut() {
|
||||
let r = item.try_split_attr_mut(|attrs, item| {
|
||||
let (pyitems, cfgs) =
|
||||
attrs_to_content_items(&attrs, new_impl_item::<syn::ImplItem>)?;
|
||||
for pyitem in pyitems.iter().rev() {
|
||||
let r = pyitem.gen_impl_item(ImplItemArgs {
|
||||
item,
|
||||
attrs,
|
||||
context: &mut context,
|
||||
cfgs: cfgs.as_slice(),
|
||||
});
|
||||
context.errors.ok_or_push(r);
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
context.errors.ok_or_push(r);
|
||||
}
|
||||
context.errors.ok_or_push(context.getset_items.validate());
|
||||
extract_items_into_context(&mut context, imp.items.iter_mut());
|
||||
|
||||
let ExtractedImplAttrs {
|
||||
with_impl,
|
||||
flags,
|
||||
with_slots,
|
||||
structseq_impl,
|
||||
} = extract_impl_attrs(attr)?;
|
||||
|
||||
let (with_impl, flags) = extract_impl_attrs(attr)?;
|
||||
let ty = &imp.self_ty;
|
||||
let getset_impl = &context.getset_items;
|
||||
let extend_impl = &context.impl_extend_items;
|
||||
quote! {
|
||||
#imp
|
||||
impl ::rustpython_vm::pyobject::PyClassImpl for #ty {
|
||||
const TP_FLAGS: ::rustpython_vm::slots::PyTpFlags = ::rustpython_vm::slots::PyTpFlags::from_bits_truncate(#flags);
|
||||
|
||||
fn impl_extend_class(
|
||||
ctx: &::rustpython_vm::pyobject::PyContext,
|
||||
class: &::rustpython_vm::obj::objtype::PyClassRef,
|
||||
) {
|
||||
#getset_impl
|
||||
#extend_impl
|
||||
#with_impl
|
||||
if structseq_impl {
|
||||
imp.items.extend(raw_extend_methods(&context));
|
||||
imp.into_token_stream()
|
||||
} else {
|
||||
let getset_impl = &context.getset_items;
|
||||
let extend_impl = &context.impl_extend_items;
|
||||
let slots_impl = &context.extend_slots_items;
|
||||
quote! {
|
||||
#imp
|
||||
impl ::rustpython_vm::pyobject::PyClassImpl for #ty {
|
||||
const TP_FLAGS: ::rustpython_vm::slots::PyTpFlags = ::rustpython_vm::slots::PyTpFlags::from_bits_truncate(#flags);
|
||||
|
||||
fn impl_extend_class(
|
||||
ctx: &::rustpython_vm::pyobject::PyContext,
|
||||
class: &::rustpython_vm::obj::objtype::PyClassRef,
|
||||
) {
|
||||
#getset_impl
|
||||
#extend_impl
|
||||
#with_impl
|
||||
}
|
||||
|
||||
fn extend_slots(slots: &mut ::rustpython_vm::slots::PyClassSlots) {
|
||||
#with_slots
|
||||
#slots_impl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Item::Trait(mut trai) => {
|
||||
let mut context = ImplContext::default();
|
||||
for item in trai.items.iter_mut() {
|
||||
let r = item.try_split_attr_mut(|attrs, item| {
|
||||
let (pyitems, cfgs) =
|
||||
attrs_to_content_items(&attrs, new_impl_item::<syn::TraitItem>)?;
|
||||
for pyitem in pyitems.iter().rev() {
|
||||
let r = pyitem.gen_impl_item(ImplItemArgs {
|
||||
item,
|
||||
attrs,
|
||||
context: &mut context,
|
||||
cfgs: cfgs.as_slice(),
|
||||
});
|
||||
context.errors.ok_or_push(r);
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
context.errors.ok_or_push(r);
|
||||
}
|
||||
context.errors.ok_or_push(context.getset_items.validate());
|
||||
extract_items_into_context(&mut context, trai.items.iter_mut());
|
||||
|
||||
trai.items.extend(raw_extend_methods(&context));
|
||||
|
||||
let getset_impl = &context.getset_items;
|
||||
let extend_impl = &context.impl_extend_items;
|
||||
trai.items.push(parse_quote! {
|
||||
fn __extend_py_class(
|
||||
ctx: &::rustpython_vm::pyobject::PyContext,
|
||||
class: &::rustpython_vm::obj::objtype::PyClassRef,
|
||||
) {
|
||||
#getset_impl
|
||||
#extend_impl
|
||||
}
|
||||
});
|
||||
trai.into_token_stream()
|
||||
}
|
||||
item => quote!(#item),
|
||||
item => item.into_token_stream(),
|
||||
};
|
||||
if let Some(error) = context.errors.into_error() {
|
||||
let error = Diagnostic::from(error);
|
||||
@@ -161,6 +190,19 @@ pub(crate) fn impl_pyclass(
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
struct StructSeqItemMeta(ItemMetaInner);
|
||||
|
||||
impl ItemMeta for StructSeqItemMeta {
|
||||
const ALLOWED_NAMES: &'static [&'static str] = &["module", "name", "with_pyimpl"];
|
||||
|
||||
fn from_inner(inner: ItemMetaInner) -> Self {
|
||||
Self(inner)
|
||||
}
|
||||
fn inner(&self) -> &ItemMetaInner {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn impl_pystruct_sequence(
|
||||
attr: AttributeArgs,
|
||||
item: Item,
|
||||
@@ -174,7 +216,9 @@ pub(crate) fn impl_pystruct_sequence(
|
||||
)
|
||||
};
|
||||
let fake_ident = Ident::new("pystruct_sequence", struc.span());
|
||||
let class_meta = ClassItemMeta::from_nested(struc.ident.clone(), fake_ident, attr.into_iter())?;
|
||||
let meta = StructSeqItemMeta::from_nested(struc.ident.clone(), fake_ident, attr.into_iter())?;
|
||||
let with_pyimpl = meta.inner()._bool("with_pyimpl")?;
|
||||
let class_meta = ClassItemMeta(meta.0);
|
||||
let class_name = class_meta.class_name()?;
|
||||
let module_name = class_meta.mandatory_module()?;
|
||||
|
||||
@@ -206,6 +250,19 @@ pub(crate) fn impl_pystruct_sequence(
|
||||
}
|
||||
}
|
||||
|
||||
let (with_extend, with_slots) = if with_pyimpl {
|
||||
(
|
||||
quote! {
|
||||
Self::__extend_py_class(ctx, class);
|
||||
},
|
||||
quote! {
|
||||
Self::__extend_slots(slots);
|
||||
},
|
||||
)
|
||||
} else {
|
||||
(quote! {}, quote! {})
|
||||
};
|
||||
|
||||
let ty = &struc.ident;
|
||||
let ret = quote! {
|
||||
#struc
|
||||
@@ -242,6 +299,7 @@ pub(crate) fn impl_pystruct_sequence(
|
||||
|
||||
#(#properties)*
|
||||
class.set_str_attr("__repr__", ctx.new_method(Self::repr));
|
||||
#with_extend
|
||||
}
|
||||
|
||||
fn make_class(
|
||||
@@ -250,6 +308,10 @@ pub(crate) fn impl_pystruct_sequence(
|
||||
use crate::pyobject::PyClassDef;
|
||||
Self::make_class_with_base(ctx, Self::NAME, &ctx.types.tuple_type)
|
||||
}
|
||||
|
||||
fn extend_slots(slots: &mut ::rustpython_vm::slots::PyClassSlots) {
|
||||
#with_slots
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(ret)
|
||||
@@ -394,11 +456,11 @@ where
|
||||
#transform(Self::#ident)
|
||||
};
|
||||
quote! {
|
||||
(*class.slots.write()).#slot_ident = Some(#into_func);
|
||||
slots.#slot_ident = Some(#into_func);
|
||||
}
|
||||
};
|
||||
|
||||
args.context.impl_extend_items.add_item(
|
||||
args.context.extend_slots_items.add_item(
|
||||
format!("(slot {})", slot_name),
|
||||
args.cfgs.to_vec(),
|
||||
tokens,
|
||||
@@ -639,11 +701,18 @@ impl SlotItemMeta {
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_impl_attrs(
|
||||
attr: AttributeArgs,
|
||||
) -> std::result::Result<(TokenStream, TokenStream), Diagnostic> {
|
||||
struct ExtractedImplAttrs {
|
||||
with_impl: TokenStream,
|
||||
with_slots: TokenStream,
|
||||
flags: TokenStream,
|
||||
structseq_impl: bool,
|
||||
}
|
||||
|
||||
fn extract_impl_attrs(attr: AttributeArgs) -> std::result::Result<ExtractedImplAttrs, Diagnostic> {
|
||||
let mut withs = Vec::new();
|
||||
let mut with_slots = Vec::new();
|
||||
let mut flags = vec![quote! { ::rustpython_vm::slots::PyTpFlags::DEFAULT.bits() }];
|
||||
let mut structseq_impl = false;
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
flags.push(quote! {
|
||||
@@ -658,9 +727,21 @@ fn extract_impl_attrs(
|
||||
for meta in nested {
|
||||
match meta {
|
||||
NestedMeta::Meta(Meta::Path(path)) => {
|
||||
withs.push(quote! {
|
||||
<Self as #path>::__extend_py_class(ctx, class);
|
||||
});
|
||||
if path_eq(&path, "Self") {
|
||||
withs.push(quote! {
|
||||
Self::__extend_py_class(ctx, class);
|
||||
});
|
||||
with_slots.push(quote! {
|
||||
Self::__extend_slots(slots);
|
||||
});
|
||||
} else {
|
||||
withs.push(quote! {
|
||||
<Self as #path>::__extend_py_class(ctx, class);
|
||||
});
|
||||
with_slots.push(quote! {
|
||||
<Self as #path>::__extend_slots(slots);
|
||||
});
|
||||
}
|
||||
}
|
||||
meta => {
|
||||
bail_span!(meta, "#[pyimpl(with(...))] arguments should be paths")
|
||||
@@ -691,18 +772,25 @@ fn extract_impl_attrs(
|
||||
bail_span!(path, "Unknown pyimpl attribute")
|
||||
}
|
||||
}
|
||||
NestedMeta::Meta(Meta::Path(path)) if path_eq(&path, "structseq_impl") => {
|
||||
structseq_impl = true
|
||||
}
|
||||
attr => bail_span!(attr, "Unknown pyimpl attribute"),
|
||||
}
|
||||
}
|
||||
|
||||
Ok((
|
||||
quote! {
|
||||
Ok(ExtractedImplAttrs {
|
||||
with_impl: quote! {
|
||||
#(#withs)*
|
||||
},
|
||||
quote! {
|
||||
flags: quote! {
|
||||
#(#flags)*
|
||||
},
|
||||
))
|
||||
with_slots: quote! {
|
||||
#(#with_slots)*
|
||||
},
|
||||
structseq_impl,
|
||||
})
|
||||
}
|
||||
|
||||
fn new_impl_item<Item>(index: usize, attr_name: String) -> Box<dyn ImplItem<Item>>
|
||||
|
||||
+1
-1
@@ -223,7 +223,7 @@ impl ItemMeta for SimpleItemMeta {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ClassItemMeta(ItemMetaInner);
|
||||
pub(crate) struct ClassItemMeta(pub ItemMetaInner);
|
||||
|
||||
impl ItemMeta for ClassItemMeta {
|
||||
const ALLOWED_NAMES: &'static [&'static str] = &["module", "name"];
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::pyobject::{
|
||||
BorrowValue, PyClassDef, PyClassImpl, PyContext, PyIterable, PyObjectRef, PyRef, PyResult,
|
||||
PyValue, TryFromObject, TypeProtocol,
|
||||
};
|
||||
use crate::types::create_type_with_flags;
|
||||
use crate::types::create_type_with_slots;
|
||||
use crate::VirtualMachine;
|
||||
use crate::{py_serde, sysmodule};
|
||||
|
||||
@@ -463,7 +463,7 @@ pub struct ExceptionZoo {
|
||||
impl ExceptionZoo {
|
||||
pub fn new(type_type: &PyClassRef, object_type: &PyClassRef) -> Self {
|
||||
let create_exception_type = |name: &str, base: &PyClassRef| {
|
||||
create_type_with_flags(name, type_type, base, PyBaseException::TP_FLAGS)
|
||||
create_type_with_slots(name, type_type, base, PyBaseException::make_slots())
|
||||
};
|
||||
// Sorted By Hierarchy then alphabetized.
|
||||
let base_exception_type = create_exception_type(PyBaseExceptionRef::NAME, &object_type);
|
||||
|
||||
+18
-13
@@ -38,30 +38,35 @@ macro_rules! py_class {
|
||||
};
|
||||
( $ctx:expr, $class_name:expr, $class_base:expr, $flags:expr, { $($name:tt => $value:expr),* $(,)* }) => {
|
||||
{
|
||||
let py_class = $ctx.new_class($class_name, $class_base, $crate::slots::PyTpFlags::DEFAULT | $flags);
|
||||
$crate::extend_class!($ctx, &py_class, { $($name => $value),* });
|
||||
#[allow(unused_mut)]
|
||||
let mut slots: $crate::slots::PyClassSlots = ($crate::slots::PyTpFlags::DEFAULT | $flags).into();
|
||||
$($crate::py_class!(@extract_slots($ctx, &mut slots, $name, $value));)*
|
||||
let py_class = $ctx.new_class($class_name, $class_base, slots);
|
||||
$($crate::py_class!(@extract_attrs($ctx, &py_class, $name, $value));)*
|
||||
$ctx.add_tp_new_wrapper(&py_class);
|
||||
py_class
|
||||
}
|
||||
};
|
||||
(@extract_slots($ctx:expr, $slots:expr, (slot $slot_name:ident), $value:expr)) => {
|
||||
$slots.$slot_name = Some(
|
||||
$crate::function::IntoPyNativeFunc::into_func($value)
|
||||
);
|
||||
};
|
||||
(@extract_slots($ctx:expr, $class:expr, $name:expr, $value:expr)) => {};
|
||||
(@extract_attrs($ctx:expr, $slots:expr, (slot $slot_name:ident), $value:expr)) => {};
|
||||
(@extract_attrs($ctx:expr, $class:expr, $name:expr, $value:expr)) => {
|
||||
$class.set_str_attr($name, $value);
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! extend_class {
|
||||
( $ctx:expr, $class:expr, { $($name:tt => $value:expr),* $(,)* }) => {
|
||||
( $ctx:expr, $class:expr, { $($name:expr => $value:expr),* $(,)* }) => {
|
||||
$(
|
||||
$crate::extend_class!(@set_attr($ctx, $class, $name, $value));
|
||||
$class.set_str_attr($name, $value);
|
||||
)*
|
||||
$ctx.add_tp_new_wrapper(&$class);
|
||||
};
|
||||
|
||||
(@set_attr($ctx:expr, $class:expr, (slot $slot_name:ident), $value:expr)) => {
|
||||
$class.slots.write().$slot_name = Some(
|
||||
$crate::function::IntoPyNativeFunc::into_func($value)
|
||||
);
|
||||
};
|
||||
(@set_attr($ctx:expr, $class:expr, $name:expr, $value:expr)) => {
|
||||
$class.set_str_attr($name, $value);
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
||||
@@ -56,6 +56,7 @@ impl PyModuleRef {
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
debug_assert!(crate::pyobject::TypeProtocol::lease_class(self.as_object())
|
||||
.slots
|
||||
.flags
|
||||
.has_feature(crate::slots::PyTpFlags::HAS_DICT));
|
||||
init_module_dict(
|
||||
|
||||
+17
-21
@@ -32,8 +32,7 @@ pub struct PyClass {
|
||||
pub mro: Vec<PyClassRef>,
|
||||
pub subclasses: PyRwLock<Vec<PyWeak>>,
|
||||
pub attributes: PyRwLock<PyAttributes>,
|
||||
pub flags: PyTpFlags,
|
||||
pub slots: PyRwLock<PyClassSlots>,
|
||||
pub slots: PyClassSlots,
|
||||
}
|
||||
|
||||
impl fmt::Display for PyClass {
|
||||
@@ -58,7 +57,7 @@ impl PyValue for PyClass {
|
||||
|
||||
impl PyClassRef {
|
||||
fn tp_name(zelf: Self, vm: &VirtualMachine) -> String {
|
||||
let opt_name = zelf.slots.read().name.clone();
|
||||
let opt_name = zelf.slots.name.read().clone();
|
||||
opt_name.unwrap_or_else(|| {
|
||||
let module = zelf.attributes.read().get("__module__").cloned();
|
||||
let new_name = if let Some(module) = module {
|
||||
@@ -69,7 +68,7 @@ impl PyClassRef {
|
||||
} else {
|
||||
zelf.name.clone()
|
||||
};
|
||||
zelf.slots.write().name = Some(new_name.clone());
|
||||
*zelf.slots.name.write() = Some(new_name.clone());
|
||||
new_name
|
||||
})
|
||||
}
|
||||
@@ -104,7 +103,7 @@ impl PyClassRef {
|
||||
|
||||
#[pyproperty(magic)]
|
||||
fn flags(self) -> u64 {
|
||||
self.flags.bits()
|
||||
self.slots.flags.bits()
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
@@ -158,7 +157,7 @@ impl PyClassRef {
|
||||
|
||||
#[pyproperty(magic, setter)]
|
||||
fn set_module(self, value: PyObjectRef) {
|
||||
self.slots.write().name = None;
|
||||
*self.slots.name.write() = None;
|
||||
self.attributes
|
||||
.write()
|
||||
.insert("__module__".to_owned(), value);
|
||||
@@ -188,7 +187,7 @@ impl PyClassRef {
|
||||
|
||||
if let Some(attr) = self.get_attr(&name) {
|
||||
let attr_class = attr.class();
|
||||
let slots = attr_class.slots.read();
|
||||
let slots = &attr_class.slots;
|
||||
if let Some(ref descr_get) = slots.descr_get {
|
||||
drop(mcl);
|
||||
return descr_get(vm, attr, None, OptionalArg::Present(self.into_object()));
|
||||
@@ -321,12 +320,10 @@ impl PyClassRef {
|
||||
let winner = calculate_meta_class(metatype.clone(), &bases, vm)?;
|
||||
let metatype = if !winner.is(&metatype) {
|
||||
#[allow(clippy::redundant_clone)] // false positive
|
||||
{
|
||||
if let Some(ref tp_new) = winner.clone().slots.read().new {
|
||||
// Pass it to the winner
|
||||
if let Some(ref tp_new) = winner.clone().slots.new {
|
||||
// Pass it to the winner
|
||||
|
||||
return tp_new(vm, args.insert(winner.into_object()));
|
||||
}
|
||||
return tp_new(vm, args.insert(winner.into_object()));
|
||||
}
|
||||
winner
|
||||
} else {
|
||||
@@ -360,7 +357,7 @@ impl PyClassRef {
|
||||
}
|
||||
|
||||
// TODO: how do we know if it should have a dict?
|
||||
let flags = base.flags | PyTpFlags::HAS_DICT;
|
||||
let flags = base.slots.flags | PyTpFlags::HAS_DICT;
|
||||
|
||||
let typ = new(
|
||||
metatype,
|
||||
@@ -368,7 +365,7 @@ impl PyClassRef {
|
||||
base,
|
||||
bases,
|
||||
attributes,
|
||||
flags,
|
||||
flags.into(),
|
||||
)
|
||||
.map_err(|e| vm.new_type_error(e))?;
|
||||
|
||||
@@ -544,7 +541,7 @@ fn call_tp_new(
|
||||
return vm.invoke(&new_meth, args.insert(typ.clone().into_object()));
|
||||
}
|
||||
}
|
||||
if let Some(tp_new) = cls.slots.read().new.as_ref() {
|
||||
if let Some(tp_new) = cls.slots.new.as_ref() {
|
||||
return tp_new(vm, args.insert(subtype.into_object()));
|
||||
}
|
||||
}
|
||||
@@ -677,7 +674,7 @@ pub fn new(
|
||||
base: PyClassRef,
|
||||
bases: Vec<PyClassRef>,
|
||||
attrs: HashMap<String, PyObjectRef>,
|
||||
mut flags: PyTpFlags,
|
||||
mut slots: PyClassSlots,
|
||||
) -> Result<PyClassRef, String> {
|
||||
// Check for duplicates in bases.
|
||||
let mut unique_bases = HashSet::new();
|
||||
@@ -693,8 +690,8 @@ pub fn new(
|
||||
.collect();
|
||||
let mro = linearise_mro(mros)?;
|
||||
|
||||
if base.flags.has_feature(PyTpFlags::HAS_DICT) {
|
||||
flags |= PyTpFlags::HAS_DICT
|
||||
if base.slots.flags.has_feature(PyTpFlags::HAS_DICT) {
|
||||
slots.flags |= PyTpFlags::HAS_DICT
|
||||
}
|
||||
let new_type = PyRef::new_ref(
|
||||
PyClass {
|
||||
@@ -704,8 +701,7 @@ pub fn new(
|
||||
mro,
|
||||
subclasses: PyRwLock::default(),
|
||||
attributes: PyRwLock::new(attrs),
|
||||
flags,
|
||||
slots: PyRwLock::default(),
|
||||
slots,
|
||||
},
|
||||
typ,
|
||||
None,
|
||||
@@ -763,7 +759,7 @@ fn best_base<'a>(bases: &'a [PyClassRef], vm: &VirtualMachine) -> PyResult<PyCla
|
||||
// return NULL;
|
||||
// }
|
||||
|
||||
if !base_i.flags.has_feature(PyTpFlags::BASETYPE) {
|
||||
if !base_i.slots.flags.has_feature(PyTpFlags::BASETYPE) {
|
||||
return Err(vm.new_type_error(format!(
|
||||
"type '{}' is not an acceptable base type",
|
||||
base_i.name
|
||||
|
||||
+18
-9
@@ -36,8 +36,8 @@ use crate::obj::objstr;
|
||||
use crate::obj::objtuple::{PyTuple, PyTupleRef};
|
||||
use crate::obj::objtype::{self, PyClass, PyClassRef};
|
||||
use crate::scope::Scope;
|
||||
use crate::slots::PyTpFlags;
|
||||
use crate::types::{create_type, create_type_with_flags, initialize_types, TypeZoo};
|
||||
use crate::slots::{PyClassSlots, PyTpFlags};
|
||||
use crate::types::{create_type, create_type_with_slots, initialize_types, TypeZoo};
|
||||
use crate::vm::VirtualMachine;
|
||||
use rustpython_common::cell::{PyRwLock, PyRwLockReadGuard};
|
||||
use rustpython_common::rc::PyRc;
|
||||
@@ -276,8 +276,8 @@ impl PyContext {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn new_class(&self, name: &str, base: &PyClassRef, flags: PyTpFlags) -> PyClassRef {
|
||||
create_type_with_flags(name, &self.types.type_type, base, flags)
|
||||
pub fn new_class(&self, name: &str, base: &PyClassRef, slots: PyClassSlots) -> PyClassRef {
|
||||
create_type_with_slots(name, &self.types.type_type, base, slots)
|
||||
}
|
||||
|
||||
pub fn new_namespace(&self) -> PyObjectRef {
|
||||
@@ -1177,7 +1177,7 @@ pub trait PyValue: fmt::Debug + PyThreadingConstraint + Sized + 'static {
|
||||
}
|
||||
|
||||
fn into_ref_with_type_unchecked(self, cls: PyClassRef, vm: &VirtualMachine) -> PyRef<Self> {
|
||||
let dict = if cls.flags.has_feature(PyTpFlags::HAS_DICT) {
|
||||
let dict = if cls.slots.flags.has_feature(PyTpFlags::HAS_DICT) {
|
||||
Some(vm.ctx.new_dict())
|
||||
} else {
|
||||
None
|
||||
@@ -1282,7 +1282,7 @@ pub trait PyClassImpl: PyClassDef {
|
||||
fn extend_class(ctx: &PyContext, class: &PyClassRef) {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
assert!(class.flags.is_created_with_flags());
|
||||
assert!(class.slots.flags.is_created_with_flags());
|
||||
}
|
||||
if Self::TP_FLAGS.has_feature(PyTpFlags::HAS_DICT) {
|
||||
class.set_str_attr(
|
||||
@@ -1295,7 +1295,6 @@ pub trait PyClassImpl: PyClassDef {
|
||||
);
|
||||
}
|
||||
Self::impl_extend_class(ctx, class);
|
||||
class.slots.write().name = Some(Self::TP_NAME.to_owned());
|
||||
ctx.add_tp_new_wrapper(&class);
|
||||
if let Some(doc) = Self::DOC {
|
||||
class.set_str_attr("__doc__", ctx.new_str(doc));
|
||||
@@ -1310,13 +1309,23 @@ pub trait PyClassImpl: PyClassDef {
|
||||
}
|
||||
|
||||
fn make_class_with_base(ctx: &PyContext, name: &str, base: &PyClassRef) -> PyClassRef {
|
||||
let py_class = ctx.new_class(name, base, Self::TP_FLAGS);
|
||||
let py_class = ctx.new_class(name, base, Self::make_slots());
|
||||
Self::extend_class(ctx, &py_class);
|
||||
py_class
|
||||
}
|
||||
|
||||
fn create_bare_type(type_type: &PyClassRef, base: &PyClassRef) -> PyClassRef {
|
||||
create_type_with_flags(Self::NAME, type_type, base, Self::TP_FLAGS)
|
||||
create_type_with_slots(Self::NAME, type_type, base, Self::make_slots())
|
||||
}
|
||||
|
||||
fn extend_slots(slots: &mut PyClassSlots);
|
||||
|
||||
fn make_slots() -> PyClassSlots {
|
||||
let mut slots = PyClassSlots::default();
|
||||
slots.flags = Self::TP_FLAGS;
|
||||
slots.name = PyRwLock::new(Some(Self::TP_NAME.to_owned()));
|
||||
Self::extend_slots(&mut slots);
|
||||
slots
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-1
@@ -1,3 +1,4 @@
|
||||
use crate::common::cell::PyRwLock;
|
||||
use crate::function::{OptionalArg, PyFuncArgs, PyNativeFunc};
|
||||
use crate::pyobject::{IdProtocol, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject};
|
||||
use crate::VirtualMachine;
|
||||
@@ -35,12 +36,22 @@ impl Default for PyTpFlags {
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PyClassSlots {
|
||||
pub name: Option<String>, // tp_name, not class name
|
||||
pub flags: PyTpFlags,
|
||||
pub name: PyRwLock<Option<String>>, // tp_name, not class name
|
||||
pub new: Option<PyNativeFunc>,
|
||||
pub call: Option<PyNativeFunc>,
|
||||
pub descr_get: Option<PyDescrGetFunc>,
|
||||
}
|
||||
|
||||
impl From<PyTpFlags> for PyClassSlots {
|
||||
fn from(flags: PyTpFlags) -> Self {
|
||||
Self {
|
||||
flags,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for PyClassSlots {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("PyClassSlots")
|
||||
|
||||
@@ -170,7 +170,7 @@ fn time_strptime(
|
||||
Ok(PyStructTime::new(vm, instant, -1).into_obj(vm))
|
||||
}
|
||||
|
||||
#[pystruct_sequence(module = "time", name = "struct_time")]
|
||||
#[pystruct_sequence(with_pyimpl, module = "time", name = "struct_time")]
|
||||
#[allow(dead_code)]
|
||||
struct PyStructTime {
|
||||
tm_year: PyObjectRef,
|
||||
@@ -190,6 +190,7 @@ impl fmt::Debug for PyStructTime {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(structseq_impl)]
|
||||
impl PyStructTime {
|
||||
fn new(vm: &VirtualMachine, tm: NaiveDateTime, isdst: i32) -> Self {
|
||||
PyStructTime {
|
||||
@@ -227,6 +228,7 @@ impl PyStructTime {
|
||||
.into_object()
|
||||
}
|
||||
|
||||
#[pyslot]
|
||||
fn tp_new(cls: PyClassRef, seq: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
|
||||
Self::try_from_object(vm, seq)?.into_struct_sequence(vm, cls)
|
||||
}
|
||||
@@ -260,11 +262,6 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
|
||||
let struct_time_type = PyStructTime::make_class(ctx);
|
||||
|
||||
// TODO: allow $[pyimpl]s for struct_sequences
|
||||
extend_class!(ctx, struct_time_type, {
|
||||
(slot new) => PyStructTime::tp_new,
|
||||
});
|
||||
|
||||
py_module!(vm, "time", {
|
||||
"asctime" => ctx.new_function(time_asctime),
|
||||
"ctime" => ctx.new_function(time_ctime),
|
||||
|
||||
+7
-11
@@ -69,7 +69,7 @@ fn getframe(offset: OptionalArg<usize>, vm: &VirtualMachine) -> PyResult<FrameRe
|
||||
/// sys.flags
|
||||
///
|
||||
/// Flags provided through command line arguments or environment vars.
|
||||
#[pystruct_sequence(name = "flags", module = "sys")]
|
||||
#[pystruct_sequence(with_pyimpl, name = "flags", module = "sys")]
|
||||
#[derive(Default, Debug)]
|
||||
struct SysFlags {
|
||||
/// -d
|
||||
@@ -104,6 +104,7 @@ struct SysFlags {
|
||||
utf8_mode: u8,
|
||||
}
|
||||
|
||||
#[pyimpl(structseq_impl)]
|
||||
impl SysFlags {
|
||||
fn from_settings(settings: &PySettings) -> Self {
|
||||
// Start with sensible defaults:
|
||||
@@ -119,6 +120,11 @@ impl SysFlags {
|
||||
flags.dont_write_bytecode = settings.dont_write_bytecode as u8;
|
||||
flags
|
||||
}
|
||||
|
||||
#[pyslot]
|
||||
fn tp_new(_cls: PyClassRef, _args: PyFuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
Err(vm.new_type_error("cannot create 'sys.flags' instances".to_owned()))
|
||||
}
|
||||
}
|
||||
|
||||
fn sys_getrefcount(obj: PyObjectRef) -> usize {
|
||||
@@ -433,21 +439,11 @@ pub fn make_module(vm: &VirtualMachine, module: PyObjectRef, builtins: PyObjectR
|
||||
let ctx = &vm.ctx;
|
||||
|
||||
let flags_type = SysFlags::make_class(ctx);
|
||||
extend_class!(ctx, flags_type, {
|
||||
(slot new) => |_cls: PyClassRef, _args: PyFuncArgs, vm: &VirtualMachine| -> PyResult {
|
||||
Err(vm.new_type_error("cannot create 'sys.flags' instances".to_owned()))
|
||||
},
|
||||
});
|
||||
let flags = SysFlags::from_settings(&vm.state.settings)
|
||||
.into_struct_sequence(vm, flags_type)
|
||||
.unwrap();
|
||||
|
||||
let version_info_type = version::VersionInfo::make_class(ctx);
|
||||
extend_class!(ctx, version_info_type, {
|
||||
(slot new) => |_cls: PyClassRef, _args: PyFuncArgs, vm: &VirtualMachine| -> PyResult {
|
||||
Err(vm.new_type_error("cannot create 'sys.version_info' instances".to_owned()))
|
||||
},
|
||||
});
|
||||
let version_info = version::VersionInfo::VERSION
|
||||
.into_struct_sequence(vm, version_info_type)
|
||||
.unwrap();
|
||||
|
||||
+7
-9
@@ -40,7 +40,7 @@ use crate::obj::objweakproxy;
|
||||
use crate::obj::objweakref;
|
||||
use crate::obj::objzip;
|
||||
use crate::pyobject::{PyAttributes, PyClassDef, PyClassImpl, PyContext, PyObject};
|
||||
use crate::slots::PyTpFlags;
|
||||
use crate::slots::PyClassSlots;
|
||||
use rustpython_common::{cell::PyRwLock, rc::PyRc};
|
||||
use std::mem::MaybeUninit;
|
||||
use std::ptr;
|
||||
@@ -202,14 +202,14 @@ impl TypeZoo {
|
||||
}
|
||||
|
||||
pub fn create_type(name: &str, type_type: &PyClassRef, base: &PyClassRef) -> PyClassRef {
|
||||
create_type_with_flags(name, type_type, base, Default::default())
|
||||
create_type_with_slots(name, type_type, base, Default::default())
|
||||
}
|
||||
|
||||
pub fn create_type_with_flags(
|
||||
pub fn create_type_with_slots(
|
||||
name: &str,
|
||||
type_type: &PyClassRef,
|
||||
base: &PyClassRef,
|
||||
flags: PyTpFlags,
|
||||
slots: PyClassSlots,
|
||||
) -> PyClassRef {
|
||||
let dict = PyAttributes::new();
|
||||
objtype::new(
|
||||
@@ -218,7 +218,7 @@ pub fn create_type_with_flags(
|
||||
base.clone(),
|
||||
vec![base.clone()],
|
||||
dict,
|
||||
PyTpFlags::default() | flags,
|
||||
slots,
|
||||
)
|
||||
.expect("Failed to create a new type in internal code.")
|
||||
}
|
||||
@@ -265,8 +265,7 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) {
|
||||
mro: vec![],
|
||||
subclasses: PyRwLock::default(),
|
||||
attributes: PyRwLock::new(PyAttributes::new()),
|
||||
flags: objtype::PyClassRef::TP_FLAGS,
|
||||
slots: PyRwLock::default(),
|
||||
slots: objtype::PyClassRef::make_slots(),
|
||||
},
|
||||
},
|
||||
Uninit { typ }
|
||||
@@ -281,8 +280,7 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) {
|
||||
mro: vec![],
|
||||
subclasses: PyRwLock::default(),
|
||||
attributes: PyRwLock::new(PyAttributes::new()),
|
||||
flags: objobject::PyBaseObject::TP_FLAGS,
|
||||
slots: PyRwLock::default(),
|
||||
slots: objobject::PyBaseObject::make_slots(),
|
||||
},
|
||||
},
|
||||
Uninit { typ },
|
||||
|
||||
+10
-1
@@ -15,7 +15,7 @@ const SERIAL: usize = 0;
|
||||
pub const VERSION_HEX: usize =
|
||||
(MAJOR << 24) | (MINOR << 16) | (MICRO << 8) | (RELEASELEVEL_N << 4) | SERIAL;
|
||||
|
||||
#[pystruct_sequence(module = "sys", name = "version_info")]
|
||||
#[pystruct_sequence(with_pyimpl, module = "sys", name = "version_info")]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct VersionInfo {
|
||||
major: usize,
|
||||
@@ -34,6 +34,7 @@ pub fn get_version() -> String {
|
||||
)
|
||||
}
|
||||
|
||||
#[pyimpl(structseq_impl)]
|
||||
impl VersionInfo {
|
||||
pub const VERSION: VersionInfo = VersionInfo {
|
||||
major: MAJOR,
|
||||
@@ -42,6 +43,14 @@ impl VersionInfo {
|
||||
releaselevel: RELEASELEVEL,
|
||||
serial: SERIAL,
|
||||
};
|
||||
#[pyslot]
|
||||
fn tp_new(
|
||||
_cls: crate::obj::objtype::PyClassRef,
|
||||
_args: crate::function::PyFuncArgs,
|
||||
vm: &crate::VirtualMachine,
|
||||
) -> crate::pyobject::PyResult {
|
||||
Err(vm.new_type_error("cannot create 'sys.version_info' instances".to_owned()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_version_number() -> String {
|
||||
|
||||
+3
-4
@@ -767,7 +767,7 @@ impl VirtualMachine {
|
||||
cls: Option<PyObjectRef>,
|
||||
) -> Option<PyResult> {
|
||||
let descr_class = descr.class();
|
||||
let slots = descr_class.slots.read();
|
||||
let slots = &descr_class.slots;
|
||||
if let Some(descr_get) = slots.descr_get.as_ref() {
|
||||
Some(descr_get(self, descr, obj, OptionalArg::from_option(cls)))
|
||||
} else if let Some(ref descriptor) = descr_class.get_attr("__get__") {
|
||||
@@ -819,7 +819,7 @@ impl VirtualMachine {
|
||||
|
||||
fn _invoke(&self, callable: &PyObjectRef, args: PyFuncArgs) -> PyResult {
|
||||
vm_trace!("Invoke: {:?} {:?}", callable, args);
|
||||
if let Some(slot_call) = callable.lease_class().slots.read().call.as_ref() {
|
||||
if let Some(slot_call) = callable.lease_class().slots.call.as_ref() {
|
||||
self.trace_event(TraceEvent::Call)?;
|
||||
let args = args.insert(callable.clone());
|
||||
let result = slot_call(self, args);
|
||||
@@ -1052,8 +1052,7 @@ impl VirtualMachine {
|
||||
|
||||
pub fn is_callable(&self, obj: &PyObjectRef) -> bool {
|
||||
let class = obj.lease_class();
|
||||
let lock = class.slots.read();
|
||||
lock.call.is_some() || class.has_attr("__call__")
|
||||
class.slots.call.is_some() || class.has_attr("__call__")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
Reference in new issue
Block a user