@@ -22,6 +22,8 @@ enum FieldKind {
2222struct ParsedField {
2323 ident : Ident ,
2424 kind : FieldKind ,
25+ /// Optional cfg attributes for conditional compilation
26+ cfg_attrs : Vec < syn:: Attribute > ,
2527}
2628
2729/// Parsed field info from struct
@@ -31,27 +33,24 @@ struct FieldInfo {
3133}
3234
3335impl FieldInfo {
34- fn named_fields ( & self ) -> Vec < Ident > {
36+ fn named_fields ( & self ) -> Vec < & ParsedField > {
3537 self . fields
3638 . iter ( )
3739 . filter ( |f| f. kind == FieldKind :: Named )
38- . map ( |f| f. ident . clone ( ) )
3940 . collect ( )
4041 }
4142
42- fn visible_fields ( & self ) -> Vec < Ident > {
43+ fn visible_fields ( & self ) -> Vec < & ParsedField > {
4344 self . fields
4445 . iter ( )
4546 . filter ( |f| f. kind != FieldKind :: Skipped )
46- . map ( |f| f. ident . clone ( ) )
4747 . collect ( )
4848 }
4949
50- fn skipped_fields ( & self ) -> Vec < Ident > {
50+ fn skipped_fields ( & self ) -> Vec < & ParsedField > {
5151 self . fields
5252 . iter ( )
5353 . filter ( |f| f. kind == FieldKind :: Skipped )
54- . map ( |f| f. ident . clone ( ) )
5554 . collect ( )
5655 }
5756
@@ -82,8 +81,15 @@ fn parse_fields(input: &mut DeriveInput) -> Result<FieldInfo> {
8281 let mut skip = false ;
8382 let mut unnamed = false ;
8483 let mut attrs_to_remove = Vec :: new ( ) ;
84+ let mut cfg_attrs = Vec :: new ( ) ;
8585
8686 for ( i, attr) in field. attrs . iter ( ) . enumerate ( ) {
87+ // Collect cfg attributes for conditional compilation
88+ if attr. path ( ) . is_ident ( "cfg" ) {
89+ cfg_attrs. push ( attr. clone ( ) ) ;
90+ continue ;
91+ }
92+
8793 if !attr. path ( ) . is_ident ( "pystruct_sequence" ) {
8894 continue ;
8995 }
@@ -135,7 +141,11 @@ fn parse_fields(input: &mut DeriveInput) -> Result<FieldInfo> {
135141 FieldKind :: Named
136142 } ;
137143
138- parsed_fields. push ( ParsedField { ident, kind } ) ;
144+ parsed_fields. push ( ParsedField {
145+ ident,
146+ kind,
147+ cfg_attrs,
148+ } ) ;
139149 }
140150
141151 Ok ( FieldInfo {
@@ -194,18 +204,91 @@ pub(crate) fn impl_pystruct_sequence_data(
194204 let skipped_fields = field_info. skipped_fields ( ) ;
195205 let n_unnamed_fields = field_info. n_unnamed_fields ( ) ;
196206
197- // Generate field index constants for visible fields
207+ // Generate field index constants for visible fields (with cfg guards)
198208 let field_indices: Vec < _ > = visible_fields
199209 . iter ( )
200210 . enumerate ( )
201211 . map ( |( i, field) | {
202- let const_name = format_ident ! ( "{}_INDEX" , field. to_string( ) . to_uppercase( ) ) ;
212+ let const_name = format_ident ! ( "{}_INDEX" , field. ident. to_string( ) . to_uppercase( ) ) ;
213+ let cfg_attrs = & field. cfg_attrs ;
203214 quote ! {
215+ #( #cfg_attrs) *
204216 pub const #const_name: usize = #i;
205217 }
206218 } )
207219 . collect ( ) ;
208220
221+ // Generate field name entries with cfg guards for named fields
222+ let named_field_names: Vec < _ > = named_fields
223+ . iter ( )
224+ . map ( |f| {
225+ let ident = & f. ident ;
226+ let cfg_attrs = & f. cfg_attrs ;
227+ if cfg_attrs. is_empty ( ) {
228+ quote ! { stringify!( #ident) , }
229+ } else {
230+ quote ! {
231+ #( #cfg_attrs) *
232+ { stringify!( #ident) } ,
233+ }
234+ }
235+ } )
236+ . collect ( ) ;
237+
238+ // Generate field name entries with cfg guards for skipped fields
239+ let skipped_field_names: Vec < _ > = skipped_fields
240+ . iter ( )
241+ . map ( |f| {
242+ let ident = & f. ident ;
243+ let cfg_attrs = & f. cfg_attrs ;
244+ if cfg_attrs. is_empty ( ) {
245+ quote ! { stringify!( #ident) , }
246+ } else {
247+ quote ! {
248+ #( #cfg_attrs) *
249+ { stringify!( #ident) } ,
250+ }
251+ }
252+ } )
253+ . collect ( ) ;
254+
255+ // Generate into_tuple items with cfg guards
256+ let visible_tuple_items: Vec < _ > = visible_fields
257+ . iter ( )
258+ . map ( |f| {
259+ let ident = & f. ident ;
260+ let cfg_attrs = & f. cfg_attrs ;
261+ if cfg_attrs. is_empty ( ) {
262+ quote ! {
263+ :: rustpython_vm:: convert:: ToPyObject :: to_pyobject( self . #ident, vm) ,
264+ }
265+ } else {
266+ quote ! {
267+ #( #cfg_attrs) *
268+ { :: rustpython_vm:: convert:: ToPyObject :: to_pyobject( self . #ident, vm) } ,
269+ }
270+ }
271+ } )
272+ . collect ( ) ;
273+
274+ let skipped_tuple_items: Vec < _ > = skipped_fields
275+ . iter ( )
276+ . map ( |f| {
277+ let ident = & f. ident ;
278+ let cfg_attrs = & f. cfg_attrs ;
279+ if cfg_attrs. is_empty ( ) {
280+ quote ! {
281+ :: rustpython_vm:: convert:: ToPyObject :: to_pyobject( self . #ident, vm) ,
282+ }
283+ } else {
284+ quote ! {
285+ #( #cfg_attrs) *
286+ { :: rustpython_vm:: convert:: ToPyObject :: to_pyobject( self . #ident, vm) } ,
287+ }
288+ }
289+ } )
290+ . collect ( ) ;
291+
209292 // Generate TryFromObject impl only when try_from_object=true
210293 let try_from_object_impl = if try_from_object {
211294 let n_required = visible_fields. len ( ) ;
@@ -233,15 +316,17 @@ pub(crate) fn impl_pystruct_sequence_data(
233316
234317 // Generate try_from_elements trait override only when try_from_object=true
235318 let try_from_elements_trait_override = if try_from_object {
319+ let visible_field_idents: Vec < _ > = visible_fields. iter ( ) . map ( |f| & f. ident ) . collect ( ) ;
320+ let skipped_field_idents: Vec < _ > = skipped_fields. iter ( ) . map ( |f| & f. ident ) . collect ( ) ;
236321 quote ! {
237322 fn try_from_elements(
238323 elements: Vec <:: rustpython_vm:: PyObjectRef >,
239324 vm: & :: rustpython_vm:: VirtualMachine ,
240325 ) -> :: rustpython_vm:: PyResult <Self > {
241326 let mut iter = elements. into_iter( ) ;
242327 Ok ( Self {
243- #( #visible_fields : iter. next( ) . unwrap( ) . clone( ) . try_into_value( vm) ?, ) *
244- #( #skipped_fields : match iter. next( ) {
328+ #( #visible_field_idents : iter. next( ) . unwrap( ) . clone( ) . try_into_value( vm) ?, ) *
329+ #( #skipped_field_idents : match iter. next( ) {
245330 Some ( v) => v. clone( ) . try_into_value( vm) ?,
246331 None => vm. ctx. none( ) ,
247332 } , ) *
@@ -259,20 +344,14 @@ pub(crate) fn impl_pystruct_sequence_data(
259344
260345 // PyStructSequenceData trait impl
261346 impl :: rustpython_vm:: types:: PyStructSequenceData for #data_ident {
262- const REQUIRED_FIELD_NAMES : & ' static [ & ' static str ] = & [ #( stringify! ( #named_fields ) , ) * ] ;
263- const OPTIONAL_FIELD_NAMES : & ' static [ & ' static str ] = & [ #( stringify! ( #skipped_fields ) , ) * ] ;
347+ const REQUIRED_FIELD_NAMES : & ' static [ & ' static str ] = & [ #( #named_field_names ) * ] ;
348+ const OPTIONAL_FIELD_NAMES : & ' static [ & ' static str ] = & [ #( #skipped_field_names ) * ] ;
264349 const UNNAMED_FIELDS_LEN : usize = #n_unnamed_fields;
265350
266351 fn into_tuple( self , vm: & :: rustpython_vm:: VirtualMachine ) -> :: rustpython_vm:: builtins:: PyTuple {
267352 let items = vec![
268- #( :: rustpython_vm:: convert:: ToPyObject :: to_pyobject(
269- self . #visible_fields,
270- vm,
271- ) , ) *
272- #( :: rustpython_vm:: convert:: ToPyObject :: to_pyobject(
273- self . #skipped_fields,
274- vm,
275- ) , ) *
353+ #( #visible_tuple_items) *
354+ #( #skipped_tuple_items) *
276355 ] ;
277356 :: rustpython_vm:: builtins:: PyTuple :: new_unchecked( items. into_boxed_slice( ) )
278357 }
0 commit comments