Attribute macro for Data structs: #[pystruct_sequence_data(...)] Generates: - `REQUIRED_FIELD_NAMES` constant (named visible fields) - `OPTIONAL_FIELD_NAMES` constant (hidden/skipped fields) - `UNNAMED_FIELDS_LEN` constant - `into_tuple()` method - Field index constants (e.g., `TM_YEAR_INDEX`) Options: - `try_from_object`: Generate `try_from_elements()` method and `TryFromObject` impl
(
attr: PunctuatedNestedMeta,
item: Item,
)
| 174 | /// Options: |
| 175 | /// - `try_from_object`: Generate `try_from_elements()` method and `TryFromObject` impl |
| 176 | pub(crate) fn impl_pystruct_sequence_data( |
| 177 | attr: PunctuatedNestedMeta, |
| 178 | item: Item, |
| 179 | ) -> Result<TokenStream> { |
| 180 | let Item::Struct(item_struct) = item else { |
| 181 | bail_span!( |
| 182 | item, |
| 183 | "#[pystruct_sequence_data] can only be applied to structs" |
| 184 | ); |
| 185 | }; |
| 186 | |
| 187 | let try_from_object = has_try_from_object(&attr); |
| 188 | let mut input: DeriveInput = DeriveInput { |
| 189 | attrs: item_struct.attrs.clone(), |
| 190 | vis: item_struct.vis.clone(), |
| 191 | ident: item_struct.ident.clone(), |
| 192 | generics: item_struct.generics.clone(), |
| 193 | data: syn::Data::Struct(syn::DataStruct { |
| 194 | struct_token: item_struct.struct_token, |
| 195 | fields: item_struct.fields.clone(), |
| 196 | semi_token: item_struct.semi_token, |
| 197 | }), |
| 198 | }; |
| 199 | let field_info = parse_fields(&mut input)?; |
| 200 | let data_ident = &input.ident; |
| 201 | |
| 202 | let named_fields = field_info.named_fields(); |
| 203 | let visible_fields = field_info.visible_fields(); |
| 204 | let skipped_fields = field_info.skipped_fields(); |
| 205 | let n_unnamed_fields = field_info.n_unnamed_fields(); |
| 206 | |
| 207 | // Generate field index constants for visible fields (with cfg guards) |
| 208 | let field_indices: Vec<_> = visible_fields |
| 209 | .iter() |
| 210 | .enumerate() |
| 211 | .map(|(i, field)| { |
| 212 | let const_name = format_ident!("{}_INDEX", field.ident.to_string().to_uppercase()); |
| 213 | let cfg_attrs = &field.cfg_attrs; |
| 214 | quote! { |
| 215 | #(#cfg_attrs)* |
| 216 | pub const #const_name: usize = #i; |
| 217 | } |
| 218 | }) |
| 219 | .collect(); |
| 220 | |
| 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 | } |
no test coverage detected