Skip to main content

cu29_soa_derive/
lib.rs

1use proc_macro::TokenStream;
2use quote::{ToTokens, format_ident, quote};
3use syn::{Attribute, Data, DeriveInput, Fields, Path, PathArguments, Type, parse_macro_input};
4
5/// Build a fixed sized SoA (Structure of Arrays) from a struct.
6/// The outputted SoA will be suitable for in place storage in messages and should be
7/// easier for the compiler to vectorize.
8///
9/// for example:
10///
11/// ```ignore
12/// #[derive(Soa)]
13/// struct MyStruct {
14///    a: i32,
15///    b: f32,
16/// }
17/// ```
18///
19/// will generate:
20/// ```ignore
21/// pub struct MyStructSoa<const N: usize> {
22///     pub a: [i32; N],
23///     pub b: [f32; N],
24/// }
25/// ```
26///
27/// You can then use the generated struct to store multiple
28/// instances of the original struct in an SoA format.
29///
30/// ```ignore
31/// // makes an SOA with a default value
32/// let soa1: MyStructSoa<8> = XyzSoa::new(MyStruct{ a: 1, b: 2.3 });
33/// ```
34///
35/// Then you can access the fields of the SoA as slices:
36/// ```ignore
37/// let a = soa1.a();
38/// let b = soa1.b();
39/// ```
40///
41/// You can also access a range of the fields:
42/// ```ignore
43/// let a = soa1.a_range(0..4);
44/// let b = soa1.b_range(0..4);
45/// ```
46///
47/// You can also modify the fields of the SoA:
48/// ```ignore
49/// soa1.a_mut()[0] = 42;
50/// soa1.b_mut()[0] = 42.0;
51/// ```
52///
53/// You can also modify a range of the fields:
54/// ```ignore
55/// soa1.a_range_mut(0..4)[0] = 42;
56/// soa1.b_range_mut(0..4)[0] = 42.0;
57/// ```
58///
59/// You can also apply a function to all the fields of the SoA:
60/// ```ignore
61/// soa1.apply(|a, b| {
62///    (a + 1, b + 1.0)
63/// });
64/// ```
65///
66/// You can also compose nested SoAs by annotating fields with `#[soa(nested)]`:
67/// ```ignore
68/// #[derive(Soa)]
69/// struct ColoredPoint {
70///     #[soa(nested)]
71///     position: Xyz,
72///     #[soa(nested)]
73///     color: Color,
74/// }
75/// // ColoredPointSoa<N> stores position as XyzSoaStorage<N> and color as ColorSoaStorage<N>.
76/// ```
77/// For nested types from other crates, use absolute paths like `::other_crate::Type`
78/// so the generated storage path resolves correctly.
79/// Type aliases are not supported for `#[soa(nested)]` because storage names are derived from the
80/// final type identifier.
81/// Bincode encoding changed: SoA fields no longer include per-field length prefixes. Old blobs are
82/// not compatible with the new layout.
83///
84/// Memory layout
85/// - Flat fields: `MyStructSoa<N>` stores `len` plus one `[T; N]` per field.
86/// - Nested fields (`#[soa(nested)]`): the field is stored inline as `<Field>SoaStorage<N>`,
87///   so the top-level struct contains `len` plus nested storage(s) and the leaf arrays live
88///   in those nested storages.
89/// - `*SoaStorage<N>` has the same layout as `*Soa<N>` without the `len` field.
90///
91/// ASCII layouts
92/// ```text
93/// Flat:
94///   MyStructSoa<N>
95///   +-----+------------------+------------------+
96///   | len | a: [i32; N]       | b: [f32; N]      |
97///   +-----+------------------+------------------+
98///
99/// Nested:
100///   ColoredPointSoa<N>
101///   +-----+---------------------+---------------------+
102///   | len | position: XyzSoaStorage<N> | color: ColorSoaStorage<N> |
103///   +-----+---------------------+---------------------+
104///                |                               |
105///                v                               v
106///        XyzSoaStorage<N>                 ColorSoaStorage<N>
107///        +------------------+             +------------------+
108///        | x: [f32; N]       |             | r: [f32; N]       |
109///        | y: [f32; N]       |             | g: [f32; N]       |
110///        | z: [f32; N]       |             | b: [f32; N]       |
111///        | i: [i32; N]       |             +------------------+
112///        +------------------+
113/// ```
114/// ```ignore
115/// struct ColoredPointSoa<const N: usize> {
116///     len: usize,
117///     position: XyzSoaStorage<N>,
118///     color: ColorSoaStorage<N>,
119/// }
120/// struct XyzSoaStorage<const N: usize> {
121///     x: [f32; N],
122///     y: [f32; N],
123///     z: [f32; N],
124///     i: [i32; N],
125/// }
126/// ```
127#[proc_macro_derive(Soa, attributes(soa))]
128pub fn derive_soa(input: TokenStream) -> TokenStream {
129    use syn::TypePath;
130
131    let input = parse_macro_input!(input as DeriveInput);
132    let visibility = &input.vis;
133    let derive_reflect = input
134        .attrs
135        .iter()
136        .any(|attr| attr.path().is_ident("reflect"));
137    let reflect_import = if derive_reflect {
138        quote!(
139            use super::{bevy_reflect, Reflect};
140        )
141    } else {
142        quote!()
143    };
144    let soa_reflect_attrs = if derive_reflect {
145        quote! {
146            #[derive(Reflect)]
147            #[reflect(from_reflect = false)]
148        }
149    } else {
150        quote!()
151    };
152
153    let name = &input.ident;
154    if let Some(lifetime) = input.generics.lifetimes().next() {
155        return syn::Error::new_spanned(lifetime, "lifetime parameters are not supported")
156            .to_compile_error()
157            .into();
158    }
159    if let Some(const_param) = input.generics.const_params().next() {
160        return syn::Error::new_spanned(const_param, "const parameters are not supported")
161            .to_compile_error()
162            .into();
163    }
164    if let Some(where_clause) = &input.generics.where_clause {
165        return syn::Error::new_spanned(where_clause, "where clauses are not supported")
166            .to_compile_error()
167            .into();
168    }
169    let ty_params: Vec<syn::TypeParam> = input
170        .generics
171        .type_params()
172        .cloned()
173        .map(|mut param| {
174            param.attrs.clear();
175            param.default = None;
176            param
177        })
178        .collect();
179    let ty_idents: Vec<syn::Ident> = ty_params.iter().map(|param| param.ident.clone()).collect();
180    // `N` is the generated capacity parameter.
181    if let Some(clashing) = ty_idents.iter().find(|ident| *ident == "N") {
182        return syn::Error::new_spanned(
183            clashing,
184            "a type parameter named `N` collides with the generated capacity parameter; rename it",
185        )
186        .to_compile_error()
187        .into();
188    }
189    let has_type_params = !ty_params.is_empty();
190
191    // Generic parameter lists for the generated items. With no type params on
192    // the input these collapse to today's `<const N: usize>` / `<N>` forms.
193    let soa_decl = quote!(<#(#ty_params,)* const N: usize>);
194    let soa_use = quote!(<#(#ty_idents,)* N>);
195    let iter_decl = quote!(<'a, #(#ty_params,)* const N: usize>);
196    let iter_use = quote!(<'a, #(#ty_idents,)* N>);
197    let iter_use_elided = quote!(<#(#ty_idents,)* N>);
198    let serde_decl = quote!(<'a, #(#ty_params,)* const N: usize>);
199    let serde_use = quote!(<'a, #(#ty_idents,)* N>);
200    let serde_use_anon = quote!(<'_, #(#ty_idents,)* N>);
201    let de_decl = quote!(<'de, #(#ty_params,)* const N: usize>);
202    let wire_decl = if has_type_params {
203        quote!(<#(#ty_params),*>)
204    } else {
205        quote!()
206    };
207    let wire_use = if has_type_params {
208        quote!(<#(#ty_idents),*>)
209    } else {
210        quote!()
211    };
212    let orig_ty = if has_type_params {
213        quote!(super::#name<#(#ty_idents),*>)
214    } else {
215        quote!(super::#name)
216    };
217    // Bounds on the input struct (e.g. `L: Copy + Debug`) may reference names
218    // from the parent scope, so pull that scope into the generated module.
219    let parent_scope_import = if has_type_params {
220        quote!(
221            #[allow(unused_imports)]
222            use super::*;
223        )
224    } else {
225        quote!()
226    };
227    let module_name = format_ident!("{}_soa", name.to_string().to_lowercase());
228    let soa_struct_name = format_ident!("{}Soa", name);
229    let soa_storage_name = format_ident!("{}SoaStorage", name);
230    let soa_storage_wire_name = format_ident!("{}SoaStorageWire", name);
231    let soa_storage_serde_name = format_ident!("{}SoaStorageSerde", name);
232    let soa_struct_wire_name = format_ident!("{}SoaWire", name);
233
234    let data = match &input.data {
235        Data::Struct(data) => data,
236        _ => {
237            return syn::Error::new_spanned(&input, "Only structs are supported")
238                .to_compile_error()
239                .into();
240        }
241    };
242    let fields = match &data.fields {
243        Fields::Named(fields) => &fields.named,
244        _ => {
245            return syn::Error::new_spanned(&data.fields, "Only named fields are supported")
246                .to_compile_error()
247                .into();
248        }
249    };
250
251    struct FieldInfo {
252        name: syn::Ident,
253        ty: syn::Type,
254        nested: bool,
255        storage_path: Option<syn::Path>,
256        storage_wire_path: Option<syn::Path>,
257    }
258
259    let mut field_infos = Vec::new();
260    let mut unique_imports = vec![];
261    let mut unique_import_names = vec![];
262
263    fn is_primitive(type_name: &str) -> bool {
264        matches!(
265            type_name,
266            "i8" | "i16"
267                | "i32"
268                | "i64"
269                | "i128"
270                | "u8"
271                | "u16"
272                | "u32"
273                | "u64"
274                | "u128"
275                | "f32"
276                | "f64"
277                | "bool"
278                | "char"
279                | "str"
280                | "usize"
281                | "isize"
282        )
283    }
284
285    fn parse_soa_nested(attrs: &[Attribute]) -> Result<bool, syn::Error> {
286        let mut nested = false;
287        for attr in attrs {
288            if attr.path().is_ident("soa") {
289                attr.parse_nested_meta(|meta| {
290                    if meta.path.is_ident("nested") {
291                        nested = true;
292                        Ok(())
293                    } else {
294                        Err(meta.error("unsupported #[soa] option, expected `nested`"))
295                    }
296                })?;
297            }
298        }
299        Ok(nested)
300    }
301
302    fn qualify_path(path: &Path) -> Path {
303        if path.leading_colon.is_some() {
304            return path.clone();
305        }
306        if let Some(first) = path.segments.first() {
307            if first.ident == "crate" {
308                return path.clone();
309            }
310            if first.ident == "self" {
311                let mut path = path.clone();
312                if let Some(segment) = path.segments.first_mut() {
313                    segment.ident = format_ident!("super");
314                }
315                return path;
316            }
317            if first.ident == "std" || first.ident == "core" || first.ident == "alloc" {
318                return path.clone();
319            }
320        }
321        syn::parse_quote!(super::#path)
322    }
323
324    fn storage_paths(field_type: &Type) -> Result<(Path, Path), syn::Error> {
325        let Type::Path(type_path) = field_type else {
326            return Err(syn::Error::new_spanned(
327                field_type,
328                "expected a path type for #[soa(nested)]",
329            ));
330        };
331
332        let mut storage_path = type_path.path.clone();
333        let last_segment = storage_path
334            .segments
335            .last_mut()
336            .ok_or_else(|| syn::Error::new_spanned(field_type, "expected a non-empty type path"))?;
337        if !matches!(last_segment.arguments, PathArguments::None) {
338            return Err(syn::Error::new_spanned(
339                field_type,
340                "generic types are not supported with #[soa(nested)]",
341            ));
342        }
343        let base_ident = last_segment.ident.clone();
344        last_segment.ident = format_ident!("{}SoaStorage", base_ident);
345
346        let mut storage_wire_path = type_path.path.clone();
347        let last_wire_segment = storage_wire_path
348            .segments
349            .last_mut()
350            .ok_or_else(|| syn::Error::new_spanned(field_type, "expected a non-empty type path"))?;
351        last_wire_segment.ident = format_ident!("{}SoaStorageWire", base_ident);
352
353        Ok((
354            qualify_path(&storage_path),
355            qualify_path(&storage_wire_path),
356        ))
357    }
358
359    for field in fields {
360        let field_name = match &field.ident {
361            Some(ident) => ident.clone(),
362            None => {
363                return syn::Error::new_spanned(field, "Only named fields are supported")
364                    .to_compile_error()
365                    .into();
366            }
367        };
368        let field_type = field.ty.clone();
369        let nested = match parse_soa_nested(&field.attrs) {
370            Ok(value) => value,
371            Err(err) => return err.to_compile_error().into(),
372        };
373        if nested && has_type_params {
374            return syn::Error::new_spanned(
375                field,
376                "#[soa(nested)] is not supported on generic structs",
377            )
378            .to_compile_error()
379            .into();
380        }
381        let (storage_path, storage_wire_path) = if nested {
382            match storage_paths(&field_type) {
383                Ok((storage_path, storage_wire_path)) => {
384                    (Some(storage_path), Some(storage_wire_path))
385                }
386                Err(err) => return err.to_compile_error().into(),
387            }
388        } else {
389            (None, None)
390        };
391
392        if let Type::Path(TypePath { path, .. }) = &field_type {
393            let Some(last_segment) = path.segments.last() else {
394                return syn::Error::new_spanned(path, "expected a non-empty type path")
395                    .to_compile_error()
396                    .into();
397            };
398            let type_name = last_segment.ident.to_string();
399            let path_str = path.to_token_stream().to_string();
400            let is_type_param = path.segments.len() == 1
401                && path.leading_colon.is_none()
402                && ty_idents.contains(&last_segment.ident);
403
404            if !is_primitive(&type_name)
405                && !is_type_param
406                && !unique_import_names.contains(&path_str)
407            {
408                unique_imports.push(path.clone());
409                unique_import_names.push(path_str);
410            }
411        }
412
413        field_infos.push(FieldInfo {
414            name: field_name,
415            ty: field_type,
416            nested,
417            storage_path,
418            storage_wire_path,
419        });
420    }
421
422    let field_names: Vec<_> = field_infos.iter().map(|info| &info.name).collect();
423    let field_types: Vec<_> = field_infos.iter().map(|info| &info.ty).collect();
424
425    let soa_struct_name_iterator = format_ident!("{}Iterator", name);
426    let storage_field_count = field_names.len();
427    let field_count = storage_field_count + 1; // +1 for the len field
428
429    // Shared between storage and soa (identical generated code)
430    let mut field_decls = Vec::new();
431    let mut new_inits = Vec::new();
432    let mut default_inits = Vec::new();
433    let mut get_fields = Vec::new();
434    let mut set_fields = Vec::new();
435    let mut accessors = Vec::new();
436
437    // Soa-only fields
438    let mut soa_push_fields = Vec::new();
439    let mut soa_pop_fields = Vec::new();
440    let mut soa_apply_args = Vec::new();
441    let mut soa_apply_sets = Vec::new();
442    let mut soa_encode_fields = Vec::new();
443    let mut soa_decode_fields = Vec::new();
444    let mut soa_serialize_fields = Vec::new();
445    let mut soa_serialize_bounds = Vec::new();
446    let mut soa_deserialize_bounds = Vec::new();
447    let mut soa_wire_fields = Vec::new();
448    let mut soa_wire_checks = Vec::new();
449    let mut soa_wire_assignments = Vec::new();
450
451    // Bounds the generated impls need on generic field types; empty for
452    // non-generic inputs so their output is unchanged.
453    let mut generic_method_bounds = Vec::new();
454    let mut generic_encode_bounds = Vec::new();
455    let mut generic_decode_bounds = Vec::new();
456    let mut generic_default_bounds = Vec::new();
457
458    // Storage-only fields
459    let mut storage_encode_fields = Vec::new();
460    let mut storage_decode_fields = Vec::new();
461    let mut storage_serialize_fields = Vec::new();
462    let mut storage_serialize_bounds = Vec::new();
463    let mut storage_clone_bounds = Vec::new();
464    let mut storage_wire_fields = Vec::new();
465    let mut storage_wire_checks = Vec::new();
466    let mut storage_wire_assignments = Vec::new();
467
468    for info in &field_infos {
469        let name = &info.name;
470        let ty = &info.ty;
471        let name_mut = format_ident!("{}_mut", name);
472
473        if info.nested {
474            let storage_path = info
475                .storage_path
476                .as_ref()
477                .expect("nested field missing storage path");
478            let storage_wire_path = info
479                .storage_wire_path
480                .as_ref()
481                .expect("nested field missing storage wire path");
482            let serde_name = format_ident!("{}_serde", name);
483
484            field_decls.push(quote!(pub #name: #storage_path<N>));
485            new_inits.push(quote!(#name: #storage_path::<N>::new(default.#name.clone())));
486            default_inits.push(quote!(#name: #storage_path::<N>::default()));
487            storage_clone_bounds.push(quote!(#storage_path<N>: Clone,));
488
489            accessors.push(quote! {
490                pub fn #name(&self) -> &#storage_path<N> {
491                    &self.#name
492                }
493
494                pub fn #name_mut(&mut self) -> &mut #storage_path<N> {
495                    &mut self.#name
496                }
497            });
498
499            get_fields.push(quote!(#name: self.#name.get(index),));
500            set_fields.push(quote!(self.#name.set(index, value.#name.clone());));
501
502            soa_push_fields.push(quote!(self.#name.set(self.len, value.#name.clone());));
503            soa_pop_fields.push(quote!(#name: self.#name.get(self.len),));
504
505            soa_apply_args.push(quote!(self.#name.get(_idx)));
506            soa_apply_sets.push(quote!(self.#name.set(_idx, #name);));
507
508            storage_encode_fields.push(quote!(self.#name.encode_len(encoder, len)?;));
509            storage_decode_fields
510                .push(quote!(result.#name = #storage_path::<N>::decode_len(decoder, len)?;));
511
512            soa_encode_fields.push(quote!(self.#name.encode_len(encoder, self.len)?;));
513            soa_decode_fields
514                .push(quote!(result.#name = #storage_path::<N>::decode_len(decoder, result.len)?;));
515
516            storage_serialize_fields.push(quote! {
517                {
518                    let #serde_name = self.storage.#name.serialize_len(self.len);
519                    state.serialize_field(stringify!(#name), &#serde_name)?;
520                }
521            });
522            soa_serialize_fields.push(quote! {
523                {
524                    let #serde_name = self.#name.serialize_len(self.len);
525                    state.serialize_field(stringify!(#name), &#serde_name)?;
526                }
527            });
528
529            storage_wire_fields.push(quote!(#name: #storage_wire_path,));
530            storage_wire_assignments.push(quote!(
531                result.#name = #storage_path::<N>::from_wire(#name, len)
532                    .map_err(|err| format!("field {}: {}", stringify!(#name), err))?;
533            ));
534
535            soa_wire_fields.push(quote!(#name: #storage_wire_path,));
536            soa_wire_assignments.push(quote!(
537                result.#name = #storage_path::<N>::from_wire(#name, len)
538                    .map_err(|err| serde::de::Error::custom(format!(
539                        "field {}: {}",
540                        stringify!(#name),
541                        err
542                    )))?;
543            ));
544        } else {
545            let name_range = format_ident!("{}_range", name);
546            let name_range_mut = format_ident!("{}_range_mut", name);
547
548            field_decls.push(quote!(pub #name: [#ty; N]));
549            new_inits.push(quote!(#name: from_fn(|_| default.#name.clone())));
550            default_inits.push(quote!(#name: from_fn(|_| #ty::default())));
551            storage_clone_bounds.push(quote!(#ty: Clone,));
552            if has_type_params {
553                generic_method_bounds.push(quote!(#ty: Clone + Default,));
554                generic_encode_bounds.push(quote!(#ty: Encode,));
555                generic_decode_bounds.push(quote!(#ty: Decode<()> + Default,));
556                generic_default_bounds.push(quote!(#ty: Default,));
557            }
558
559            accessors.push(quote! {
560                pub fn #name(&self) -> &[#ty] {
561                    &self.#name
562                }
563
564                pub fn #name_mut(&mut self) -> &mut [#ty] {
565                    &mut self.#name
566                }
567
568                pub fn #name_range(&self, range: core::ops::Range<usize>) -> &[#ty] {
569                    &self.#name[range]
570                }
571
572                pub fn #name_range_mut(&mut self, range: core::ops::Range<usize>) -> &mut [#ty] {
573                    &mut self.#name[range]
574                }
575            });
576
577            get_fields.push(quote!(#name: self.#name[index].clone(),));
578            set_fields.push(quote!(self.#name[index] = value.#name.clone();));
579
580            soa_push_fields.push(quote!(self.#name[self.len] = value.#name.clone();));
581            soa_pop_fields.push(quote!(#name: self.#name[self.len].clone(),));
582
583            soa_apply_args.push(quote!(self.#name[_idx].clone()));
584            soa_apply_sets.push(quote!(self.#name[_idx] = #name;));
585
586            storage_encode_fields.push(quote! {
587                for _idx in 0..len {
588                    Encode::encode(&self.#name[_idx], encoder)?;
589                }
590            });
591            storage_decode_fields.push(quote! {
592                for _idx in 0..len {
593                    result.#name[_idx] = Decode::decode(decoder)?;
594                }
595            });
596
597            soa_encode_fields.push(quote! {
598                for _idx in 0..self.len {
599                    Encode::encode(&self.#name[_idx], encoder)?;
600                }
601            });
602            soa_decode_fields.push(quote! {
603                for _idx in 0..result.len {
604                    result.#name[_idx] = Decode::decode(decoder)?;
605                }
606            });
607
608            storage_serialize_fields.push(quote! {
609                state.serialize_field(stringify!(#name), &self.storage.#name[..self.len])?;
610            });
611            soa_serialize_fields.push(quote! {
612                state.serialize_field(stringify!(#name), &self.#name[..self.len])?;
613            });
614
615            storage_serialize_bounds.push(quote!(#ty: Serialize,));
616            soa_serialize_bounds.push(quote!(#ty: Serialize,));
617            soa_deserialize_bounds.push(quote!(#ty: Deserialize<'de> + Default,));
618
619            storage_wire_fields.push(quote!(#name: Vec<#ty>,));
620            storage_wire_checks.push(quote! {
621                if #name.len() != len {
622                    return Err(format!(
623                        "field {} has length {} but len is {}",
624                        stringify!(#name),
625                        #name.len(),
626                        len
627                    ));
628                }
629            });
630            storage_wire_assignments.push(quote! {
631                for (idx, value) in #name.into_iter().enumerate() {
632                    result.#name[idx] = value;
633                }
634            });
635
636            soa_wire_fields.push(quote!(#name: Vec<#ty>,));
637            soa_wire_checks.push(quote! {
638                if #name.len() != len {
639                    return Err(serde::de::Error::custom(format!(
640                        "field {} has length {} but len is {}",
641                        stringify!(#name),
642                        #name.len(),
643                        len
644                    )));
645                }
646            });
647            soa_wire_assignments.push(quote! {
648                for (idx, value) in #name.into_iter().enumerate() {
649                    result.#name[idx] = value;
650                }
651            });
652        }
653    }
654
655    let storage_clone_where = if storage_clone_bounds.is_empty() {
656        quote!()
657    } else {
658        quote!(where #(#storage_clone_bounds)*)
659    };
660    let storage_serialize_where = if storage_serialize_bounds.is_empty() {
661        quote!()
662    } else {
663        quote!(where #(#storage_serialize_bounds)*)
664    };
665    let soa_serialize_where = if soa_serialize_bounds.is_empty() {
666        quote!()
667    } else {
668        quote!(where #(#soa_serialize_bounds)*)
669    };
670    let soa_deserialize_where = if soa_deserialize_bounds.is_empty() {
671        quote!()
672    } else {
673        quote!(where #(#soa_deserialize_bounds)*)
674    };
675    let methods_where = if generic_method_bounds.is_empty() {
676        quote!()
677    } else {
678        quote!(where #(#generic_method_bounds)*)
679    };
680    let storage_methods_where = if generic_method_bounds.is_empty() {
681        quote!()
682    } else {
683        quote!(where #(#generic_method_bounds)* #(#generic_encode_bounds)* #(#generic_decode_bounds)*)
684    };
685    let encode_where = if generic_encode_bounds.is_empty() {
686        quote!()
687    } else {
688        quote!(where #(#generic_encode_bounds)*)
689    };
690    let decode_where = if generic_decode_bounds.is_empty() {
691        quote!()
692    } else {
693        quote!(where #(#generic_decode_bounds)*)
694    };
695    let default_where = if generic_default_bounds.is_empty() {
696        quote!()
697    } else {
698        quote!(where #(#generic_default_bounds)*)
699    };
700
701    let iterator = quote! {
702        pub struct #soa_struct_name_iterator #iter_decl {
703            soa_struct: &'a #soa_struct_name #soa_use,
704            current: usize,
705        }
706
707        impl #iter_decl #soa_struct_name_iterator #iter_use
708        #methods_where
709        {
710            pub fn new(soa_struct: &'a #soa_struct_name #soa_use) -> Self {
711                Self {
712                    soa_struct,
713                    current: 0,
714                }
715            }
716        }
717
718        impl #iter_decl Iterator for #soa_struct_name_iterator #iter_use
719        #methods_where
720        {
721            type Item = #orig_ty;
722
723            fn next(&mut self) -> Option<Self::Item> {
724                if self.current < self.soa_struct.len {
725                    let item = self.soa_struct.get(self.current); // Reuse `get` method
726                    self.current += 1;
727                    Some(item)
728                } else {
729                    None
730                }
731            }
732        }
733    };
734
735    let expanded = quote! {
736        #visibility mod #module_name {
737            extern crate alloc;
738            use self::alloc::format;
739            use self::alloc::string::String;
740            use self::alloc::vec::Vec;
741            use bincode::{Decode, Encode};
742            use bincode::enc::Encoder;
743            use bincode::de::Decoder;
744            use bincode::error::{DecodeError, EncodeError};
745            use serde::Deserialize;
746            use serde::Serialize;
747            use serde::Serializer;
748            use serde::ser::SerializeStruct;
749            #parent_scope_import
750            #( use super::#unique_imports; )*
751            #reflect_import
752            use core::array::from_fn;
753
754            #[derive(Debug)]
755            #visibility struct #soa_storage_name #soa_decl {
756                #(#field_decls,)*
757            }
758
759            #[doc(hidden)]
760            #[derive(Deserialize)]
761            #visibility struct #soa_storage_wire_name #wire_decl {
762                #(#storage_wire_fields)*
763            }
764
765            #[doc(hidden)]
766            #visibility struct #soa_storage_serde_name #serde_decl {
767                storage: &'a #soa_storage_name #soa_use,
768                len: usize,
769            }
770
771            impl #soa_decl #soa_storage_name #soa_use
772            #storage_methods_where
773            {
774                pub fn new(default: #orig_ty) -> Self {
775                    Self {
776                        #(#new_inits,)*
777                    }
778                }
779
780                pub fn set(&mut self, index: usize, value: #orig_ty) {
781                    assert!(index < N, "Index out of bounds");
782                    #(#set_fields)*
783                }
784
785                pub fn get(&self, index: usize) -> #orig_ty {
786                    assert!(index < N, "Index out of bounds");
787                    super::#name {
788                        #(#get_fields)*
789                    }
790                }
791
792                pub fn encode_len<E: Encoder>(
793                    &self,
794                    encoder: &mut E,
795                    len: usize,
796                ) -> Result<(), EncodeError> {
797                    #(#storage_encode_fields)*
798                    Ok(())
799                }
800
801                pub fn decode_len<D: Decoder<Context = ()>>(
802                    decoder: &mut D,
803                    len: usize,
804                ) -> Result<Self, DecodeError> {
805                    if len > N {
806                        return Err(DecodeError::ArrayLengthMismatch {
807                            required: N,
808                            found: len,
809                        });
810                    }
811                    let mut result = Self::default();
812                    #(#storage_decode_fields)*
813                    Ok(result)
814                }
815
816                pub fn serialize_len(&self, len: usize) -> #soa_storage_serde_name #serde_use_anon {
817                    #soa_storage_serde_name {
818                        storage: self,
819                        len,
820                    }
821                }
822
823                pub fn from_wire(wire: #soa_storage_wire_name #wire_use, len: usize) -> Result<Self, String> {
824                    let #soa_storage_wire_name { #( #field_names ),* } = wire;
825
826                    if len > N {
827                        return Err(format!(
828                            "len {} exceeds capacity {}",
829                            len,
830                            N
831                        ));
832                    }
833
834                    #(#storage_wire_checks)*
835
836                    let mut result = Self::default();
837                    #(#storage_wire_assignments)*
838                    Ok(result)
839                }
840
841                #(#accessors)*
842            }
843
844            impl #serde_decl Serialize for #soa_storage_serde_name #serde_use
845            #storage_serialize_where
846            {
847                fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
848                where
849                    S: Serializer,
850                {
851                    let mut state = serializer.serialize_struct(
852                        stringify!(#soa_storage_name),
853                        #storage_field_count,
854                    )?;
855                    #(#storage_serialize_fields)*
856                    state.end()
857                }
858            }
859
860            impl #soa_decl Default for #soa_storage_name #soa_use
861            #default_where
862            {
863                fn default() -> Self {
864                    Self {
865                        #(#default_inits,)*
866                    }
867                }
868            }
869
870            impl #soa_decl Clone for #soa_storage_name #soa_use
871            #storage_clone_where
872            {
873                fn clone(&self) -> Self {
874                    Self {
875                        #( #field_names: self.#field_names.clone(), )*
876                    }
877                }
878            }
879
880            #[derive(Debug)]
881            #soa_reflect_attrs
882            #visibility struct #soa_struct_name #soa_decl {
883                pub len: usize,
884                #(#field_decls,)*
885            }
886
887            // Kept free of the field bounds so callers don't inherit them
888            // just to ask for a length.
889            impl #soa_decl #soa_struct_name #soa_use {
890                pub fn len(&self) -> usize {
891                    self.len
892                }
893
894                pub fn is_empty(&self) -> bool {
895                    self.len == 0
896                }
897            }
898
899            impl #soa_decl #soa_struct_name #soa_use
900            #methods_where
901            {
902                pub fn new(default: #orig_ty) -> Self {
903                    Self {
904                        #(#new_inits,)*
905                        len: 0,
906                    }
907                }
908
909                pub fn push(&mut self, value: #orig_ty) {
910                    if self.len < N {
911                        #(#soa_push_fields)*
912                        self.len += 1;
913                    } else {
914                        panic!("Capacity exceeded")
915                    }
916                }
917
918                pub fn pop(&mut self) -> Option<#orig_ty> {
919                    if self.len == 0 {
920                        None
921                    } else {
922                        self.len -= 1;
923                        Some(super::#name {
924                            #(#soa_pop_fields)*
925                        })
926                    }
927                }
928
929                pub fn set(&mut self, index: usize, value: #orig_ty) {
930                    assert!(index < self.len, "Index out of bounds");
931                    #(#set_fields)*
932                }
933
934                pub fn get(&self, index: usize) -> #orig_ty {
935                    assert!(index < self.len, "Index out of bounds");
936                    super::#name {
937                        #(#get_fields)*
938                    }
939                }
940
941                pub fn apply<F>(&mut self, mut f: F)
942                where
943                    F: FnMut(#(#field_types),*) -> (#(#field_types),*)
944                {
945                    // don't use something common like i here.
946                    for _idx in 0..self.len {
947                        let result = f(#(#soa_apply_args),*);
948                        let (#(#field_names),*) = result;
949                        #(#soa_apply_sets)*
950                    }
951                }
952
953                pub fn iter(&self) -> #soa_struct_name_iterator #iter_use_elided {
954                    #soa_struct_name_iterator::new(self)
955                }
956
957                #(#accessors)*
958            }
959
960            impl #soa_decl Encode for #soa_struct_name #soa_use
961            #encode_where
962            {
963                fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
964                    Encode::encode(&self.len, encoder)?;
965                    #(#soa_encode_fields)*
966                    Ok(())
967                }
968            }
969
970            impl #soa_decl Decode<()> for #soa_struct_name #soa_use
971            #decode_where
972            {
973                fn decode<D: Decoder<Context = ()>>(decoder: &mut D) -> Result<Self, DecodeError> {
974                    let mut result = Self::default();
975                    result.len = Decode::decode(decoder)?;
976                    // `len` comes off the wire; check it before indexing.
977                    if result.len > N {
978                        return Err(DecodeError::ArrayLengthMismatch {
979                            required: N,
980                            found: result.len,
981                        });
982                    }
983                    #(#soa_decode_fields)*
984                    Ok(result)
985                }
986            }
987
988            impl #soa_decl Default for #soa_struct_name #soa_use
989            #default_where
990            {
991                fn default() -> Self {
992                    Self {
993                        #(#default_inits,)*
994                        len: 0,
995                    }
996                }
997            }
998
999            impl #soa_decl Clone for #soa_struct_name #soa_use
1000            #storage_clone_where
1001            {
1002                fn clone(&self) -> Self {
1003                    Self {
1004                        #( #field_names: self.#field_names.clone(), )*
1005                        len: self.len,
1006                    }
1007                }
1008            }
1009
1010            impl #soa_decl Serialize for #soa_struct_name #soa_use
1011            #soa_serialize_where
1012            {
1013                fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1014                where
1015                    S: Serializer,
1016                {
1017                    let mut state =
1018                        serializer.serialize_struct(stringify!(#soa_struct_name), #field_count)?;
1019                    state.serialize_field("len", &self.len)?;
1020                    #(#soa_serialize_fields)*
1021                    state.end()
1022                }
1023            }
1024
1025            impl #de_decl Deserialize<'de> for #soa_struct_name #soa_use
1026            #soa_deserialize_where
1027            {
1028                fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1029                where
1030                    D: serde::Deserializer<'de>,
1031                {
1032                    #[derive(Deserialize)]
1033                    struct #soa_struct_wire_name #wire_decl {
1034                        len: usize,
1035                        #(#soa_wire_fields)*
1036                    }
1037
1038                    let wire = #soa_struct_wire_name::deserialize(deserializer)?;
1039                    let #soa_struct_wire_name { len, #( #field_names ),* } = wire;
1040
1041                    if len > N {
1042                        return Err(serde::de::Error::custom(format!(
1043                            "len {} exceeds capacity {}",
1044                            len,
1045                            N
1046                        )));
1047                    }
1048
1049                    #(#soa_wire_checks)*
1050
1051                    let mut result = Self::default();
1052                    result.len = len;
1053                    #(#soa_wire_assignments)*
1054                    Ok(result)
1055                }
1056            }
1057
1058            #iterator
1059        }
1060        #visibility use #module_name::#soa_struct_name;
1061        #visibility use #module_name::#soa_storage_name;
1062        #visibility use #module_name::#soa_storage_wire_name;
1063        #visibility use #module_name::#soa_struct_name_iterator;
1064    };
1065
1066    let tokens: TokenStream = expanded.into();
1067
1068    tokens
1069}