mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Make PyStructSequence a derive macro
This commit is contained in:
20 files changed
+252
-205
No files matched your search
+4
-5
@@ -52,11 +52,10 @@ pub fn pymodule(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
result_to_tokens(pymodule::impl_pymodule(attr, item))
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn pystruct_sequence(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let attr = parse_macro_input!(attr as AttributeArgs);
|
||||
let item = parse_macro_input!(item as Item);
|
||||
result_to_tokens(pyclass::impl_pystruct_sequence(attr, item))
|
||||
#[proc_macro_derive(PyStructSequence)]
|
||||
pub fn pystruct_sequence(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
result_to_tokens(pyclass::impl_pystruct_sequence(input))
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
|
||||
+119
-137
@@ -7,8 +7,8 @@ use proc_macro2::TokenStream;
|
||||
use quote::{quote, quote_spanned, ToTokens};
|
||||
use std::collections::HashMap;
|
||||
use syn::{
|
||||
parse_quote, spanned::Spanned, Attribute, AttributeArgs, Ident, Index, Item, Meta, NestedMeta,
|
||||
Result,
|
||||
parse_quote, spanned::Spanned, Attribute, AttributeArgs, DeriveInput, Ident, Index, Item, Meta,
|
||||
NestedMeta, Result,
|
||||
};
|
||||
use syn_ext::ext::*;
|
||||
|
||||
@@ -17,6 +17,7 @@ struct ImplContext {
|
||||
impl_extend_items: ItemNursery,
|
||||
getset_items: GetSetNursery,
|
||||
extend_slots_items: ItemNursery,
|
||||
class_extensions: Vec<TokenStream>,
|
||||
errors: Vec<syn::Error>,
|
||||
}
|
||||
|
||||
@@ -49,6 +50,7 @@ fn raw_extend_methods<T: syn::parse::Parse>(context: &ImplContext) -> impl Itera
|
||||
let getset_impl = &context.getset_items;
|
||||
let extend_impl = &context.impl_extend_items;
|
||||
let slots_impl = &context.extend_slots_items;
|
||||
let class_extensions = &context.class_extensions;
|
||||
macro_rules! iter_chain {
|
||||
($($it:expr),*$(,)?) => {
|
||||
std::iter::empty()
|
||||
@@ -63,6 +65,7 @@ fn raw_extend_methods<T: syn::parse::Parse>(context: &ImplContext) -> impl Itera
|
||||
) {
|
||||
#getset_impl
|
||||
#extend_impl
|
||||
#(#class_extensions)*
|
||||
}
|
||||
},
|
||||
parse_quote! {
|
||||
@@ -86,36 +89,32 @@ pub(crate) fn impl_pyimpl(
|
||||
with_impl,
|
||||
flags,
|
||||
with_slots,
|
||||
structseq_impl,
|
||||
} = extract_impl_attrs(attr)?;
|
||||
|
||||
let ty = &imp.self_ty;
|
||||
|
||||
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);
|
||||
let getset_impl = &context.getset_items;
|
||||
let extend_impl = &context.impl_extend_items;
|
||||
let slots_impl = &context.extend_slots_items;
|
||||
let class_extensions = &context.class_extensions;
|
||||
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 impl_extend_class(
|
||||
ctx: &::rustpython_vm::pyobject::PyContext,
|
||||
class: &::rustpython_vm::obj::objtype::PyClassRef,
|
||||
) {
|
||||
#getset_impl
|
||||
#extend_impl
|
||||
#with_impl
|
||||
#(#class_extensions)*
|
||||
}
|
||||
|
||||
fn extend_slots(slots: &mut ::rustpython_vm::slots::PyClassSlots) {
|
||||
#with_slots
|
||||
#slots_impl
|
||||
}
|
||||
fn extend_slots(slots: &mut ::rustpython_vm::slots::PyClassSlots) {
|
||||
#with_slots
|
||||
#slots_impl
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,6 +159,29 @@ fn generate_class_def(
|
||||
Some(v) => quote!(Some(#v) ),
|
||||
None => quote!(None),
|
||||
};
|
||||
let mut is_pystruct = false;
|
||||
'pystruct_check: for attr in attrs {
|
||||
if path_eq(&attr.path, "derive") {
|
||||
if let Ok(Meta::List(l)) = attr.parse_meta() {
|
||||
for nested in l.nested {
|
||||
if nested
|
||||
.get_ident()
|
||||
.map_or(false, |p| p == "PyStructSequence")
|
||||
{
|
||||
is_pystruct = true;
|
||||
break 'pystruct_check;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let base_class = if is_pystruct {
|
||||
let baseclassdef = quote!(::rustpython_vm::pyobject::BaseClassDef);
|
||||
quote!(const BASE: #baseclassdef = #baseclassdef::tuple();)
|
||||
} else {
|
||||
quote!()
|
||||
};
|
||||
|
||||
let tokens = quote! {
|
||||
impl ::rustpython_vm::pyobject::PyClassDef for #ident {
|
||||
@@ -167,6 +189,7 @@ fn generate_class_def(
|
||||
const MODULE_NAME: Option<&'static str> = #module_name;
|
||||
const TP_NAME: &'static str = #module_class_name;
|
||||
const DOC: Option<&'static str> = #doc;
|
||||
#base_class
|
||||
}
|
||||
};
|
||||
Ok(tokens)
|
||||
@@ -190,127 +213,59 @@ 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,
|
||||
input: DeriveInput,
|
||||
) -> std::result::Result<TokenStream, Diagnostic> {
|
||||
let struc = if let Item::Struct(struc) = item {
|
||||
struc
|
||||
let fields = if let syn::Data::Struct(ref struc) = input.data {
|
||||
&struc.fields
|
||||
} else {
|
||||
bail_span!(
|
||||
item,
|
||||
input,
|
||||
"#[pystruct_sequence] can only be on a struct declaration"
|
||||
)
|
||||
};
|
||||
let fake_ident = Ident::new("pystruct_sequence", struc.span());
|
||||
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()?;
|
||||
|
||||
let class_def =
|
||||
generate_class_def(&struc.ident, &class_name, Some(&module_name), &struc.attrs)?;
|
||||
let mut properties = Vec::new();
|
||||
let mut field_names = Vec::new();
|
||||
for (i, field) in struc.fields.iter().enumerate() {
|
||||
let idx = Index::from(i);
|
||||
if let Some(ref field_name) = field.ident {
|
||||
let field_name_str = field_name.to_string();
|
||||
// TODO add doc to the generated property
|
||||
let property = quote! {
|
||||
class.set_str_attr(
|
||||
#field_name_str,
|
||||
ctx.new_readonly_getset(
|
||||
match fields {
|
||||
syn::Fields::Named(fields) => {
|
||||
for (i, field) in fields.named.iter().enumerate() {
|
||||
let idx = Index::from(i);
|
||||
let field_name = field.ident.as_ref().unwrap();
|
||||
let field_name_str = field_name.to_string();
|
||||
// TODO add doc to the generated property
|
||||
let property = quote! {
|
||||
class.set_str_attr(
|
||||
#field_name_str,
|
||||
|zelf: &::rustpython_vm::obj::objtuple::PyTuple,
|
||||
_vm: &::rustpython_vm::VirtualMachine| {
|
||||
zelf.fast_getitem(#idx)
|
||||
}
|
||||
),
|
||||
);
|
||||
};
|
||||
properties.push(property);
|
||||
field_names.push(quote!(#field_name));
|
||||
} else {
|
||||
field_names.push(quote!(#idx));
|
||||
ctx.new_readonly_getset(
|
||||
#field_name_str,
|
||||
|zelf: &::rustpython_vm::obj::objtuple::PyTuple,
|
||||
_vm: &::rustpython_vm::VirtualMachine| {
|
||||
zelf.fast_getitem(#idx)
|
||||
}
|
||||
),
|
||||
);
|
||||
};
|
||||
properties.push(property);
|
||||
field_names.push(quote!(#field_name));
|
||||
}
|
||||
}
|
||||
_ => bail_span!(
|
||||
input,
|
||||
"#[pystruct_sequence] can only be on a struct with named fields"
|
||||
),
|
||||
}
|
||||
|
||||
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 ty = &input.ident;
|
||||
let ret = quote! {
|
||||
#struc
|
||||
#class_def
|
||||
|
||||
impl #ty {
|
||||
pub fn into_struct_sequence(&self,
|
||||
vm: &::rustpython_vm::VirtualMachine,
|
||||
cls: ::rustpython_vm::obj::objtype::PyClassRef,
|
||||
) -> ::rustpython_vm::pyobject::PyResult<::rustpython_vm::obj::objtuple::PyTupleRef> {
|
||||
let tuple = ::rustpython_vm::obj::objtuple::PyTuple::from(
|
||||
vec![#(::rustpython_vm::pyobject::IntoPyObject::into_pyobject(
|
||||
::std::clone::Clone::clone(&self.#field_names),
|
||||
vm,
|
||||
)),*],
|
||||
);
|
||||
::rustpython_vm::pyobject::PyValue::into_ref_with_type(tuple, vm, cls)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::rustpython_vm::pyobject::PyStructSequenceImpl for #ty {
|
||||
impl ::rustpython_vm::pyobject::PyStructSequence for #ty {
|
||||
const FIELD_NAMES: &'static [&'static str] = &[#(stringify!(#field_names)),*];
|
||||
}
|
||||
|
||||
impl ::rustpython_vm::pyobject::PyClassImpl for #ty {
|
||||
#[cfg(debug_assertions)]
|
||||
const TP_FLAGS: ::rustpython_vm::slots::PyTpFlags = ::rustpython_vm::slots::PyTpFlags::_CREATED_WITH_FLAGS;
|
||||
|
||||
fn impl_extend_class(
|
||||
ctx: &::rustpython_vm::pyobject::PyContext,
|
||||
class: &::rustpython_vm::obj::objtype::PyClassRef,
|
||||
) {
|
||||
use ::rustpython_vm::pyobject::PyStructSequenceImpl;
|
||||
|
||||
#(#properties)*
|
||||
class.set_str_attr("__repr__", ctx.new_method(Self::repr));
|
||||
#with_extend
|
||||
}
|
||||
|
||||
fn make_class(
|
||||
ctx: &::rustpython_vm::pyobject::PyContext,
|
||||
) -> ::rustpython_vm::obj::objtype::PyClassRef {
|
||||
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
|
||||
fn to_tuple(&self, vm: &::rustpython_vm::VirtualMachine,) -> ::rustpython_vm::obj::objtuple::PyTuple {
|
||||
let items = vec![#(::rustpython_vm::pyobject::IntoPyObject::into_pyobject(
|
||||
::std::clone::Clone::clone(&self.#field_names),
|
||||
vm,
|
||||
)),*];
|
||||
items.into()
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -333,6 +288,11 @@ struct SlotItem {
|
||||
inner: ContentItemInner,
|
||||
}
|
||||
|
||||
/// #[extend_class]
|
||||
struct ExtendClassItem {
|
||||
inner: ContentItemInner,
|
||||
}
|
||||
|
||||
impl ContentItem for MethodItem {
|
||||
fn inner(&self) -> &ContentItemInner {
|
||||
&self.inner
|
||||
@@ -348,6 +308,11 @@ impl ContentItem for SlotItem {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
impl ContentItem for ExtendClassItem {
|
||||
fn inner(&self) -> &ContentItemInner {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
struct ImplItemArgs<'a, Item: ItemLike> {
|
||||
item: &'a Item,
|
||||
@@ -469,6 +434,26 @@ where
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl<Item> ImplItem<Item> for ExtendClassItem
|
||||
where
|
||||
Item: ItemLike + ToTokens + GetIdent,
|
||||
{
|
||||
fn gen_impl_item(&self, args: ImplItemArgs<'_, Item>) -> Result<()> {
|
||||
args.attrs.remove(self.index());
|
||||
|
||||
let ident = if args.item.is_function_or_method() {
|
||||
Ok(args.item.get_ident().unwrap())
|
||||
} else {
|
||||
Err(self.new_syn_error(args.item.span(), "can only be on a method"))
|
||||
}?;
|
||||
|
||||
args.context.class_extensions.push(quote! {
|
||||
Self::#ident(ctx, class);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[allow(clippy::type_complexity)]
|
||||
@@ -705,14 +690,12 @@ 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! {
|
||||
@@ -772,9 +755,6 @@ fn extract_impl_attrs(attr: AttributeArgs) -> std::result::Result<ExtractedImplA
|
||||
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"),
|
||||
}
|
||||
}
|
||||
@@ -789,7 +769,6 @@ fn extract_impl_attrs(attr: AttributeArgs) -> std::result::Result<ExtractedImplA
|
||||
with_slots: quote! {
|
||||
#(#with_slots)*
|
||||
},
|
||||
structseq_impl,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -812,6 +791,9 @@ where
|
||||
"pyslot" => Box::new(SlotItem {
|
||||
inner: ContentItemInner { index, attr_name },
|
||||
}),
|
||||
"extend_class" => Box::new(ExtendClassItem {
|
||||
inner: ContentItemInner { index, attr_name },
|
||||
}),
|
||||
other => unreachable!("#[pyimpl] doesn't accept #[{}]", other),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ fn new_module_item(
|
||||
"pyattr" => Box::new(AttributeItem {
|
||||
inner: ContentItemInner { index, attr_name },
|
||||
}),
|
||||
"pystruct_sequence" | "pyclass" => Box::new(ClassItem {
|
||||
"pyclass" => Box::new(ClassItem {
|
||||
inner: ContentItemInner { index, attr_name },
|
||||
pyattrs: pyattrs.unwrap_or_else(Vec::new),
|
||||
}),
|
||||
@@ -175,7 +175,7 @@ where
|
||||
if pyattrs.is_empty() {
|
||||
result.push(new_item(i, attr_name, None));
|
||||
} else {
|
||||
if !["pyclass", "pystruct_sequence"].contains(&attr_name.as_str()) {
|
||||
if attr_name != "pyclass" {
|
||||
return Err(syn::Error::new_spanned(
|
||||
attr,
|
||||
"#[pyattr] #[pyclass] is the only supported composition",
|
||||
@@ -199,7 +199,7 @@ struct FunctionItem {
|
||||
inner: ContentItemInner,
|
||||
}
|
||||
|
||||
/// #[pyclass] or #[pystruct_sequence]
|
||||
/// #[pyclass]
|
||||
struct ClassItem {
|
||||
inner: ContentItemInner,
|
||||
pyattrs: Vec<usize>,
|
||||
|
||||
+13
-12
@@ -14,6 +14,7 @@ pub(crate) const ALL_ALLOWED_NAMES: &[&str] = &[
|
||||
"pystruct_sequence",
|
||||
"pyattr",
|
||||
"pyslot",
|
||||
"extend_class",
|
||||
];
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -292,18 +293,18 @@ impl ClassItemMeta {
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
pub fn mandatory_module(&self) -> Result<String> {
|
||||
let inner = self.inner();
|
||||
let value = self.module().ok().flatten().
|
||||
ok_or_else(|| syn::Error::new_spanned(
|
||||
&inner.meta_ident,
|
||||
format!(
|
||||
"#[{attr_name}(module = ...)] must exist as a string. Built-in module is not allowed here.",
|
||||
attr_name=inner.meta_name()
|
||||
),
|
||||
))?;
|
||||
Ok(value)
|
||||
}
|
||||
// pub fn mandatory_module(&self) -> Result<String> {
|
||||
// let inner = self.inner();
|
||||
// let value = self.module().ok().flatten().
|
||||
// ok_or_else(|| syn::Error::new_spanned(
|
||||
// &inner.meta_ident,
|
||||
// format!(
|
||||
// "#[{attr_name}(module = ...)] must exist as a string. Built-in module is not allowed here.",
|
||||
// attr_name=inner.meta_name()
|
||||
// ),
|
||||
// ))?;
|
||||
// Ok(value)
|
||||
// }
|
||||
}
|
||||
|
||||
pub(crate) fn path_eq(path: &Path, s: &str) -> bool {
|
||||
|
||||
@@ -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_slots(name, type_type, base, PyBaseException::make_slots())
|
||||
create_type_with_slots(name, type_type, base.clone(), PyBaseException::make_slots())
|
||||
};
|
||||
// Sorted By Hierarchy then alphabetized.
|
||||
let base_exception_type = create_exception_type(PyBaseExceptionRef::NAME, &object_type);
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ macro_rules! py_class {
|
||||
#[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);
|
||||
let py_class = $ctx.new_class($class_name, $class_base.clone(), slots);
|
||||
$($crate::py_class!(@extract_attrs($ctx, &py_class, $name, $value));)*
|
||||
$ctx.add_tp_new_wrapper(&py_class);
|
||||
py_class
|
||||
|
||||
+50
-8
@@ -130,13 +130,16 @@ impl PyContext {
|
||||
PyRef::new_ref(payload, cls.clone(), None)
|
||||
}
|
||||
|
||||
let none_type = PyNone::create_bare_type(&types.type_type, &types.object_type);
|
||||
let none_type = PyNone::create_bare_type(&types.type_type, types.object_type.clone());
|
||||
let none = create_object(PyNone, &none_type);
|
||||
|
||||
let ellipsis = create_object(PyEllipsis, &types.ellipsis_type);
|
||||
|
||||
let not_implemented_type =
|
||||
create_type("NotImplementedType", &types.type_type, &types.object_type);
|
||||
let not_implemented_type = create_type(
|
||||
"NotImplementedType",
|
||||
&types.type_type,
|
||||
types.object_type.clone(),
|
||||
);
|
||||
let not_implemented = create_object(PyNotImplemented, ¬_implemented_type);
|
||||
|
||||
let int_cache_pool = (Self::INT_CACHE_POOL_MIN..=Self::INT_CACHE_POOL_MAX)
|
||||
@@ -276,7 +279,7 @@ impl PyContext {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn new_class(&self, name: &str, base: &PyClassRef, slots: PyClassSlots) -> PyClassRef {
|
||||
pub fn new_class(&self, name: &str, base: PyClassRef, slots: PyClassSlots) -> PyClassRef {
|
||||
create_type_with_slots(name, &self.types.type_type, base, slots)
|
||||
}
|
||||
|
||||
@@ -1257,11 +1260,29 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// can be extended in the future to use some sort of pyclass() attr instead of make_class_with_base
|
||||
pub struct BaseClassDef {
|
||||
is_tuple: bool,
|
||||
}
|
||||
impl BaseClassDef {
|
||||
pub const fn tuple() -> Self {
|
||||
BaseClassDef { is_tuple: true }
|
||||
}
|
||||
pub fn get_class(&self, ctx: &PyContext) -> PyClassRef {
|
||||
if self.is_tuple {
|
||||
ctx.types.tuple_type.clone()
|
||||
} else {
|
||||
ctx.types.object_type.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PyClassDef {
|
||||
const NAME: &'static str;
|
||||
const MODULE_NAME: Option<&'static str>;
|
||||
const TP_NAME: &'static str;
|
||||
const DOC: Option<&'static str> = None;
|
||||
const BASE: BaseClassDef = BaseClassDef { is_tuple: false };
|
||||
}
|
||||
|
||||
impl<T> PyClassDef for PyRef<T>
|
||||
@@ -1305,16 +1326,16 @@ pub trait PyClassImpl: PyClassDef {
|
||||
}
|
||||
|
||||
fn make_class(ctx: &PyContext) -> PyClassRef {
|
||||
Self::make_class_with_base(ctx, Self::NAME, &ctx.types.object_type)
|
||||
Self::make_class_with_base(ctx, Self::NAME, Self::BASE.get_class(ctx))
|
||||
}
|
||||
|
||||
fn make_class_with_base(ctx: &PyContext, name: &str, base: &PyClassRef) -> PyClassRef {
|
||||
fn make_class_with_base(ctx: &PyContext, name: &str, base: PyClassRef) -> PyClassRef {
|
||||
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 {
|
||||
fn create_bare_type(type_type: &PyClassRef, base: PyClassRef) -> PyClassRef {
|
||||
create_type_with_slots(Self::NAME, type_type, base, Self::make_slots())
|
||||
}
|
||||
|
||||
@@ -1329,9 +1350,17 @@ pub trait PyClassImpl: PyClassDef {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PyStructSequenceImpl: PyClassImpl {
|
||||
#[pyimpl]
|
||||
pub trait PyStructSequence: PyClassImpl + 'static {
|
||||
const FIELD_NAMES: &'static [&'static str];
|
||||
|
||||
fn to_tuple(&self, vm: &VirtualMachine) -> PyTuple;
|
||||
|
||||
fn into_struct_sequence(&self, vm: &VirtualMachine, cls: PyClassRef) -> PyResult<PyTupleRef> {
|
||||
self.to_tuple(vm).into_ref_with_type(vm, cls)
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn repr(zelf: PyRef<PyTuple>, vm: &VirtualMachine) -> PyResult<String> {
|
||||
let format_field = |(value, name)| {
|
||||
let s = vm.to_repr(value)?;
|
||||
@@ -1357,6 +1386,19 @@ pub trait PyStructSequenceImpl: PyClassImpl {
|
||||
};
|
||||
Ok(format!("{}({}{})", Self::TP_NAME, body, suffix))
|
||||
}
|
||||
|
||||
#[extend_class]
|
||||
fn extend_pyclass(ctx: &PyContext, class: &PyClassRef) {
|
||||
for (i, &name) in Self::FIELD_NAMES.iter().enumerate() {
|
||||
// cast i to a u8 so there's less to store in the getter closure.
|
||||
// Hopefully there's not struct sequences with >=256 elements :P
|
||||
let i = i as u8;
|
||||
class.set_str_attr(
|
||||
name,
|
||||
ctx.new_readonly_getset(name, move |zelf: &PyTuple| zelf.fast_getitem(i.into())),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: find a better place to put this impl
|
||||
|
||||
@@ -202,7 +202,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
let error = create_type(
|
||||
"Error",
|
||||
&ctx.types.type_type,
|
||||
&ctx.exceptions.exception_type,
|
||||
ctx.exceptions.exception_type.clone(),
|
||||
);
|
||||
|
||||
py_module!(vm, "_csv", {
|
||||
|
||||
+1
-1
@@ -877,7 +877,7 @@ mod fileio {
|
||||
}
|
||||
|
||||
pub fn make_fileio(ctx: &crate::pyobject::PyContext, raw_io_base: PyClassRef) -> PyClassRef {
|
||||
FileIO::make_class_with_base(ctx, FileIO::NAME, &raw_io_base)
|
||||
FileIO::make_class_with_base(ctx, FileIO::NAME, raw_io_base)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-7
@@ -23,8 +23,8 @@ use crate::obj::objstr::{PyString, PyStringRef};
|
||||
use crate::obj::objtuple::PyTupleRef;
|
||||
use crate::obj::objtype::PyClassRef;
|
||||
use crate::pyobject::{
|
||||
BorrowValue, Either, ItemProtocol, PyClassImpl, PyObjectRef, PyRef, PyResult, PyValue,
|
||||
TryFromObject, TypeProtocol,
|
||||
BorrowValue, Either, ItemProtocol, PyClassImpl, PyObjectRef, PyRef, PyResult, PyStructSequence,
|
||||
PyValue, TryFromObject, TypeProtocol,
|
||||
};
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
@@ -637,8 +637,8 @@ mod _os {
|
||||
}
|
||||
|
||||
#[pyattr]
|
||||
#[pystruct_sequence(module = "os", name = "stat_result")]
|
||||
#[derive(Debug)]
|
||||
#[pyclass(module = "os", name = "stat_result")]
|
||||
#[derive(Debug, PyStructSequence)]
|
||||
pub(super) struct StatResult {
|
||||
pub st_mode: u32,
|
||||
pub st_ino: u64,
|
||||
@@ -652,6 +652,7 @@ mod _os {
|
||||
pub st_ctime: f64,
|
||||
}
|
||||
|
||||
#[pyimpl(with(PyStructSequence))]
|
||||
impl StatResult {
|
||||
pub(super) fn into_obj(self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
self.into_struct_sequence(vm, vm.class(super::MODULE_NAME, "stat_result"))
|
||||
@@ -847,12 +848,15 @@ mod _os {
|
||||
}
|
||||
|
||||
#[pyattr]
|
||||
#[pystruct_sequence(module = "os", name = "terminal_size")]
|
||||
#[pyclass(module = "os", name = "terminal_size")]
|
||||
#[derive(PyStructSequence)]
|
||||
#[allow(dead_code)]
|
||||
pub(super) struct PyTerminalSize {
|
||||
pub columns: usize,
|
||||
pub lines: usize,
|
||||
}
|
||||
#[pyimpl(with(PyStructSequence))]
|
||||
impl PyTerminalSize {}
|
||||
|
||||
pub(super) fn support_funcs(vm: &VirtualMachine) -> Vec<SupportFunc> {
|
||||
let mut supports = super::platform::support_funcs(vm);
|
||||
@@ -1757,8 +1761,8 @@ mod posix {
|
||||
}
|
||||
|
||||
#[pyattr]
|
||||
#[pystruct_sequence(module = "os", name = "uname_result")]
|
||||
#[derive(Debug)]
|
||||
#[pyclass(module = "os", name = "uname_result")]
|
||||
#[derive(Debug, PyStructSequence)]
|
||||
struct UnameResult {
|
||||
sysname: String,
|
||||
nodename: String,
|
||||
@@ -1767,6 +1771,7 @@ mod posix {
|
||||
machine: String,
|
||||
}
|
||||
|
||||
#[pyimpl(with(PyStructSequence))]
|
||||
impl UnameResult {
|
||||
fn into_obj(self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
self.into_struct_sequence(vm, vm.class(super::MODULE_NAME, "uname_result"))
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
use crate::exceptions::IntoPyException;
|
||||
use crate::obj::objint::PyIntRef;
|
||||
use crate::obj::objstr::PyStringRef;
|
||||
use crate::pyobject::{BorrowValue, PyClassImpl, PyObjectRef, PyResult};
|
||||
use crate::pyobject::{BorrowValue, PyClassImpl, PyObjectRef, PyResult, PyStructSequence};
|
||||
use crate::vm::VirtualMachine;
|
||||
use std::convert::TryFrom;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
use nix::unistd::{self, User};
|
||||
|
||||
#[pystruct_sequence(module = "pwd", name = "struct_passwd")]
|
||||
#[pyclass(module = "pwd", name = "struct_passwd")]
|
||||
#[derive(PyStructSequence)]
|
||||
struct Passwd {
|
||||
pw_name: String,
|
||||
pw_passwd: String,
|
||||
@@ -18,6 +19,8 @@ struct Passwd {
|
||||
pw_dir: String,
|
||||
pw_shell: String,
|
||||
}
|
||||
#[pyimpl(with(PyStructSequence))]
|
||||
impl Passwd {}
|
||||
|
||||
impl From<User> for Passwd {
|
||||
fn from(user: User) -> Self {
|
||||
|
||||
@@ -972,7 +972,7 @@ pub(crate) fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
|
||||
let struct_error = ctx.new_class(
|
||||
"struct.error",
|
||||
&ctx.exceptions.exception_type,
|
||||
ctx.exceptions.exception_type.clone(),
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
|
||||
@@ -671,12 +671,12 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
let ctx = &vm.ctx;
|
||||
let socket_timeout = ctx.new_class(
|
||||
"socket.timeout",
|
||||
&vm.ctx.exceptions.os_error,
|
||||
vm.ctx.exceptions.os_error.clone(),
|
||||
Default::default(),
|
||||
);
|
||||
let socket_gaierror = ctx.new_class(
|
||||
"socket.gaierror",
|
||||
&vm.ctx.exceptions.os_error,
|
||||
vm.ctx.exceptions.os_error.clone(),
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
|
||||
@@ -757,7 +757,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
let ssl_error = create_type(
|
||||
"SSLError",
|
||||
&vm.ctx.types.type_type,
|
||||
&vm.ctx.exceptions.os_error,
|
||||
vm.ctx.exceptions.os_error.clone(),
|
||||
);
|
||||
let module = py_module!(vm, "_ssl", {
|
||||
"_SSLContext" => PySslContext::make_class(ctx),
|
||||
|
||||
@@ -11,7 +11,9 @@ use crate::function::OptionalArg;
|
||||
use crate::obj::objstr::PyStringRef;
|
||||
use crate::obj::objtuple::PyTupleRef;
|
||||
use crate::obj::objtype::PyClassRef;
|
||||
use crate::pyobject::{BorrowValue, Either, PyClassImpl, PyObjectRef, PyResult, TryFromObject};
|
||||
use crate::pyobject::{
|
||||
BorrowValue, Either, PyClassImpl, PyObjectRef, PyResult, PyStructSequence, TryFromObject,
|
||||
};
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -170,7 +172,8 @@ fn time_strptime(
|
||||
Ok(PyStructTime::new(vm, instant, -1).into_obj(vm))
|
||||
}
|
||||
|
||||
#[pystruct_sequence(with_pyimpl, module = "time", name = "struct_time")]
|
||||
#[pyclass(module = "time", name = "struct_time")]
|
||||
#[derive(PyStructSequence)]
|
||||
#[allow(dead_code)]
|
||||
struct PyStructTime {
|
||||
tm_year: PyObjectRef,
|
||||
@@ -190,7 +193,7 @@ impl fmt::Debug for PyStructTime {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(structseq_impl)]
|
||||
#[pyimpl(with(PyStructSequence))]
|
||||
impl PyStructTime {
|
||||
fn new(vm: &VirtualMachine, tm: NaiveDateTime, isdst: i32) -> Self {
|
||||
PyStructTime {
|
||||
|
||||
@@ -44,7 +44,7 @@ mod decl {
|
||||
create_type(
|
||||
"error",
|
||||
&vm.ctx.types.type_type,
|
||||
&vm.ctx.exceptions.exception_type,
|
||||
vm.ctx.exceptions.exception_type.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+20
-9
@@ -5,7 +5,9 @@ use crate::frame::FrameRef;
|
||||
use crate::function::{Args, OptionalArg, PyFuncArgs};
|
||||
use crate::obj::objstr::PyStringRef;
|
||||
use crate::obj::objtype::PyClassRef;
|
||||
use crate::pyobject::{IntoPyObject, ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyResult};
|
||||
use crate::pyobject::{
|
||||
IntoPyObject, ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyResult, PyStructSequence,
|
||||
};
|
||||
use crate::vm::{PySettings, VirtualMachine};
|
||||
use crate::{builtins, exceptions, py_io, version};
|
||||
use rustpython_common::hash::{PyHash, PyUHash};
|
||||
@@ -69,8 +71,8 @@ fn getframe(offset: OptionalArg<usize>, vm: &VirtualMachine) -> PyResult<FrameRe
|
||||
/// sys.flags
|
||||
///
|
||||
/// Flags provided through command line arguments or environment vars.
|
||||
#[pystruct_sequence(with_pyimpl, name = "flags", module = "sys")]
|
||||
#[derive(Default, Debug)]
|
||||
#[pyclass(name = "flags", module = "sys")]
|
||||
#[derive(Default, Debug, PyStructSequence)]
|
||||
struct SysFlags {
|
||||
/// -d
|
||||
debug: u8,
|
||||
@@ -104,7 +106,7 @@ struct SysFlags {
|
||||
utf8_mode: u8,
|
||||
}
|
||||
|
||||
#[pyimpl(structseq_impl)]
|
||||
#[pyimpl(with(PyStructSequence))]
|
||||
impl SysFlags {
|
||||
fn from_settings(settings: &PySettings) -> Self {
|
||||
// Start with sensible defaults:
|
||||
@@ -249,8 +251,8 @@ fn sys_displayhook(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pystruct_sequence(module = "sys", name = "getwindowsversion")]
|
||||
#[derive(Default, Debug)]
|
||||
#[pyclass(module = "sys", name = "getwindowsversion")]
|
||||
#[derive(Default, Debug, PyStructSequence)]
|
||||
#[cfg(windows)]
|
||||
struct WindowsVersion {
|
||||
major: u32,
|
||||
@@ -264,6 +266,9 @@ struct WindowsVersion {
|
||||
product_type: u8,
|
||||
platform_version: (u32, u32, u32),
|
||||
}
|
||||
#[cfg(windows)]
|
||||
#[pyimpl(with(PyStructSequence))]
|
||||
impl WindowsVersion {}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn sys_getwindowsversion(vm: &VirtualMachine) -> PyResult<crate::obj::objtuple::PyTupleRef> {
|
||||
@@ -364,7 +369,8 @@ pub fn sysconfigdata_name() -> String {
|
||||
format!("_sysconfigdata_{}_{}_{}", ABIFLAGS, PLATFORM, MULTIARCH)
|
||||
}
|
||||
|
||||
#[pystruct_sequence(module = "sys", name = "hash_info")]
|
||||
#[pyclass(module = "sys", name = "hash_info")]
|
||||
#[derive(PyStructSequence)]
|
||||
struct PyHashInfo {
|
||||
width: usize,
|
||||
modulus: PyUHash,
|
||||
@@ -376,6 +382,7 @@ struct PyHashInfo {
|
||||
seed_bits: usize,
|
||||
cutoff: usize,
|
||||
}
|
||||
#[pyimpl(with(PyStructSequence))]
|
||||
impl PyHashInfo {
|
||||
const INFO: Self = {
|
||||
use rustpython_common::hash::*;
|
||||
@@ -393,7 +400,8 @@ impl PyHashInfo {
|
||||
};
|
||||
}
|
||||
|
||||
#[pystruct_sequence(module = "sys", name = "float_info")]
|
||||
#[pyclass(module = "sys", name = "float_info")]
|
||||
#[derive(PyStructSequence)]
|
||||
struct PyFloatInfo {
|
||||
max: f64,
|
||||
max_exp: i32,
|
||||
@@ -407,6 +415,7 @@ struct PyFloatInfo {
|
||||
radix: u32,
|
||||
rounds: i32,
|
||||
}
|
||||
#[pyimpl(with(PyStructSequence))]
|
||||
impl PyFloatInfo {
|
||||
const INFO: Self = PyFloatInfo {
|
||||
max: f64::MAX,
|
||||
@@ -423,11 +432,13 @@ impl PyFloatInfo {
|
||||
};
|
||||
}
|
||||
|
||||
#[pystruct_sequence(module = "sys", name = "int_info")]
|
||||
#[pyclass(module = "sys", name = "int_info")]
|
||||
#[derive(PyStructSequence)]
|
||||
struct PyIntInfo {
|
||||
bits_per_digit: usize,
|
||||
sizeof_digit: usize,
|
||||
}
|
||||
#[pyimpl(with(PyStructSequence))]
|
||||
impl PyIntInfo {
|
||||
const INFO: Self = PyIntInfo {
|
||||
bits_per_digit: 30, //?
|
||||
|
||||
+6
-6
@@ -125,10 +125,10 @@ impl TypeZoo {
|
||||
|
||||
macro_rules! create_type {
|
||||
($class:ty) => {
|
||||
<$class>::create_bare_type(&type_type, &object_type)
|
||||
<$class>::create_bare_type(&type_type, object_type.clone())
|
||||
};
|
||||
($class:ty, $base:expr) => {
|
||||
<$class>::create_bare_type(&type_type, $base)
|
||||
<$class>::create_bare_type(&type_type, $base.clone())
|
||||
};
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ impl TypeZoo {
|
||||
async_generator_asend: create_type!(objasyncgenerator::PyAsyncGenASend),
|
||||
async_generator_athrow: create_type!(objasyncgenerator::PyAsyncGenAThrow),
|
||||
async_generator_wrapped_value: create_type!(objasyncgenerator::PyAsyncGenWrappedValue),
|
||||
bool_type: create_type!(objbool::PyBool, &int_type),
|
||||
bool_type: create_type!(objbool::PyBool, int_type),
|
||||
bound_method_type: create_type!(objfunction::PyBoundMethod),
|
||||
builtin_function_or_method_type: create_type!(objbuiltinfunc::PyBuiltinFunction),
|
||||
bytearray_type: create_type!(objbytearray::PyByteArray),
|
||||
@@ -201,14 +201,14 @@ impl TypeZoo {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_type(name: &str, type_type: &PyClassRef, base: &PyClassRef) -> PyClassRef {
|
||||
pub fn create_type(name: &str, type_type: &PyClassRef, base: PyClassRef) -> PyClassRef {
|
||||
create_type_with_slots(name, type_type, base, Default::default())
|
||||
}
|
||||
|
||||
pub fn create_type_with_slots(
|
||||
name: &str,
|
||||
type_type: &PyClassRef,
|
||||
base: &PyClassRef,
|
||||
base: PyClassRef,
|
||||
slots: PyClassSlots,
|
||||
) -> PyClassRef {
|
||||
let dict = PyAttributes::new();
|
||||
@@ -216,7 +216,7 @@ pub fn create_type_with_slots(
|
||||
type_type.clone(),
|
||||
name,
|
||||
base.clone(),
|
||||
vec![base.clone()],
|
||||
vec![base],
|
||||
dict,
|
||||
slots,
|
||||
)
|
||||
|
||||
+4
-3
@@ -1,6 +1,7 @@
|
||||
/* Several function to retrieve version information.
|
||||
*/
|
||||
|
||||
use crate::pyobject::PyStructSequence;
|
||||
use chrono::prelude::DateTime;
|
||||
use chrono::Local;
|
||||
use std::time::{Duration, UNIX_EPOCH};
|
||||
@@ -15,8 +16,8 @@ const SERIAL: usize = 0;
|
||||
pub const VERSION_HEX: usize =
|
||||
(MAJOR << 24) | (MINOR << 16) | (MICRO << 8) | (RELEASELEVEL_N << 4) | SERIAL;
|
||||
|
||||
#[pystruct_sequence(with_pyimpl, module = "sys", name = "version_info")]
|
||||
#[derive(Default, Debug)]
|
||||
#[pyclass(module = "sys", name = "version_info")]
|
||||
#[derive(Default, Debug, PyStructSequence)]
|
||||
pub struct VersionInfo {
|
||||
major: usize,
|
||||
minor: usize,
|
||||
@@ -34,7 +35,7 @@ pub fn get_version() -> String {
|
||||
)
|
||||
}
|
||||
|
||||
#[pyimpl(structseq_impl)]
|
||||
#[pyimpl(with(PyStructSequence))]
|
||||
impl VersionInfo {
|
||||
pub const VERSION: VersionInfo = VersionInfo {
|
||||
major: MAJOR,
|
||||
|
||||
@@ -255,7 +255,7 @@ fn new_js_error(vm: &VirtualMachine, err: JsValue) -> PyBaseExceptionRef {
|
||||
pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
let ctx = &vm.ctx;
|
||||
py_module!(vm, "_js", {
|
||||
"JsError" => create_type("JsError", &ctx.types.type_type, &ctx.exceptions.exception_type),
|
||||
"JsError" => create_type("JsError", &ctx.types.type_type, ctx.exceptions.exception_type.clone()),
|
||||
"JsValue" => PyJsValue::make_class(ctx),
|
||||
})
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user