Make class.slots completely immutable

This commit is contained in:
Noah committed 2020-08-30 15:46:04 -05:00
1 parent 79964b0f48
commit 79c0efc491
13 files changed
+262 -153

No files matched your search

+163 -75
View File
@@ -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
View File
@@ -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"];
+2 -2
View File
@@ -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
View File
@@ -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]
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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")
+3 -6
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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]