wiggle_generate/types/
record.rs

1use crate::lifetimes::{LifetimeExt, anon_lifetime};
2use crate::names;
3
4use proc_macro2::TokenStream;
5use quote::{format_ident, quote};
6use witx::Layout;
7
8pub(super) fn define_struct(name: &witx::Id, s: &witx::RecordDatatype) -> TokenStream {
9    let ident = names::type_(name);
10    let size = s.mem_size_align().size as u32;
11    let align = s.mem_size_align().align;
12
13    let member_names = s.members.iter().map(|m| names::struct_member(&m.name));
14    let member_decls = s.members.iter().map(|m| {
15        let name = names::struct_member(&m.name);
16        let type_ = match &m.tref {
17            witx::TypeRef::Name(nt) => {
18                let tt = names::type_(&nt.name);
19                quote!(#tt)
20            }
21            witx::TypeRef::Value(ty) => match &**ty {
22                witx::Type::Builtin(builtin) => names::builtin_type(*builtin),
23                witx::Type::Pointer(pointee) | witx::Type::ConstPointer(pointee) => {
24                    let pointee_type = names::type_ref(&pointee, quote!('a));
25                    quote!(wiggle::GuestPtr<#pointee_type>)
26                }
27                _ => unimplemented!("other anonymous struct members: {:?}", m.tref),
28            },
29        };
30        quote!(pub #name: #type_)
31    });
32
33    let member_offsets = s.member_layout().into_iter().map(|ml| {
34        let name = names::struct_member(&ml.member.name);
35        let offset = ml.offset as u32;
36        let method_name = format_ident!("offset_of_{}", name);
37        quote! {
38            pub const fn #method_name () -> u32 {
39                #offset
40            }
41        }
42    });
43
44    let member_reads = s.member_layout().into_iter().map(|ml| {
45        let name = names::struct_member(&ml.member.name);
46        let offset = ml.offset as u32;
47        let location = quote!(location.cast::<u8>().add(#offset)?.cast());
48        match &ml.member.tref {
49            witx::TypeRef::Name(nt) => {
50                let type_ = names::type_(&nt.name);
51                quote! {
52                    let #name = <#type_ as wiggle::GuestType>::read(mem, #location)?;
53                }
54            }
55            witx::TypeRef::Value(ty) => match &**ty {
56                witx::Type::Builtin(builtin) => {
57                    let type_ = names::builtin_type(*builtin);
58                    quote! {
59                        let #name = <#type_ as wiggle::GuestType>::read(mem, #location)?;
60                    }
61                }
62                witx::Type::Pointer(pointee) | witx::Type::ConstPointer(pointee) => {
63                    let pointee_type = names::type_ref(&pointee, anon_lifetime());
64                    quote! {
65                        let #name = <wiggle::GuestPtr::<#pointee_type> as wiggle::GuestType>::read(mem, #location)?;
66                    }
67                }
68                _ => unimplemented!("other anonymous struct members: {:?}", ty),
69            },
70        }
71    });
72
73    let member_writes = s.member_layout().into_iter().map(|ml| {
74        let name = names::struct_member(&ml.member.name);
75        let offset = ml.offset as u32;
76        quote! {
77            wiggle::GuestType::write(
78                mem,
79                location.cast::<u8>().add(#offset)?.cast(),
80                val.#name,
81            )?;
82        }
83    });
84
85    let (struct_lifetime, extra_derive) = if s.needs_lifetime() {
86        (quote!(<'a>), quote!())
87    } else {
88        (quote!(), quote!(, PartialEq))
89    };
90
91    quote! {
92        #[derive(Clone, Debug #extra_derive)]
93        pub struct #ident {
94            #(#member_decls),*
95        }
96
97        impl #struct_lifetime #ident {
98            #(#member_offsets)*
99        }
100
101        impl wiggle::GuestType for #ident {
102            #[inline]
103            fn guest_size() -> u32 {
104                #size
105            }
106
107            #[inline]
108            fn guest_align() -> usize {
109                #align
110            }
111
112            fn read(mem: &wiggle::GuestMemory, location: wiggle::GuestPtr<Self>) -> Result<Self, wiggle::GuestError> {
113                #(#member_reads)*
114                Ok(#ident { #(#member_names),* })
115            }
116
117            fn write(mem: &mut wiggle::GuestMemory, location: wiggle::GuestPtr<Self>, val: Self) -> Result<(), wiggle::GuestError> {
118                #(#member_writes)*
119                Ok(())
120            }
121        }
122    }
123}
124
125impl super::WiggleType for witx::RecordDatatype {
126    fn impls_display(&self) -> bool {
127        false
128    }
129}