witx_codegen/assemblyscript/
union.rs1use std::io::Write;
2
3use super::*;
4
5impl AssemblyScriptGenerator {
6 fn define_union_member_accessors<T: Write>(
7 w: &mut PrettyWriter<T>,
8 union_name: &str,
9 i: usize,
10 member: &ASUnionMember,
11 ) -> Result<(), Error> {
12 let member_type = member.type_.as_ref();
13 match member_type {
14 ASType::Void => {
15 w.write_line(format!(
16 "static {}(): {} {{",
17 member.name.as_fn(),
18 union_name.as_type()
19 ))?
20 .indent()?
21 .write_line(format!("return {}.new({});", union_name.as_type(), i))?
22 .write_line("}")?
23 .eob()?;
24
25 w.write_line(format!("set{}(): void {{", member.name.as_fn_suffix()))?
26 .indent()?
27 .write_line(format!("this.tag = {};", i))?
28 .write_line("}")?
29 .eob()?;
30
31 w.write_line(format!("is{}(): bool {{", member.name.as_fn_suffix()))?
32 .indent()?
33 .write_line(format!("return this.tag === {};", i))?
34 .write_line("}")?;
35 }
36 _ => {
37 w.write_line(format!(
38 "static {}(val: {}): {} {{",
39 member.name.as_fn(),
40 member_type.as_lang(),
41 union_name.as_type()
42 ))?;
43 w.new_block().write_line(format!(
44 "return {}.new({}, val);",
45 union_name.as_type(),
46 i
47 ))?;
48 w.write_line("}")?.eob()?;
49
50 w.write_line(format!(
51 "set{}(val: {}): void {{",
52 member.name.as_fn_suffix(),
53 member_type.as_lang()
54 ))?;
55 {
56 w.new_block()
57 .write_line(format!("this.tag = {};", i))?
58 .write_line("this.set(val);")?;
59 }
60 w.write_line("}")?.eob()?;
61
62 w.write_line(format!("is{}(): bool {{", member.name.as_fn_suffix(),))?
63 .indent()?
64 .write_line(format!("return this.tag === {};", i))?
65 .write_line("}")?
66 .eob()?;
67
68 if member_type.is_nullable() {
69 w.write_line(format!(
70 "get{}(): {} | null {{",
71 member.name.as_fn_suffix(),
72 member_type.as_lang()
73 ))?;
74 } else {
75 w.write_line(format!(
76 "get{}(): {} {{",
77 member.name.as_fn_suffix(),
78 member_type.as_lang()
79 ))?;
80 }
81 {
82 let mut w = w.new_block();
83 if member_type.is_nullable() {
84 w.write_line(format!("if (this.tag !== {}) {{ return null; }}", i))?;
85 }
86 w.write_line(format!("return this.get<{}>();", member_type.as_lang()))?;
87 }
88 w.write_line("}")?;
89 }
90 }
91 Ok(())
92 }
93
94 fn define_union_member<T: Write>(
95 w: &mut PrettyWriter<T>,
96 union_name: &str,
97 i: usize,
98 member: &ASUnionMember,
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)?;
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 w.write_line("// @ts-ignore: decorator")?
130 .write_line("@unmanaged")?
131 .write_line(format!("export class {} {{", name.as_type()))?;
132 {
133 let mut w = w.new_block();
134 w.write_line(format!("tag: {};", tag_repr.as_lang()))?;
135 let pad_len = union_.padding_after_tag;
136 for i in 0..(pad_len & 1) {
137 w.write_line(format!("private __pad8_{}: u8;", i))?;
138 }
139 for i in 0..(pad_len & 3) / 2 {
140 w.write_line(format!("private __pad16_{}: u16;", i))?;
141 }
142 for i in 0..(pad_len & 7) / 4 {
143 w.write_line(format!("private __pad32_{}: u32;", i))?;
144 }
145 for i in 0..pad_len / 8 {
146 w.write_line(format!("private __pad64_{}: u64;", i))?;
147 }
148 w.eob()?;
149
150 w.write_line(format!("constructor(tag: {}) {{", tag_repr.as_lang()))?;
151 {
152 let mut w = w.new_block();
153 w.write_line("this.tag = tag;")?.write_line(format!(
154 "memory.fill(changetype<usize>(this) + {}, 0, {});",
155 union_.member_offset, union_.max_member_size
156 ))?;
157 }
158 w.write_line("}")?.eob()?;
159
160 w.write_line("// @ts-ignore: default")?.write_line(format!(
161 "static new<T>(tag: {}, val: T = 0): {} {{",
162 tag_repr.as_lang(),
163 name.as_type()
164 ))?;
165 {
166 let mut w = w.new_block();
167 w.write_line(format!("let tu = new {}(tag);", name.as_type()))?
168 .write_line("tu.set(val);")?
169 .write_line("return tu;")?;
170 }
171 w.write_line("}")?.eob()?;
172
173 w.write_line("get<T>(): T {")?;
174 {
175 let mut w = w.new_block();
176 w.write_line("// @ts-ignore: cast")?
177 .write_line(format!(
178 "let valBuf = changetype<usize>(this) + {};",
179 union_.member_offset
180 ))?
181 .write_line("if (isReference<T>()) {")?;
182 w.new_block().write_line("return changetype<T>(valBuf);")?;
183 w.write_line("} else {")?;
184 w.new_block().write_line("return load<T>(valBuf);")?;
185 w.write_line("}")?;
186 }
187 w.write_line("}")?.eob()?;
188
189 w.write_line("// @ts-ignore: default")?
190 .write_line("set<T>(val: T = 0): void {")?;
191 {
192 let mut w = w.new_block();
193 w.write_line("// @ts-ignore: cast")?
194 .write_line(format!(
195 "let valBuf = changetype<usize>(this) + {};",
196 union_.member_offset
197 ))?
198 .write_line(format!(
199 "memory.fill(valBuf, 0, {});",
200 union_.max_member_size
201 ))?
202 .write_line("if (isReference<T>()) {")?;
203 w.new_block().write_line(
204 "(val !== null) && memory.copy(valBuf, changetype<usize>(val), offsetof<T>());",
205 )?;
206 w.write_line("} else {")?;
207 w.new_block().write_line("store<T>(valBuf, val)")?;
208 w.write_line("}")?;
209 }
210 w.write_line("}")?;
211
212 for (i, member) in union_.members.iter().enumerate() {
213 w.eob()?;
214 Self::define_union_member(&mut w, name, i, member)?;
215 }
216 }
217 w.write_line("}")?.eob()?;
218 Ok(())
219 }
220}