witx_codegen/rust/
union.rs1use std::io::Write;
2
3use super::*;
4
5impl RustGenerator {
6 fn define_union_member_accessors<T: Write>(
7 w: &mut PrettyWriter<T>,
8 _union_name: &str,
9 i: usize,
10 member: &ASUnionMember,
11 inner_name: &str,
12 ) -> Result<(), Error> {
13 let name = &member.name;
14 let member_is_void = matches!(member.type_.as_ref(), ASType::Void);
15
16 if member_is_void {
17 w.write_line(format!("pub fn new_{}() -> Self {{", name.as_fn_suffix(),))?;
19 {
20 let mut w = w.new_block();
21 w.write_line(format!("Self::new({})", i))?;
22 }
23 w.write_line("}")?.eob()?;
24 } else {
25 w.write_line(format!(
28 "pub fn new_{}(val: {}) -> Self {{",
29 name.as_fn_suffix(),
30 member.type_.as_lang()
31 ))?;
32 {
33 let mut w = w.new_block();
34 w.write_line(format!("let mut tu = Self::new({});", i))?;
35 w.write_line(format!(
36 "tu.member = std::mem::MaybeUninit::new({} {{ {}: val }});",
37 inner_name.as_type(),
38 member.name.as_var()
39 ))?;
40 w.write_line("tu")?;
41 }
42 w.write_line("}")?.eob()?;
43
44 w.write_line(format!(
46 "pub fn into_{}(self) -> {} {{",
47 name.as_fn_suffix(),
48 member.type_.as_lang()
49 ))?;
50 {
51 let mut w = w.new_block();
52 w.write_line(format!("assert_eq!(self.tag, {});", i))?;
53 w.write_line(format!(
54 "unsafe {{ self.member.assume_init().{} }}",
55 member.name.as_var()
56 ))?;
57 }
58 w.write_line("}")?.eob()?;
59
60 w.write_line(format!(
62 "pub fn set_{}(&mut self, val: {}) {{",
63 name.as_fn_suffix(),
64 member.type_.as_lang()
65 ))?;
66 {
67 let mut w = w.new_block();
68 w.write_line(format!("assert_eq!(self.tag, {});", i))?;
69 w.write_line(format!(
70 "let uval = {} {{ {}: val }};",
71 inner_name.as_type(),
72 member.name.as_var()
73 ))?;
74 w.write_line("unsafe { *self.member.as_mut_ptr() = uval };")?;
75 }
76 w.write_line("}")?.eob()?;
77 }
78
79 w.write_line(format!(
81 "pub fn is_{}(&self) -> bool {{",
82 name.as_fn_suffix()
83 ))?;
84 {
85 let mut w = w.new_block();
86 w.write_line(format!("self.tag == {}", i))?;
87 }
88 w.write_line("}")?.eob()?;
89
90 Ok(())
91 }
92
93 fn define_union_member<T: Write>(
94 w: &mut PrettyWriter<T>,
95 union_name: &str,
96 i: usize,
97 member: &ASUnionMember,
98 inner_name: &str,
99 ) -> Result<(), Error> {
100 let member_type = member.type_.as_ref();
101 match member_type {
102 ASType::Void => {
103 w.write_line(format!(
104 "// --- {}: (no associated content) if tag={}",
105 member.name.as_var(),
106 i
107 ))?;
108 }
109 _ => {
110 w.write_line(format!(
111 "// --- {}: {} if tag={}",
112 member.name.as_var(),
113 member_type.as_lang(),
114 i
115 ))?;
116 }
117 }
118 w.eob()?;
119 Self::define_union_member_accessors(w, union_name, i, member, inner_name)?;
120 Ok(())
121 }
122
123 pub fn define_as_union<T: Write>(
124 w: &mut PrettyWriter<T>,
125 name: &str,
126 union_: &ASUnion,
127 ) -> Result<(), Error> {
128 let tag_repr = union_.tag_repr.as_ref();
129 let inner_name = format!("{}_member", name);
130 w.write_line("#[repr(C)]")?
131 .write_line(format!("pub union {} {{", inner_name.as_type()))?;
132 {
133 let mut w = w.new_block();
134 for (i, member) in union_.members.iter().enumerate() {
135 let member_is_void = matches!(member.type_.as_ref(), ASType::Void);
136 if member_is_void {
137 w.write_line(format!(
138 "// {} with no associated value if tag={}",
139 member.name.as_var(),
140 i
141 ))?;
142 } else {
143 w.write_line(format!(
144 "{}: {}, // if tag={}",
145 member.name.as_var(),
146 member.type_.as_lang(),
147 i
148 ))?;
149 }
150 }
151 }
152 w.write_line("}")?;
153 w.eob()?;
154
155 w.write_line("#[repr(C, packed)]")?
156 .write_line(format!("pub struct {} {{", name.as_type()))?;
157 {
158 let mut w = w.new_block();
159 w.write_line(format!("pub tag: {},", tag_repr.as_lang()))?;
160 let pad_len = union_.padding_after_tag;
161 for i in 0..(pad_len & 1) {
162 w.write_line(format!("__pad8_{}: u8,", i))?;
163 }
164 for i in 0..(pad_len & 3) / 2 {
165 w.write_line(format!("__pad16_{}: u16,", i))?;
166 }
167 for i in 0..(pad_len & 7) / 4 {
168 w.write_line(format!("__pad32_{}: u32,", i))?;
169 }
170 for i in 0..pad_len / 8 {
171 w.write_line(format!("__pad64_{}: u64,", i))?;
172 }
173 w.write_line(format!(
174 "pub member: std::mem::MaybeUninit<{}>,",
175 inner_name.as_type()
176 ))?;
177 }
178 w.write_line("}")?;
179 w.eob()?;
180
181 w.write_line(format!("impl {} {{", name.as_type()))?;
182 {
183 let mut w = w.new_block();
184 w.write_line(format!("fn new(tag: {}) -> Self {{", tag_repr.as_lang()))?;
185 {
186 let mut w = w.new_block();
187 w.write_line("let mut tu = unsafe { std::mem::zeroed::<Self>() };")?;
188 w.write_line("tu.tag = tag;")?;
189 w.write_line("tu")?;
190 }
191 w.write_line("}")?.eob()?;
192
193 for (i, member) in union_.members.iter().enumerate() {
194 w.eob()?;
195 Self::define_union_member(&mut w, name, i, member, &inner_name)?;
196 }
197 }
198 w.write_line("}")?.eob()?;
199 Ok(())
200 }
201}