Skip to main content

mirage_engine_derive/
lib.rs

1//! The derive macros behind Mirage's vocabulary traits, which the engine
2//! makes public; nothing here depends on the engine itself.
3
4use proc_macro::TokenStream;
5
6use quote::{format_ident, quote};
7use syn::punctuated::Punctuated;
8use syn::{
9    Attribute, Data, DeriveInput, Expr, Fields, Ident, LitStr, Path, Token, parse_macro_input,
10    parse_quote,
11};
12
13/// The block a shader reads a set of values in: what each of them starts
14/// on, and what the whole of them fills.
15const BLOCK: usize = 16;
16
17/// The parts of a mesh, named by the materials a source states.
18const PART: Named = Named {
19    trait_name: "Part",
20    what: "part",
21};
22
23/// The clips of a mesh, named by the animations a source states.
24const CLIP: Named = Named {
25    trait_name: "Clip",
26    what: "clip",
27};
28
29/// Derives `Catalog` for a mesh vocabulary: every value the engine builds
30/// before the game's startup closure runs, to prove the assets it names
31/// are loaded.
32///
33/// Fieldless variants catalog themselves. A variant with fields needs one
34/// `#[catalog(...)]` naming the values to prove, each written as a value of
35/// the type, and omitting it fails to compile:
36/// `#[catalog(Self::Asteroid { seed: 1 }, Self::Asteroid { seed: 7 })]`.
37/// Wrap a primitive in a variant's field only when each of its values is its
38/// own mesh; a variant that draws one fixed primitive stays fieldless and
39/// builds it in `build`.
40#[proc_macro_derive(Catalog, attributes(catalog))]
41pub fn derive_catalog(input: TokenStream) -> TokenStream {
42    let input = parse_macro_input!(input as DeriveInput);
43    match catalog_impl(&input) {
44        Ok(implementation) => implementation,
45        Err(error) => error.to_compile_error().into(),
46    }
47}
48
49fn catalog_impl(input: &DeriveInput) -> syn::Result<TokenStream> {
50    let name = &input.ident;
51    let values = match &input.data {
52        Data::Enum(data) => data
53            .variants
54            .iter()
55            .map(|variant| {
56                let variant_name = &variant.ident;
57                cataloged(
58                    &parse_quote!(#name::#variant_name),
59                    &variant.fields,
60                    &variant.attrs,
61                    variant_name,
62                )
63            })
64            .collect::<syn::Result<Vec<_>>>()?
65            .concat(),
66        Data::Struct(data) => cataloged(&parse_quote!(#name), &data.fields, &input.attrs, name)?,
67        Data::Union(_) => {
68            return Err(syn::Error::new_spanned(
69                name,
70                "Catalog covers enums and structs; a union needs the impl written by hand",
71            ));
72        }
73    };
74
75    let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
76    Ok(quote! {
77        impl #impl_generics ::mirage_engine::Catalog for #name #type_generics #where_clause {
78            fn catalog() -> ::std::vec::Vec<Self> {
79                ::std::vec![#(#values),*]
80            }
81        }
82    }
83    .into())
84}
85
86/// The values `#[catalog(…)]` names for one variant or struct, or the value
87/// it is on its own when it has no fields.
88fn cataloged(
89    path: &Path,
90    fields: &Fields,
91    attributes: &[Attribute],
92    name: &Ident,
93) -> syn::Result<Vec<Expr>> {
94    let mut declared = attributes
95        .iter()
96        .filter(|attribute| attribute.path().is_ident("catalog"));
97    let Some(attribute) = declared.next() else {
98        return match fields {
99            Fields::Unit => Ok(vec![parse_quote!(#path)]),
100            _ => Err(syn::Error::new_spanned(
101                name,
102                format!(
103                    "`{name}` has fields, so each value of it is a mesh of its own: name a value \
104                     of the type in `#[catalog({}, …)]`",
105                    representative(path, fields)
106                ),
107            )),
108        };
109    };
110    if let Some(extra) = declared.next() {
111        return Err(syn::Error::new_spanned(
112            extra,
113            format!(
114                "`{name}` names its values in one `#[catalog(…)]`; drop the attribute past the \
115                 first"
116            ),
117        ));
118    }
119    if matches!(fields, Fields::Unit) {
120        return Err(syn::Error::new_spanned(
121            attribute,
122            format!("`{name}` has no fields, so it catalogs itself; drop the attribute"),
123        ));
124    }
125
126    let values: Vec<Expr> = attribute
127        .parse_args_with(Punctuated::<Expr, Token![,]>::parse_terminated)?
128        .into_iter()
129        .collect();
130    match values.is_empty() {
131        true => Err(syn::Error::new_spanned(
132            attribute,
133            format!(
134                "`{name}` names no value; give the attribute a value of the type, `{}`",
135                representative(path, fields)
136            ),
137        )),
138        false => Ok(values),
139    }
140}
141
142/// One value of the item, written the way the attribute would name it, for
143/// the error that requests the attribute.
144fn representative(path: &Path, fields: &Fields) -> String {
145    let spelled = path
146        .segments
147        .iter()
148        .map(|segment| segment.ident.to_string())
149        .collect::<Vec<_>>()
150        .join("::");
151    let each: Vec<String> = fields
152        .iter()
153        .map(|field| match &field.ident {
154            Some(field) => format!("{field}: …"),
155            None => "…".to_owned(),
156        })
157        .collect();
158    match fields {
159        Fields::Named(_) => format!("{spelled} {{ {} }}", each.join(", ")),
160        _ => format!("{spelled}({})", each.join(", ")),
161    }
162}
163
164/// Derives `Part` for a vocabulary of mesh parts: each fieldless variant
165/// (and a unit struct) is named by what it is called in code, or by
166/// `#[part("...")]` when the loaded material name cannot be written as one
167/// — repeat the attribute for other spellings. The variants are numbered
168/// in order, which is the position a draw's override of one is stored at.
169///
170/// A variant with fields fails to compile: a part is a plain name.
171#[proc_macro_derive(Part, attributes(part))]
172pub fn derive_part(input: TokenStream) -> TokenStream {
173    let input = parse_macro_input!(input as DeriveInput);
174    match named_impl(&input, &PART) {
175        Ok(implementation) => implementation,
176        Err(error) => error.to_compile_error().into(),
177    }
178}
179
180/// Derives `Clip` for a vocabulary of the clips a mesh is posed by: each
181/// fieldless variant (and a unit struct) is named by what it is called in
182/// code, or by `#[clip("...")]` when the loaded animation name cannot be
183/// written as one — repeat the attribute for other spellings. The variants
184/// are numbered in order.
185///
186/// A variant with fields fails to compile: a clip is a plain name.
187#[proc_macro_derive(Clip, attributes(clip))]
188pub fn derive_clip(input: TokenStream) -> TokenStream {
189    let input = parse_macro_input!(input as DeriveInput);
190    match named_impl(&input, &CLIP) {
191        Ok(implementation) => implementation,
192        Err(error) => error.to_compile_error().into(),
193    }
194}
195
196/// A vocabulary whose every value is one name a loaded source states: the
197/// trait to write, and the attribute and the word its errors spell it with.
198struct Named {
199    trait_name: &'static str,
200    what: &'static str,
201}
202
203fn named_impl(input: &DeriveInput, named: &Named) -> syn::Result<TokenStream> {
204    let name = &input.ident;
205    let parts = match &input.data {
206        Data::Enum(data) => data
207            .variants
208            .iter()
209            .map(|variant| {
210                let variant_name = &variant.ident;
211                spellings(
212                    &parse_quote!(#name::#variant_name),
213                    &variant.fields,
214                    &variant.attrs,
215                    variant_name,
216                    named,
217                )
218            })
219            .collect::<syn::Result<Vec<_>>>()?,
220        Data::Struct(data) => vec![spellings(
221            &parse_quote!(#name),
222            &data.fields,
223            &input.attrs,
224            name,
225            named,
226        )?],
227        Data::Union(_) => {
228            let trait_name = named.trait_name;
229            return Err(syn::Error::new_spanned(
230                name,
231                format!(
232                    "{trait_name} covers enums and unit structs; a union needs the impl written \
233                     by hand"
234                ),
235            ));
236        }
237    };
238
239    let every = parts.iter().map(|(key, _)| key);
240    let indices = 0u32..parts.len() as u32;
241    let indexed = parts.iter().map(|(key, _)| key);
242    let (modelled, keys): (Vec<&LitStr>, Vec<&Expr>) = parts
243        .iter()
244        .flat_map(|(key, names)| names.iter().map(move |spelling| (spelling, key)))
245        .unzip();
246
247    let trait_name = format_ident!("{}", named.trait_name);
248    let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
249    Ok(quote! {
250        impl #impl_generics ::mirage_engine::#trait_name for #name #type_generics #where_clause {
251            fn from_name(name: &str) -> ::core::option::Option<Self> {
252                match name {
253                    #(#modelled => ::core::option::Option::Some(#keys),)*
254                    _ => ::core::option::Option::None,
255                }
256            }
257
258            fn all() -> ::std::vec::Vec<Self> {
259                ::std::vec![#(#every),*]
260            }
261
262            fn index(&self) -> u32 {
263                match self {
264                    #(#indexed => #indices,)*
265                }
266            }
267        }
268    }
269    .into())
270}
271
272/// One variant or struct: the value it is, and the names that resolve to
273/// it — whatever `#[part("...")]` or `#[clip("...")]` spells, or what it is
274/// called in code.
275fn spellings(
276    path: &Path,
277    fields: &Fields,
278    attributes: &[Attribute],
279    name: &Ident,
280    named: &Named,
281) -> syn::Result<(Expr, Vec<LitStr>)> {
282    let what = named.what;
283    if !matches!(fields, Fields::Unit) {
284        return Err(syn::Error::new_spanned(
285            name,
286            format!("`{name}` has fields, but a {what} is a plain name; give it none"),
287        ));
288    }
289
290    let declared: Vec<LitStr> = attributes
291        .iter()
292        .filter(|attribute| attribute.path().is_ident(what))
293        .map(Attribute::parse_args)
294        .collect::<syn::Result<_>>()?;
295
296    let names = match declared.is_empty() {
297        true => vec![LitStr::new(&name.to_string(), name.span())],
298        false => declared,
299    };
300    Ok((parse_quote!(#path), names))
301}
302
303/// Derives the engine's view of a vocabulary of actions whose value is held
304/// or not: its values, and the names a rebind of one is kept under.
305///
306/// The bindings themselves are declared by hand in the `InputButtonAction`
307/// trait, which the derived code calls; a variant with fields fails to compile,
308/// because an action is a verb and its parameters belong to the game's own
309/// state.
310#[proc_macro_derive(InputButtonAction)]
311pub fn derive_input_button_action(input: TokenStream) -> TokenStream {
312    let input = parse_macro_input!(input as DeriveInput);
313    emit(
314        &input,
315        &parse_quote!(::mirage_engine::ButtonBinding),
316        &parse_quote!(::mirage_engine::InputButtonAction),
317        "NoInputButtons",
318    )
319}
320
321/// Derives the engine's view of a vocabulary of actions whose value is a
322/// number, whose bindings are declared by hand in the `InputAxisAction` trait; see
323/// [`InputButtonAction`](macro@InputButtonAction).
324#[proc_macro_derive(InputAxisAction)]
325pub fn derive_input_axis_action(input: TokenStream) -> TokenStream {
326    let input = parse_macro_input!(input as DeriveInput);
327    emit(
328        &input,
329        &parse_quote!(::mirage_engine::AxisBinding),
330        &parse_quote!(::mirage_engine::InputAxisAction),
331        "NoInputAxes",
332    )
333}
334
335/// Derives the engine's view of a vocabulary of actions whose value is a
336/// vector, whose bindings are declared by hand in the `InputAxis2Action`
337/// trait; see
338/// [`InputButtonAction`](macro@InputButtonAction).
339#[proc_macro_derive(InputAxis2Action)]
340pub fn derive_input_axis2_action(input: TokenStream) -> TokenStream {
341    let input = parse_macro_input!(input as DeriveInput);
342    emit(
343        &input,
344        &parse_quote!(::mirage_engine::Axis2Binding),
345        &parse_quote!(::mirage_engine::InputAxis2Action),
346        "NoInputAxes2",
347    )
348}
349
350fn emit(input: &DeriveInput, binding: &Path, kind: &Path, empty: &str) -> TokenStream {
351    match actions(input, binding, kind, empty) {
352        Ok(implementation) => implementation,
353        Err(error) => error.to_compile_error().into(),
354    }
355}
356
357fn actions(
358    input: &DeriveInput,
359    binding: &Path,
360    kind: &Path,
361    empty: &str,
362) -> syn::Result<TokenStream> {
363    let name = &input.ident;
364    let verbs: Vec<(Path, &Ident)> = match &input.data {
365        Data::Enum(data) => data
366            .variants
367            .iter()
368            .map(|variant| {
369                let variant_name = &variant.ident;
370                verb(
371                    parse_quote!(#name::#variant_name),
372                    &variant.fields,
373                    variant_name,
374                )
375            })
376            .collect::<syn::Result<_>>()?,
377        Data::Struct(data) => vec![verb(parse_quote!(#name), &data.fields, name)?],
378        Data::Union(_) => {
379            return Err(syn::Error::new_spanned(
380                name,
381                "an action vocabulary is an enum or a unit struct; a union needs the impl \
382                 written by hand",
383            ));
384        }
385    };
386    if verbs.is_empty() {
387        return Err(syn::Error::new_spanned(
388            name,
389            format!("`{name}` names no action; the vocabulary of none is `mirage_engine::{empty}`"),
390        ));
391    }
392
393    let (paths, idents): (Vec<&Path>, Vec<&Ident>) =
394        verbs.iter().map(|(path, ident)| (path, *ident)).unzip();
395    let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
396    Ok(quote! {
397        impl #impl_generics ::mirage_engine::InputAction for #name #type_generics #where_clause {
398            type Binding = #binding;
399
400            fn defaults(&self) -> ::std::vec::Vec<#binding> {
401                <Self as #kind>::bindings(self)
402            }
403
404            fn all() -> ::std::vec::Vec<Self> {
405                ::std::vec![#(#paths),*]
406            }
407
408            fn name(&self) -> &'static str {
409                match self {
410                    #(#paths => ::core::stringify!(#idents),)*
411                }
412            }
413
414            fn from_name(name: &str) -> ::core::option::Option<Self> {
415                match name {
416                    #(::core::stringify!(#idents) => ::core::option::Option::Some(#paths),)*
417                    _ => ::core::option::Option::None,
418                }
419            }
420        }
421    }
422    .into())
423}
424
425/// One action: the value it is, and what it is called in code.
426fn verb<'a>(path: Path, fields: &Fields, name: &'a Ident) -> syn::Result<(Path, &'a Ident)> {
427    fieldless(
428        fields,
429        name,
430        "an action is a plain verb; move what varies into the game's own state",
431    )?;
432    Ok((path, name))
433}
434
435/// Derives the engine's view of a vocabulary of keys a game keeps between
436/// runs: its values, and the name the store keeps each of them under — the
437/// vocabulary's own name, `.`, and the value's name.
438///
439/// The value a key keeps, and its fallback before any run has saved one,
440/// are declared by hand in `SaveKey`; a variant with fields fails to
441/// compile, because a key is a plain name.
442#[proc_macro_derive(Saves)]
443pub fn derive_saves(input: TokenStream) -> TokenStream {
444    let input = parse_macro_input!(input as DeriveInput);
445    match saves(&input) {
446        Ok(implementation) => implementation,
447        Err(error) => error.to_compile_error().into(),
448    }
449}
450
451fn saves(input: &DeriveInput) -> syn::Result<TokenStream> {
452    let name = &input.ident;
453    let keys: Vec<(Path, LitStr)> = match &input.data {
454        Data::Enum(data) => data
455            .variants
456            .iter()
457            .map(|variant| {
458                let variant_name = &variant.ident;
459                kept(
460                    parse_quote!(#name::#variant_name),
461                    &variant.fields,
462                    variant_name,
463                    &format!("{name}.{variant_name}"),
464                )
465            })
466            .collect::<syn::Result<_>>()?,
467        Data::Struct(data) => vec![kept(
468            parse_quote!(#name),
469            &data.fields,
470            name,
471            &name.to_string(),
472        )?],
473        Data::Union(_) => {
474            return Err(syn::Error::new_spanned(
475                name,
476                "a save vocabulary is an enum or a unit struct; a union needs the impl written \
477                 by hand",
478            ));
479        }
480    };
481
482    let (paths, names): (Vec<&Path>, Vec<&LitStr>) =
483        keys.iter().map(|(path, name)| (path, name)).unzip();
484    let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
485    Ok(quote! {
486        impl #impl_generics ::mirage_engine::Saves for #name #type_generics #where_clause {
487            fn name(&self) -> &'static str {
488                match *self {
489                    #(#paths => #names,)*
490                }
491            }
492        }
493    }
494    .into())
495}
496
497/// One key: the value it is, and the name `under` the store keeps it.
498fn kept(path: Path, fields: &Fields, name: &Ident, under: &str) -> syn::Result<(Path, LitStr)> {
499    fieldless(
500        fields,
501        name,
502        "a save key is a plain name; move what varies into what it keeps",
503    )?;
504    Ok((path, LitStr::new(under, name.span())))
505}
506
507/// Errors on the fields a vocabulary of plain names has none of.
508fn fieldless(fields: &Fields, name: &Ident, complaint: &str) -> syn::Result<()> {
509    match fields {
510        Fields::Unit => Ok(()),
511        _ => Err(syn::Error::new_spanned(
512            name,
513            format!("`{name}` has fields, but {complaint}"),
514        )),
515    }
516}
517
518/// Derives `ShaderValues` for the values a style's or an effect's WGSL
519/// reads: the WGSL struct declaring them, and the layout writing each of
520/// them where that struct reads it.
521///
522/// The WGSL struct takes the Rust type's own name and each field its own,
523/// in the order they were written; a field of any other type than these
524/// fails to compile, and a type with no fields reads no values and binds
525/// none.
526///
527/// | Rust   | WGSL                                          |
528/// |--------|-----------------------------------------------|
529/// | `f32`  | `f32`                                         |
530/// | `u32`  | `u32`                                         |
531/// | `Vec2` | `vec2<f32>`                                   |
532/// | `Vec3` | `vec3<f32>`                                   |
533/// | `Vec4` | `vec4<f32>`                                   |
534/// | `Mat4` | `mat4x4<f32>`                                 |
535/// | `Color` | `vec4<f32>`, linear red, green, blue and alpha |
536#[proc_macro_derive(ShaderValues)]
537pub fn derive_shader_values(input: TokenStream) -> TokenStream {
538    let input = parse_macro_input!(input as DeriveInput);
539    match shader_values(&input) {
540        Ok(implementation) => implementation,
541        Err(error) => error.to_compile_error().into(),
542    }
543}
544
545fn shader_values(input: &DeriveInput) -> syn::Result<TokenStream> {
546    let name = &input.ident;
547    let Data::Struct(data) = &input.data else {
548        return Err(syn::Error::new_spanned(
549            name,
550            "values a shader reads are a struct of the fields it reads",
551        ));
552    };
553    let read = match &data.fields {
554        Fields::Named(fields) => fields.named.iter().collect(),
555        Fields::Unit => Vec::new(),
556        Fields::Unnamed(_) => {
557            return Err(syn::Error::new_spanned(
558                name,
559                "values a shader reads are named, so that it reads them by name",
560            ));
561        }
562    };
563
564    let layout = Layout::of(name, &read)?;
565    let declaration = &layout.declaration;
566    let size = layout.size;
567    let written = layout
568        .placed
569        .iter()
570        .map(|placed| placed.lane.written(&placed.field, placed.offset));
571    let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
572    Ok(quote! {
573        impl #impl_generics ::mirage_engine::Sealed for #name #type_generics #where_clause {}
574
575        impl #impl_generics ::mirage_engine::ShaderValues for #name #type_generics #where_clause {
576            const TYPE: &'static str = ::core::stringify!(#name);
577            const DECLARATION: &'static str = #declaration;
578
579            fn write(&self, into: &mut ::std::vec::Vec<u8>) {
580                let start = into.len();
581                #(#written)*
582                into.resize(start + #size, 0);
583            }
584        }
585    }
586    .into())
587}
588
589/// The values a shader reads as the derive lays them out: the WGSL
590/// declaring them, where each field is written, and the bytes the whole of
591/// them fills.
592struct Layout {
593    declaration: String,
594    placed: Vec<Placed>,
595    size: usize,
596}
597
598impl Layout {
599    /// How a shader reads the fields `read` of the struct `name`.
600    fn of(name: &Ident, read: &[&syn::Field]) -> syn::Result<Self> {
601        if read.is_empty() {
602            return Ok(Self {
603                declaration: String::new(),
604                placed: Vec::new(),
605                size: 0,
606            });
607        }
608
609        let mut declaration = format!("struct {name} {{\n");
610        let mut placed = Vec::new();
611        let mut offset = 0usize;
612        for read in read {
613            let Some(field) = read.ident.clone() else {
614                continue;
615            };
616            let lane = Lane::of(&read.ty)?;
617            offset = lane.aligned(offset);
618            declaration.push_str(&format!("    {field}: {},\n", lane.wgsl()));
619            placed.push(Placed {
620                lane,
621                field,
622                offset,
623            });
624            offset += lane.size();
625        }
626        declaration.push('}');
627        Ok(Self {
628            declaration,
629            placed,
630            size: offset.next_multiple_of(BLOCK),
631        })
632    }
633}
634
635/// One field as the shader reads it: through which lane, under which name,
636/// at which offset.
637struct Placed {
638    lane: Lane,
639    field: Ident,
640    offset: usize,
641}
642
643/// One kind of value a shader reads, of the kinds it has a lane for.
644#[derive(Clone, Copy)]
645enum Lane {
646    Number,
647    Count,
648    Vec2,
649    Vec3,
650    Vec4,
651    Mat4,
652    Color,
653}
654
655impl Lane {
656    /// The lane `ty` is read through, or an error naming the kinds there
657    /// are.
658    fn of(ty: &syn::Type) -> syn::Result<Self> {
659        let syn::Type::Path(path) = ty else {
660            return Err(Self::unread(ty));
661        };
662        match path.path.segments.last() {
663            Some(segment) => match segment.ident.to_string().as_str() {
664                "f32" => Ok(Self::Number),
665                "u32" => Ok(Self::Count),
666                "Vec2" => Ok(Self::Vec2),
667                "Vec3" => Ok(Self::Vec3),
668                "Vec4" => Ok(Self::Vec4),
669                "Mat4" => Ok(Self::Mat4),
670                "Color" => Ok(Self::Color),
671                _ => Err(Self::unread(ty)),
672            },
673            None => Err(Self::unread(ty)),
674        }
675    }
676
677    fn unread(ty: &syn::Type) -> syn::Error {
678        syn::Error::new_spanned(
679            ty,
680            "a shader reads `f32`, `u32`, `Vec2`, `Vec3`, `Vec4`, `Mat4` and `Color`, and \
681             nothing else",
682        )
683    }
684
685    /// Type the shader declares this lane as.
686    fn wgsl(self) -> &'static str {
687        match self {
688            Self::Number => "f32",
689            Self::Count => "u32",
690            Self::Vec2 => "vec2<f32>",
691            Self::Vec3 => "vec3<f32>",
692            Self::Vec4 | Self::Color => "vec4<f32>",
693            Self::Mat4 => "mat4x4<f32>",
694        }
695    }
696
697    /// Bytes of it the shader reads.
698    fn size(self) -> usize {
699        match self {
700            Self::Number | Self::Count => 4,
701            Self::Vec2 => 8,
702            Self::Vec3 => 12,
703            Self::Vec4 | Self::Color => 16,
704            Self::Mat4 => 64,
705        }
706    }
707
708    /// The next offset a value of this lane may start at, from `offset`.
709    fn aligned(self, offset: usize) -> usize {
710        let align = match self {
711            Self::Number | Self::Count => 4,
712            Self::Vec2 => 8,
713            Self::Vec3 | Self::Vec4 | Self::Color | Self::Mat4 => BLOCK,
714        };
715        offset.next_multiple_of(align)
716    }
717
718    /// Writing one field of this lane where the shader reads it.
719    fn written(self, field: &Ident, offset: usize) -> impl quote::ToTokens {
720        let numbers = match self {
721            Self::Number | Self::Count => vec![quote!(self.#field)],
722            Self::Vec2 => vec![quote!(self.#field.x), quote!(self.#field.y)],
723            Self::Vec3 => vec![
724                quote!(self.#field.x),
725                quote!(self.#field.y),
726                quote!(self.#field.z),
727            ],
728            Self::Vec4 => vec![
729                quote!(self.#field.x),
730                quote!(self.#field.y),
731                quote!(self.#field.z),
732                quote!(self.#field.w),
733            ],
734            Self::Color => vec![
735                quote!(self.#field.red),
736                quote!(self.#field.green),
737                quote!(self.#field.blue),
738                quote!(self.#field.alpha),
739            ],
740            Self::Mat4 => {
741                return quote! {
742                    into.resize(start + #offset, 0);
743                    for number in self.#field.to_cols_array() {
744                        into.extend_from_slice(&number.to_le_bytes());
745                    }
746                };
747            }
748        };
749
750        quote! {
751            into.resize(start + #offset, 0);
752            #(into.extend_from_slice(&#numbers.to_le_bytes());)*
753        }
754    }
755}