Make PyMethodDef construction const (#5117)

* Make PyMethodDef construction const

* Remove iter_chain![]

Obsolete since arrays now impl IntoIterator
This commit is contained in:
Noa
2023-11-14 21:52:47 -06:00
committed by GitHub
parent 6d23daa480
commit 87cf891e50
7 changed files with 148 additions and 84 deletions

View File

@@ -4,7 +4,7 @@ use crate::util::{
ClassItemMeta, ContentItem, ContentItemInner, ErrorVec, ExceptionItemMeta, ItemMeta,
ItemMetaInner, ItemNursery, SimpleItemMeta, ALL_ALLOWED_NAMES,
};
use proc_macro2::{Span, TokenStream};
use proc_macro2::{Delimiter, Group, Span, TokenStream, TokenTree};
use quote::{quote, quote_spanned, ToTokens};
use std::collections::{HashMap, HashSet};
use std::str::FromStr;
@@ -172,14 +172,9 @@ pub(crate) fn impl_pyclass_impl(attr: AttributeArgs, item: Item) -> Result<Token
let slots_impl = context.extend_slots_items.validate()?;
let class_extensions = &context.class_extensions;
let extra_methods = iter_chain![
let extra_methods = [
parse_quote! {
#[allow(clippy::ptr_arg)]
fn __extend_method_def(
method_defs: &mut Vec<::rustpython_vm::function::PyMethodDef>,
) {
#method_def
}
const __OWN_METHOD_DEFS: &'static [::rustpython_vm::function::PyMethodDef] = &#method_def;
},
parse_quote! {
fn __extend_py_class(
@@ -201,6 +196,15 @@ pub(crate) fn impl_pyclass_impl(attr: AttributeArgs, item: Item) -> Result<Token
imp.items.extend(extra_methods);
let is_main_impl = impl_ty == payload_ty;
if is_main_impl {
let method_defs = if with_method_defs.is_empty() {
quote!(#impl_ty::__OWN_METHOD_DEFS)
} else {
quote!(
rustpython_vm::function::PyMethodDef::__const_concat_arrays::<
{ #impl_ty::__OWN_METHOD_DEFS.len() #(+ #with_method_defs.len())* },
>(&[#impl_ty::__OWN_METHOD_DEFS, #(#with_method_defs,)*])
)
};
quote! {
#imp
impl ::rustpython_vm::class::PyClassImpl for #payload_ty {
@@ -214,13 +218,7 @@ pub(crate) fn impl_pyclass_impl(attr: AttributeArgs, item: Item) -> Result<Token
#with_impl
}
#[allow(clippy::ptr_arg)]
fn impl_extend_method_def(
method_defs: &mut Vec<::rustpython_vm::function::PyMethodDef>,
) {
#impl_ty::__extend_method_def(method_defs);
#with_method_defs
}
const METHOD_DEFS: &'static [::rustpython_vm::function::PyMethodDef] = &#method_defs;
fn extend_slots(slots: &mut ::rustpython_vm::types::PyTypeSlots) {
#impl_ty::__extend_slots(slots);
@@ -268,14 +266,9 @@ pub(crate) fn impl_pyclass_impl(attr: AttributeArgs, item: Item) -> Result<Token
} else {
quote! {}
};
let extra_methods = iter_chain![
let extra_methods = [
parse_quote! {
#[allow(clippy::ptr_arg)]
fn __extend_method_def(
method_defs: &mut Vec<::rustpython_vm::function::PyMethodDef>,
) {
#method_def
}
const __OWN_METHOD_DEFS: &'static [::rustpython_vm::function::PyMethodDef] = &#method_def;
},
parse_quote! {
fn __extend_py_class(
@@ -983,6 +976,7 @@ impl MethodNursery {
impl ToTokens for MethodNursery {
fn to_tokens(&self, tokens: &mut TokenStream) {
let mut inner_tokens = TokenStream::new();
for item in &self.items {
let py_name = &item.py_name;
let ident = &item.ident;
@@ -1011,16 +1005,18 @@ impl ToTokens for MethodNursery {
// } else {
// quote_spanned! { ident.span() => #py_name }
// };
tokens.extend(quote! {
inner_tokens.extend(quote! [
#(#cfgs)*
method_defs.push(rustpython_vm::function::PyMethodDef {
name: #py_name,
func: rustpython_vm::function::IntoPyNativeFn::into_func(Self::#ident),
flags: #flags,
doc: #doc,
});
});
rustpython_vm::function::PyMethodDef::new_const(
#py_name,
Self::#ident,
#flags,
#doc,
),
]);
}
let array: TokenTree = Group::new(Delimiter::Bracket, inner_tokens).into();
tokens.extend([array]);
}
}
@@ -1436,7 +1432,7 @@ struct ExtractedImplAttrs {
payload: Option<Ident>,
flags: TokenStream,
with_impl: TokenStream,
with_method_defs: TokenStream,
with_method_defs: Vec<TokenStream>,
with_slots: TokenStream,
}
@@ -1465,18 +1461,18 @@ fn extract_impl_attrs(attr: AttributeArgs, item: &Ident) -> Result<ExtractedImpl
let NestedMeta::Meta(Meta::Path(path)) = meta else {
bail_span!(meta, "#[pyclass(with(...))] arguments should be paths")
};
let (extend_class, extend_method_def, extend_slots) =
let (extend_class, method_defs, extend_slots) =
if path.is_ident("PyRef") || path.is_ident("Py") {
// special handling for PyRef
(
quote!(#path::<Self>::__extend_py_class),
quote!(#path::<Self>::__extend_method_def),
quote!(#path::<Self>::__OWN_METHOD_DEFS),
quote!(#path::<Self>::__extend_slots),
)
} else {
(
quote!(<Self as #path>::__extend_py_class),
quote!(<Self as #path>::__extend_method_def),
quote!(<Self as #path>::__OWN_METHOD_DEFS),
quote!(<Self as #path>::__extend_slots),
)
};
@@ -1484,9 +1480,7 @@ fn extract_impl_attrs(attr: AttributeArgs, item: &Ident) -> Result<ExtractedImpl
withs.push(quote_spanned! { path.span() =>
#extend_class(ctx, class);
});
with_method_defs.push(quote_spanned! { path.span() =>
#extend_method_def(method_defs);
});
with_method_defs.push(method_defs);
with_slots.push(quote_spanned! { item_span =>
#extend_slots(slots);
});
@@ -1530,9 +1524,7 @@ fn extract_impl_attrs(attr: AttributeArgs, item: &Ident) -> Result<ExtractedImpl
with_impl: quote! {
#(#withs)*
},
with_method_defs: quote! {
#(#with_method_defs)*
},
with_method_defs,
with_slots: quote! {
#(#with_slots)*
},

View File

@@ -4,7 +4,7 @@ use crate::util::{
AttributeExt, ClassItemMeta, ContentItem, ContentItemInner, ErrorVec, ItemMeta, ItemNursery,
ModuleItemMeta, SimpleItemMeta, ALL_ALLOWED_NAMES,
};
use proc_macro2::TokenStream;
use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
use quote::{quote, quote_spanned, ToTokens};
use std::{collections::HashSet, str::FromStr};
use syn::{parse_quote, spanned::Spanned, Attribute, AttributeArgs, Ident, Item, Result};
@@ -110,7 +110,7 @@ pub fn impl_pymodule(attr: AttributeArgs, module_item: Item) -> Result<TokenStre
let is_submodule = module_meta.sub()?;
let withs = module_meta.with()?;
if !is_submodule {
items.extend(iter_chain![
items.extend([
parse_quote! {
pub(crate) const MODULE_NAME: &'static str = #module_name;
},
@@ -122,16 +122,10 @@ pub fn impl_pymodule(attr: AttributeArgs, module_item: Item) -> Result<TokenStre
ctx: &::rustpython_vm::Context,
) -> &'static ::rustpython_vm::builtins::PyModuleDef {
DEF.get_or_init(|| {
#[allow(clippy::ptr_arg)]
let method_defs = {
let mut method_defs = Vec::new();
extend_method_def(ctx, &mut method_defs);
method_defs
};
let mut def = ::rustpython_vm::builtins::PyModuleDef {
name: ctx.intern_str(MODULE_NAME),
doc: DOC.map(|doc| ctx.intern_str(doc)),
methods: Box::leak(method_defs.into_boxed_slice()),
methods: METHOD_DEFS,
slots: Default::default(),
};
def.slots.exec = Some(extend_module);
@@ -161,23 +155,24 @@ pub fn impl_pymodule(attr: AttributeArgs, module_item: Item) -> Result<TokenStre
}
});
}
items.extend(iter_chain![
let method_defs = if withs.is_empty() {
quote!(#function_items)
} else {
quote!({
const OWN_METHODS: &'static [::rustpython_vm::function::PyMethodDef] = &#function_items;
rustpython_vm::function::PyMethodDef::__const_concat_arrays::<
{ OWN_METHODS.len() #(+ super::#withs::METHOD_DEFS.len())* },
>(&[#(super::#withs::METHOD_DEFS,)* OWN_METHODS])
})
};
items.extend([
parse_quote! {
::rustpython_vm::common::static_cell! {
pub(crate) static DEF: ::rustpython_vm::builtins::PyModuleDef;
}
},
parse_quote! {
#[allow(clippy::ptr_arg)]
pub(crate) fn extend_method_def(
ctx: &::rustpython_vm::Context,
method_defs: &mut Vec<::rustpython_vm::function::PyMethodDef>,
) {
#(
super::#withs::extend_method_def(ctx, method_defs);
)*
#function_items
}
pub(crate) const METHOD_DEFS: &'static [::rustpython_vm::function::PyMethodDef] = &#method_defs;
},
parse_quote! {
pub(crate) fn __init_attributes(
@@ -361,26 +356,30 @@ struct ValidatedFunctionNursery(FunctionNursery);
impl ToTokens for ValidatedFunctionNursery {
fn to_tokens(&self, tokens: &mut TokenStream) {
let mut inner_tokens = TokenStream::new();
let flags = quote! { rustpython_vm::function::PyMethodFlags::empty() };
for item in &self.0.items {
let ident = &item.ident;
let cfgs = &item.cfgs;
let cfgs = quote!(#(#cfgs)*);
let py_names = &item.py_names;
let doc = &item.doc;
let flags = quote! { rustpython_vm::function::PyMethodFlags::empty() };
let doc = quote!(Some(#doc));
tokens.extend(quote! {
#(#cfgs)*
{
let doc = Some(#doc);
#(method_defs.push(rustpython_vm::function::PyMethodDef::new(
(#py_names),
inner_tokens.extend(quote![
#(
#cfgs
rustpython_vm::function::PyMethodDef::new_const(
#py_names,
#ident,
#flags,
doc,
));)*
}
});
#doc,
),
)*
]);
}
let array: TokenTree = Group::new(Delimiter::Bracket, inner_tokens).into();
tokens.extend([array]);
}
}

View File

@@ -639,13 +639,6 @@ impl ErrorVec for Vec<syn::Error> {
}
}
macro_rules! iter_chain {
($($it:expr),*$(,)?) => {
::std::iter::empty()
$(.chain(::std::iter::once($it)))*
};
}
pub(crate) fn iter_use_idents<'a, F, R: 'a>(item_use: &'a syn::ItemUse, mut f: F) -> Result<Vec<R>>
where
F: FnMut(&'a syn::Ident, bool) -> Result<R>,