Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 549cce2

Browse filesBrowse files
committed
Add #[pystruct(skip)]
1 parent 7ac90f5 commit 549cce2
Copy full SHA for 549cce2

File tree

3 files changed

+84
-24
lines changed
Filter options

3 files changed

+84
-24
lines changed

‎.cspell.json

Copy file name to clipboardExpand all lines: .cspell.json
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@
148148
"origname",
149149
"posixsubprocess",
150150
"pyexpat",
151+
"pytraverse",
151152
"PYTHONDEBUG",
152153
"PYTHONHOME",
153154
"PYTHONINSPECT",

‎derive-impl/src/pystructseq.rs

Copy file name to clipboardExpand all lines: derive-impl/src/pystructseq.rs
+81-22Lines changed: 81 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,93 @@
11
use proc_macro2::TokenStream;
22
use quote::quote;
33
use syn::{DeriveInput, Ident, Result};
4+
use syn_ext::ext::{AttributeExt, GetIdent};
5+
use syn_ext::types::Meta;
46

5-
fn field_names(input: &DeriveInput) -> Result<Vec<&Ident>> {
6-
let fields = if let syn::Data::Struct(ref struc) = input.data {
7-
&struc.fields
8-
} else {
7+
// returning a pair of not-skipped and skipped field names
8+
fn field_names(input: &mut DeriveInput) -> Result<(Vec<Ident>, Vec<Ident>)> {
9+
let syn::Data::Struct(struc) = &mut input.data else {
910
bail_span!(
1011
input,
1112
"#[pystruct_sequence] can only be on a struct declaration"
1213
)
1314
};
1415

15-
let field_names: Vec<_> = match fields {
16-
syn::Fields::Named(fields) => fields
17-
.named
18-
.iter()
19-
.map(|field| field.ident.as_ref().unwrap())
20-
.collect(),
21-
_ => bail_span!(
16+
let syn::Fields::Named(fields) = &mut struc.fields else {
17+
bail_span!(
2218
input,
2319
"#[pystruct_sequence] can only be on a struct with named fields"
24-
),
20+
);
2521
};
2622

27-
Ok(field_names)
23+
let mut not_skipped = Vec::with_capacity(fields.named.len());
24+
let mut skipped = Vec::with_capacity(fields.named.len());
25+
for field in &mut fields.named {
26+
let mut skip = false;
27+
// Collect all attributes with pystruct and their indices
28+
let mut attrs_to_remove = Vec::new();
29+
30+
for (i, attr) in field.attrs.iter().enumerate() {
31+
if !attr.path().is_ident("pystruct") {
32+
continue;
33+
}
34+
35+
let Ok(meta) = attr.parse_meta() else {
36+
continue;
37+
};
38+
39+
let Meta::List(l) = meta else {
40+
bail_span!(input, "Only #[pystruct(...)] form is allowed");
41+
};
42+
43+
let idents: Vec<_> = l
44+
.nested
45+
.iter()
46+
.filter_map(|n| n.get_ident())
47+
.cloned()
48+
.collect();
49+
50+
// Follow #[serde(skip)] convention.
51+
// Consider to add skip_serializing and skip_deserializing if required.
52+
for ident in idents {
53+
match ident.to_string().as_str() {
54+
"skip" => {
55+
skip = true;
56+
}
57+
_ => {
58+
bail_span!(ident, "Unknown item for #[pystruct(...)]")
59+
}
60+
}
61+
}
62+
63+
attrs_to_remove.push(i);
64+
}
65+
66+
// Remove attributes in reverse order to maintain valid indices
67+
attrs_to_remove.sort_unstable_by(|a, b| b.cmp(a)); // Sort in descending order
68+
for index in attrs_to_remove {
69+
field.attrs.remove(index);
70+
}
71+
let ident = field.ident.clone().unwrap();
72+
if skip {
73+
skipped.push(ident.clone());
74+
} else {
75+
not_skipped.push(ident.clone());
76+
}
77+
}
78+
79+
Ok((not_skipped, skipped))
2880
}
2981

30-
pub(crate) fn impl_pystruct_sequence(input: DeriveInput) -> Result<TokenStream> {
31-
let field_names = field_names(&input)?;
82+
pub(crate) fn impl_pystruct_sequence(mut input: DeriveInput) -> Result<TokenStream> {
83+
let (not_skipped_fields, _skipped_fields) = field_names(&mut input)?;
3284
let ty = &input.ident;
3385
let ret = quote! {
3486
impl ::rustpython_vm::types::PyStructSequence for #ty {
35-
const FIELD_NAMES: &'static [&'static str] = &[#(stringify!(#field_names)),*];
87+
const FIELD_NAMES: &'static [&'static str] = &[#(stringify!(#not_skipped_fields)),*];
3688
fn into_tuple(self, vm: &::rustpython_vm::VirtualMachine) -> ::rustpython_vm::builtins::PyTuple {
3789
let items = vec![#(::rustpython_vm::convert::ToPyObject::to_pyobject(
38-
self.#field_names,
90+
self.#not_skipped_fields,
3991
vm,
4092
)),*];
4193
::rustpython_vm::builtins::PyTuple::new_unchecked(items.into_boxed_slice())
@@ -50,8 +102,10 @@ pub(crate) fn impl_pystruct_sequence(input: DeriveInput) -> Result<TokenStream>
50102
Ok(ret)
51103
}
52104

53-
pub(crate) fn impl_pystruct_sequence_try_from_object(input: DeriveInput) -> Result<TokenStream> {
54-
let field_names = field_names(&input)?;
105+
pub(crate) fn impl_pystruct_sequence_try_from_object(
106+
mut input: DeriveInput,
107+
) -> Result<TokenStream> {
108+
let (not_skipped_fields, skipped_fields) = field_names(&mut input)?;
55109
let ty = &input.ident;
56110
let ret = quote! {
57111
impl ::rustpython_vm::TryFromObject for #ty {
@@ -60,9 +114,14 @@ pub(crate) fn impl_pystruct_sequence_try_from_object(input: DeriveInput) -> Resu
60114
let seq = Self::try_elements_from::<LEN>(seq, vm)?;
61115
// TODO: this is possible to be written without iterator
62116
let mut iter = seq.into_iter();
63-
Ok(Self {#(
64-
#field_names: iter.next().unwrap().clone().try_into_value(vm)?
65-
),*})
117+
Ok(Self {
118+
#(
119+
#not_skipped_fields: iter.next().unwrap().clone().try_into_value(vm)?,
120+
)*
121+
#(
122+
#skipped_fields: vm.ctx.none(),
123+
)*
124+
})
66125
}
67126
}
68127
};

‎derive/src/lib.rs

Copy file name to clipboardExpand all lines: derive/src/lib.rs
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,13 +225,13 @@ pub fn pymodule(attr: TokenStream, item: TokenStream) -> TokenStream {
225225
derive_impl::pymodule(attr, item).into()
226226
}
227227

228-
#[proc_macro_derive(PyStructSequence)]
228+
#[proc_macro_derive(PyStructSequence, attributes(pystruct))]
229229
pub fn pystruct_sequence(input: TokenStream) -> TokenStream {
230230
let input = parse_macro_input!(input);
231231
derive_impl::pystruct_sequence(input).into()
232232
}
233233

234-
#[proc_macro_derive(TryIntoPyStructSequence)]
234+
#[proc_macro_derive(TryIntoPyStructSequence, attributes(pystruct))]
235235
pub fn pystruct_sequence_try_from_object(input: TokenStream) -> TokenStream {
236236
let input = parse_macro_input!(input);
237237
derive_impl::pystruct_sequence_try_from_object(input).into()

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.