wiggle_generate/types/
record.rs1use 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}