Skip to main content

ab_io_type_derive/
lib.rs

1use proc_macro2::{Ident, Literal, Span, TokenStream};
2use quote::{format_ident, quote, quote_spanned};
3use std::iter;
4use syn::spanned::Spanned;
5use syn::{
6    Data, DataEnum, DataStruct, DeriveInput, Error, ExprPath, Fields, Type, parse_macro_input,
7};
8
9/// Derive macro for `TrivialType` trait of `ab-io-type` crate.
10///
11/// See the documentation of the trait for supported types and requirements, which are checked at
12/// compile time.
13#[proc_macro_derive(TrivialType, attributes(trivial_type))]
14pub fn trivial_type_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
15    let input = parse_macro_input!(input as DeriveInput);
16
17    if !input.generics.params.is_empty() {
18        return Error::new(
19            input.ident.span(),
20            "`TrivialType` can't be derived on generic types",
21        )
22        .into_compile_error()
23        .into();
24    }
25
26    let validate = match parse_validate(&input) {
27        Ok(validate) => validate,
28        Err(error) => {
29            return error.to_compile_error().into();
30        }
31    };
32
33    let type_name = &input.ident;
34
35    let output = match &input.data {
36        Data::Struct(data_struct) => {
37            if let Err(error) = check_repr(
38                &input,
39                &["C", "transparent"],
40                "`TrivialType` on structs requires `#[repr(C)]` or `#[repr(transparent)]` without \
41                other options",
42            ) {
43                return error.to_compile_error().into();
44            }
45            let field_types = data_struct
46                .fields
47                .iter()
48                .map(|field| &field.ty)
49                .collect::<Vec<_>>();
50
51            let struct_metadata = match generate_struct_metadata(type_name, data_struct) {
52                Ok(struct_metadata) => struct_metadata,
53                Err(error) => {
54                    return error.to_compile_error().into();
55                }
56            };
57
58            // Fields are parsed in order: they follow each other without padding (asserted below),
59            // so each field's step consumes exactly the bytes of that field, and the bytes are a
60            // valid value of the struct when every field is a valid value
61            let checks = quote! {
62                let fields = bytes;
63                #(
64                    let (_value, fields) =
65                        <#field_types as ::ab_io_type::trivial_type::TrivialType>
66                            ::try_from_bytes_unaligned(fields)?;
67                )*
68                // Empty, there is no padding after the last field
69                let _: &[::core::primitive::u8] = fields;
70            };
71            let parsing_step = generate_parsing_step(checks, validate.as_ref());
72            let alignment = generate_alignment(&field_types);
73
74            // A `validate` function rejects some values whose fields are all valid, so such a type
75            // doesn't accept every bit pattern even if its fields do. Bounds are higher-ranked, so
76            // that a field type without the marker makes the bound false instead of being a
77            // "trivial bound" error. They also contain no type parameter, which keeps a future
78            // `try_as_dyn()` probe working.
79            let marker_impl = if validate.is_some() {
80                TokenStream::new()
81            } else {
82                quote! {
83                    // SAFETY: Padding is rejected by the assertions generated with the
84                    // `TrivialType` impl, so the bytes of a value are exactly the bytes of its
85                    // fields, and the impl only applies when every field accepts any bit pattern.
86                    // The parsing step only calls parsing steps of fields after checking the
87                    // length, which accept every pattern of the field's bytes, and there is no
88                    // `validate` function.
89                    #[automatically_derived]
90                    unsafe impl ::ab_io_type::trivial_type::AnyBitPatternMarker for #type_name
91                    where
92                        #(
93                            for<'__ab_io_type> #field_types:
94                                ::ab_io_type::trivial_type::AnyBitPatternMarker,
95                        )*
96                    {
97                    }
98                }
99            };
100
101            quote! {
102                const _: () = {
103                    // Assert statically that there is no unexpected padding that would be left
104                    // uninitialized and unsound to access
105                    ::core::assert!(
106                        0 == (
107                            ::core::mem::size_of::<#type_name>()
108                            #(- ::core::mem::size_of::<#field_types>() )*
109                        ),
110                        "Struct must not have implicit padding. Consider reordering fields, adding \
111                        `padding: [u8; N]` field where necessary or use `Unaligned<T>` wrapper for \
112                        types with larger alignment to reduce it to one byte."
113                    );
114
115                    // Assert that type doesn't exceed 32-bit size limit
116                    ::core::assert!(
117                        ::core::primitive::u32::MAX as ::core::primitive::usize
118                            >= ::core::mem::size_of::<#type_name>(),
119                        "Type size must be smaller than 2^32"
120                    );
121
122                    // Ensure metadata decodes completely, and capacity and alignment are correctly
123                    // decoded from it. Every level of nesting takes at least one byte of metadata,
124                    // so its length is enough as the max nesting depth.
125                    let (type_details, remaining_metadata) =
126                        ::ab_io_type::metadata::IoTypeMetadataKind::type_details::<{
127                            <#type_name as ::ab_io_type::trivial_type::TrivialType>::METADATA.len()
128                        }>(
129                            <#type_name as ::ab_io_type::trivial_type::TrivialType>::METADATA,
130                        )
131                            .expect(
132                                "Metadata must decode, which is not the case for layouts with \
133                                padding or misaligned fields"
134                            );
135                    ::core::assert!(remaining_metadata.is_empty());
136                    ::core::assert!(
137                        ::core::mem::size_of::<#type_name>()
138                            == type_details.recommended_capacity as ::core::primitive::usize
139                    );
140                    // Alignments are compared by their powers, `==` of `Alignment` in constants
141                    // needs the `const_trait_impl` and `const_cmp` features
142                    ::core::assert!(
143                        ::ab_io_type::alignment::Alignment::of::<#type_name>().power
144                            == type_details.alignment.power
145                    );
146                };
147
148                #[automatically_derived]
149                unsafe impl ::ab_io_type::trivial_type::TrivialType for #type_name
150                where
151                    #( #field_types: ::ab_io_type::trivial_type::TrivialType, )*
152                {
153                    #alignment
154
155                    const METADATA: &[::core::primitive::u8] = #struct_metadata;
156
157                    #parsing_step
158                }
159
160                #marker_impl
161            }
162        }
163        Data::Enum(data_enum) => {
164            // Require defined size of the discriminant instead of allowing compiler to guess. With
165            // `#[repr(u8)]` each variant is laid out like a `#[repr(C)]` struct with the
166            // discriminant as the first field, which padding assertions rely on, `#[repr(C, u8)]`
167            // has a different layout.
168            if let Err(error) = check_repr(
169                &input,
170                &["u8"],
171                "`TrivialType` on enums requires `#[repr(u8)]` without other options",
172            ) {
173                return error.to_compile_error().into();
174            }
175
176            // Metadata identifies variants by their index, so explicit discriminants must be equal
177            // to it, which makes implicit ones equal to it too. Assertions are associated constants
178            // of the enum, so `Self` in a discriminant means the same as in the enum definition.
179            // They are only evaluated when used, so each is used by its own `const _`, which
180            // reports all wrong discriminants.
181            let discriminant_assertions = data_enum
182                .variants
183                .iter()
184                // `#[repr(u8)]` allows at most 256 variants
185                .zip(0..=u8::MAX)
186                .filter_map(|(variant, index)| {
187                    let (_eq_token, discriminant) = variant.discriminant.as_ref()?;
188                    // Errors point at the discriminant
189                    let span = Span::call_site().located_at(discriminant.span());
190                    let name = format_ident!("__TRIVIAL_TYPE_DISCRIMINANT_{index}");
191                    let message = format!(
192                        "Discriminant of `{}` must be equal to its index {index}, variants are \
193                        identified by their index in `TrivialType` metadata",
194                        variant.ident
195                    );
196
197                    Some(quote_spanned! {span=>
198                        impl #type_name {
199                            // The index goes first, so the discriminant is inferred as `u8` like
200                            // in the enum definition
201                            #[doc(hidden)]
202                            const #name: () = ::core::assert!(#index == (#discriminant), #message);
203                        }
204
205                        const _: () = #type_name::#name;
206                    })
207                })
208                .collect::<Vec<_>>();
209
210            let field_types = data_enum
211                .variants
212                .iter()
213                .flat_map(|variant| &variant.fields)
214                .map(|field| &field.ty)
215                .collect::<Vec<_>>();
216
217            let padding_assertions = data_enum.variants.iter().map(|variant| {
218                let field_types = variant.fields.iter().map(|field| &field.ty);
219
220                quote! {
221                    // Assert statically that there is no unexpected padding that would be left
222                    // uninitialized and unsound to access
223                    ::core::assert!(
224                        0 == (
225                            ::core::mem::size_of::<#type_name>()
226                            - ::core::mem::size_of::<::core::primitive::u8>()
227                            #(- ::core::mem::size_of::<#field_types>() )*
228                        ),
229                        "Enum must not have implicit padding. Consider reordering fields, adding \
230                        `padding: [u8; N]` field where necessary or use `Unaligned<T>` wrapper for \
231                        types with larger alignment to reduce it to one byte."
232                    );
233                }
234            });
235
236            // The discriminant must be the index of a variant, which is its discriminant (asserted
237            // above), then fields of that variant are parsed in order. Each variant is laid out
238            // like a `#[repr(C)]` struct with the discriminant as the first field, without padding
239            // (asserted below), so each field's step consumes exactly the bytes of that field, and
240            // the bytes are a valid value of the enum when every field of the variant is a valid
241            // value.
242            let variant_arms = data_enum
243                .variants
244                .iter()
245                // `#[repr(u8)]` allows at most 256 variants
246                .zip(0..=u8::MAX)
247                .map(|(variant, index)| {
248                    let field_types = variant.fields.iter().map(|field| &field.ty);
249
250                    quote! {
251                        #index => {
252                            #(
253                                let (_value, fields) =
254                                    <#field_types as ::ab_io_type::trivial_type::TrivialType>
255                                        ::try_from_bytes_unaligned(fields)?;
256                            )*
257                            // Empty, there is no padding after the last field
258                            let _: &[::core::primitive::u8] = fields;
259                        }
260                    }
261                });
262            let checks = quote! {
263                let (&discriminant, fields) = <[::core::primitive::u8]>::split_first(bytes)?;
264                match discriminant {
265                    #( #variant_arms )*
266                    _ => {
267                        return ::core::option::Option::None;
268                    }
269                }
270            };
271            let parsing_step = generate_parsing_step(checks, validate.as_ref());
272
273            let alignment = generate_alignment(&field_types);
274
275            let enum_metadata = match generate_enum_metadata(type_name, data_enum) {
276                Ok(struct_metadata) => struct_metadata,
277                Err(error) => {
278                    return error.to_compile_error().into();
279                }
280            };
281
282            quote! {
283                #( #discriminant_assertions )*
284
285                const _: () = {
286                    #( #padding_assertions )*
287
288                    // Assert that type doesn't exceed 32-bit size limit
289                    ::core::assert!(
290                        ::core::primitive::u32::MAX as ::core::primitive::usize
291                            >= ::core::mem::size_of::<#type_name>(),
292                        "Type size must be smaller than 2^32"
293                    );
294
295                    // Ensure metadata decodes completely, and capacity and alignment are correctly
296                    // decoded from it. Every level of nesting takes at least one byte of metadata,
297                    // so its length is enough as the max nesting depth.
298                    let (type_details, remaining_metadata) =
299                        ::ab_io_type::metadata::IoTypeMetadataKind::type_details::<{
300                            <#type_name as ::ab_io_type::trivial_type::TrivialType>::METADATA.len()
301                        }>(
302                            <#type_name as ::ab_io_type::trivial_type::TrivialType>::METADATA,
303                        )
304                            .expect(
305                                "Metadata must decode, which is not the case for layouts with \
306                                padding or misaligned fields"
307                            );
308                    ::core::assert!(remaining_metadata.is_empty());
309                    ::core::assert!(
310                        ::core::mem::size_of::<#type_name>()
311                            == type_details.recommended_capacity as ::core::primitive::usize
312                    );
313                    // Alignments are compared by their powers, `==` of `Alignment` in constants
314                    // needs the `const_trait_impl` and `const_cmp` features
315                    ::core::assert!(
316                        ::ab_io_type::alignment::Alignment::of::<#type_name>().power
317                            == type_details.alignment.power
318                    );
319                };
320
321                #[automatically_derived]
322                unsafe impl ::ab_io_type::trivial_type::TrivialType for #type_name
323                where
324                    #( #field_types: ::ab_io_type::trivial_type::TrivialType, )*
325                {
326                    #alignment
327
328                    const METADATA: &[::core::primitive::u8] = #enum_metadata;
329
330                    #parsing_step
331                }
332            }
333        }
334        Data::Union(data_union) => {
335            return Error::new(
336                data_union.union_token.span(),
337                "`TrivialType` can be derived for structs and enums, but not unions",
338            )
339            .to_compile_error()
340            .into();
341        }
342    };
343
344    output.into()
345}
346
347/// Generate `TrivialType::ALIGNMENT`: the largest alignment of `field_types`, 1 byte without fields
348fn generate_alignment(field_types: &[&Type]) -> TokenStream {
349    quote! {
350        const ALIGNMENT: ::ab_io_type::alignment::Alignment = {
351            let mut field_alignments: &[::ab_io_type::alignment::Alignment] = &[
352                #( <#field_types as ::ab_io_type::trivial_type::TrivialType>::ALIGNMENT, )*
353            ];
354            let mut alignment =
355                <::core::primitive::u8 as ::ab_io_type::trivial_type::TrivialType>::ALIGNMENT;
356            while let [field_alignment, rest @ ..] = field_alignments {
357                if field_alignment.get() > alignment.get() {
358                    alignment = *field_alignment;
359                }
360                field_alignments = rest;
361            }
362            alignment
363        };
364    }
365}
366
367/// Parse `#[trivial_type(..)]` attributes, returns the path of the `validate` function if there is
368/// one
369fn parse_validate(input: &DeriveInput) -> Result<Option<ExprPath>, Error> {
370    // Registering the helper attribute makes it legal on fields and variants too, where the derive
371    // would ignore it, and an ignored `validate` lets parsing create values that `unsafe` code
372    // relies on never existing
373    let nested_attrs = match &input.data {
374        Data::Struct(data_struct) => data_struct
375            .fields
376            .iter()
377            .flat_map(|field| &field.attrs)
378            .collect::<Vec<_>>(),
379        Data::Enum(data_enum) => data_enum
380            .variants
381            .iter()
382            .flat_map(|variant| {
383                variant
384                    .attrs
385                    .iter()
386                    .chain(variant.fields.iter().flat_map(|field| &field.attrs))
387            })
388            .collect::<Vec<_>>(),
389        Data::Union(data_union) => data_union
390            .fields
391            .named
392            .iter()
393            .flat_map(|field| &field.attrs)
394            .collect::<Vec<_>>(),
395    };
396    if let Some(attr) = nested_attrs
397        .into_iter()
398        .find(|attr| attr.path().is_ident("trivial_type"))
399    {
400        return Err(Error::new_spanned(
401            attr,
402            "`#[trivial_type(..)]` is only supported on the type",
403        ));
404    }
405
406    let mut validate = None;
407    let attrs = input
408        .attrs
409        .iter()
410        .filter(|attr| attr.path().is_ident("trivial_type"));
411    for attr in attrs {
412        let mut has_options = false;
413        attr.parse_nested_meta(|meta| {
414            has_options = true;
415            if !meta.path.is_ident("validate") {
416                return Err(meta.error("Unsupported `#[trivial_type(..)]` option"));
417            }
418            if validate.is_some() {
419                return Err(meta.error("`validate` is specified more than once"));
420            }
421            // Parsed like a path in an expression, so generic arguments are written as `::<..>`
422            // and a qualified self type is supported, like in the generated call
423            let path = meta.value()?.parse::<ExprPath>()?;
424            if let Some(attr) = path.attrs.first() {
425                return Err(Error::new_spanned(
426                    attr,
427                    "Attributes are not supported in `validate = path`",
428                ));
429            }
430            validate = Some(path);
431            Ok(())
432        })?;
433
434        if !has_options {
435            return Err(Error::new_spanned(
436                attr,
437                "`#[trivial_type(..)]` requires an option, like `validate = path`",
438            ));
439        }
440    }
441
442    Ok(validate)
443}
444
445/// Generate the parsing step of `TrivialType`, which checks the size, runs `checks` with `bytes` of
446/// the size of the type in scope, which must return `None` for invalid bytes, casts `bytes` to the
447/// type and calls the `validate` function with the value if there is one
448fn generate_parsing_step(checks: TokenStream, validate: Option<&ExprPath>) -> TokenStream {
449    let validation = if let Some(path) = validate {
450        // Errors, like a wrong signature or an `unsafe` function, point at the path in the
451        // attribute
452        let span = Span::call_site().located_at(path.span());
453        quote_spanned! {span=>
454            if !#path(::ab_io_type::unaligned::Unaligned::<Self>::as_inner(__ab_io_type_value)) {
455                return ::core::option::Option::None;
456            }
457        }
458    } else {
459        TokenStream::new()
460    };
461
462    // The value is the only local of the step with a prefixed name: a constant with the same name
463    // in the module of the type would turn the binding into a constant pattern, which compiles for
464    // types with a single value, and the step would return the constant instead of a reference
465    // into `bytes`. Constants named like the other locals only cause compile errors.
466    quote! {
467        #[inline(always)]
468        fn try_from_bytes_unaligned(
469            bytes: &[::core::primitive::u8],
470        ) -> ::core::option::Option<(
471            &::ab_io_type::unaligned::Unaligned<Self>,
472            &[::core::primitive::u8],
473        )> {
474            let (bytes, remainder) = <[::core::primitive::u8]>::split_at_checked(
475                bytes,
476                ::core::mem::size_of::<Self>(),
477            )?;
478            #checks
479            // SAFETY: `bytes` have the size of the type and `checks` return `None` unless every
480            // field, of the variant whose index is the discriminant for an enum, is a valid value.
481            // Variants have discriminants equal to their indices and fields follow each other
482            // without padding (both asserted next to the type), and `Unaligned<Self>` has
483            // alignment 1.
484            let __ab_io_type_value = unsafe {
485                &*<[::core::primitive::u8]>::as_ptr(bytes)
486                    .cast::<::ab_io_type::unaligned::Unaligned<Self>>()
487            };
488            // The `validate` function, if any, rejects values whose invariants don't hold. It is
489            // called outside of the `unsafe` block above, so it can't be an `unsafe` function.
490            #validation
491            ::core::option::Option::Some((__ab_io_type_value, remainder))
492        }
493    }
494}
495
496/// Check that `#[repr(..)]` attributes of the type contain at least one of `allowed` options and no
497/// other options, returns an error with `message` otherwise
498fn check_repr(input: &DeriveInput, allowed: &[&str], message: &str) -> Result<(), Error> {
499    let mut found_allowed = false;
500
501    // All `#[repr(..)]` attributes are combined by the compiler
502    let repr_attrs = input
503        .attrs
504        .iter()
505        .filter(|attr| attr.path().is_ident("repr"));
506    for repr_attr in repr_attrs {
507        repr_attr.parse_nested_meta(|meta| {
508            if allowed.iter().any(|option| meta.path.is_ident(option)) {
509                found_allowed = true;
510                Ok(())
511            } else {
512                Err(meta.error(message))
513            }
514        })?;
515    }
516
517    if !found_allowed {
518        return Err(Error::new(input.ident.span(), message));
519    }
520
521    Ok(())
522}
523
524fn generate_struct_metadata(ident: &Ident, data_struct: &DataStruct) -> Result<TokenStream, Error> {
525    let inner_struct_metadata = generate_inner_struct_metadata(ident, &data_struct.fields)
526        .collect::<Result<Vec<_>, _>>()?;
527
528    // Encodes the following:
529    // * Type: struct
530    // * The rest as inner struct metadata
531    Ok(quote! {{
532        #[inline(always)]
533        const fn metadata() -> (
534            [::core::primitive::u8; ::ab_io_type::metadata::MAX_METADATA_CAPACITY],
535            ::core::primitive::usize,
536        )
537        {
538            ::ab_io_type::metadata::concat_metadata_sources(&[
539                &[::ab_io_type::metadata::IoTypeMetadataKind::Struct as ::core::primitive::u8],
540                #( #inner_struct_metadata )*
541            ])
542        }
543
544        // The reference extends the lifetime of metadata scratch to that of the constant
545        let (metadata_scratch, metadata_size) = &metadata();
546        // `split_at()` is called by path, with method call syntax a method of a trait in scope that
547        // is implemented for arrays would be called instead
548        <[_]>::split_at(metadata_scratch, *metadata_size).0
549    }})
550}
551
552fn generate_enum_metadata(ident: &Ident, data_enum: &DataEnum) -> Result<TokenStream, Error> {
553    let type_name_string = ident.to_string();
554    let type_name_bytes = type_name_string.as_bytes();
555
556    let type_name_bytes_len = u8::try_from(type_name_bytes.len()).map_err(|_error| {
557        Error::new(
558            ident.span(),
559            format!(
560                "Name of the enum must not be more than {} bytes in length",
561                u8::MAX
562            ),
563        )
564    })?;
565    let num_variants = u8::try_from(data_enum.variants.len()).map_err(|_error| {
566        Error::new(
567            ident.span(),
568            format!("Enum must not have more than {} variants", u8::MAX),
569        )
570    })?;
571    // Encodes the following:
572    // * Type: enum
573    // * Length of enum name in bytes (u8)
574    // * Enum name as UTF-8 bytes
575    // * Number of variants (u8)
576    let enum_metadata_header = {
577        let enum_metadata_header = [Literal::u8_unsuffixed(type_name_bytes_len)]
578            .into_iter()
579            .chain(
580                type_name_bytes
581                    .iter()
582                    .map(|&char| Literal::byte_character(char)),
583            )
584            .chain([Literal::u8_unsuffixed(num_variants)]);
585
586        quote! {
587            &[
588                ::ab_io_type::metadata::IoTypeMetadataKind::Enum as ::core::primitive::u8,
589                #( #enum_metadata_header, )*
590            ]
591        }
592    };
593
594    // Encodes each variant as inner struct, fields of tuple variants have zero-length names like
595    // fields of tuple structs
596    let inner = data_enum
597        .variants
598        .iter()
599        .flat_map(|variant| generate_inner_struct_metadata(&variant.ident, &variant.fields))
600        .collect::<Result<Vec<TokenStream>, Error>>()?;
601
602    Ok(quote! {{
603        #[inline(always)]
604        const fn metadata() -> (
605            [::core::primitive::u8; ::ab_io_type::metadata::MAX_METADATA_CAPACITY],
606            ::core::primitive::usize,
607        )
608        {
609            ::ab_io_type::metadata::concat_metadata_sources(&[
610                #enum_metadata_header,
611                #( #inner )*
612            ])
613        }
614
615        // The reference extends the lifetime of metadata scratch to that of the constant
616        let (metadata_scratch, metadata_size) = &metadata();
617        // `split_at()` is called by path, with method call syntax a method of a trait in scope that
618        // is implemented for arrays would be called instead
619        <[_]>::split_at(metadata_scratch, *metadata_size).0
620    }})
621}
622
623fn generate_inner_struct_metadata<'a>(
624    ident: &'a Ident,
625    fields: &'a Fields,
626) -> impl Iterator<Item = Result<TokenStream, Error>> + 'a {
627    iter::once_with(move || generate_inner_struct_metadata_header(ident, fields))
628        .chain(generate_fields_metadata(fields))
629}
630
631fn generate_inner_struct_metadata_header(
632    ident: &Ident,
633    fields: &Fields,
634) -> Result<TokenStream, Error> {
635    let ident_string = ident.to_string();
636    let ident_bytes = ident_string.as_bytes();
637
638    let ident_bytes_len = u8::try_from(ident_bytes.len()).map_err(|_error| {
639        Error::new(
640            ident.span(),
641            format!(
642                "Identifier must not be more than {} bytes in length",
643                u8::MAX
644            ),
645        )
646    })?;
647    let num_fields = u8::try_from(fields.len()).map_err(|_error| {
648        Error::new(
649            fields.span(),
650            format!("Must not have more than {} fields", u8::MAX),
651        )
652    })?;
653
654    // Encodes the following:
655    // * Length of identifier in bytes (u8)
656    // * Identifier as UTF-8 bytes
657    // * Number of fields (u8)
658    Ok({
659        let struct_metadata_header = [Literal::u8_unsuffixed(ident_bytes_len)]
660            .into_iter()
661            .chain(
662                ident_bytes
663                    .iter()
664                    .map(|&char| Literal::byte_character(char)),
665            )
666            .chain([Literal::u8_unsuffixed(num_fields)]);
667
668        quote! {
669            &[#( #struct_metadata_header, )*],
670        }
671    })
672}
673
674fn generate_fields_metadata(
675    fields: &Fields,
676) -> impl Iterator<Item = Result<TokenStream, Error>> + '_ {
677    // Encodes the following for each field:
678    // * Length of the field name in bytes (u8, zero for tuple fields)
679    // * Field name as UTF-8 bytes
680    // * Recursive metadata of the field's type
681    fields.iter().map(move |field| {
682        let field_metadata = if let Some(field_name) = &field.ident {
683            let field_name_string = field_name.to_string();
684            let field_name_bytes = field_name_string.as_bytes();
685            let field_name_len = u8::try_from(field_name_bytes.len()).map_err(|_error| {
686                Error::new(
687                    field.span(),
688                    format!(
689                        "Name of the field must not be more than {} bytes in length",
690                        u8::MAX
691                    ),
692                )
693            })?;
694
695            let field_metadata = [Literal::u8_unsuffixed(field_name_len)].into_iter().chain(
696                field_name_bytes
697                    .iter()
698                    .map(|&char| Literal::byte_character(char)),
699            );
700
701            quote! { #( #field_metadata, )* }
702        } else {
703            quote! { 0, }
704        };
705        let field_type = &field.ty;
706
707        Ok(quote! {
708            &[ #field_metadata ],
709            <#field_type as ::ab_io_type::trivial_type::TrivialType>::METADATA,
710        })
711    })
712}