vox_codegen/targets/swift/
decode.rs1use facet_core::{ScalarType, Shape};
7use heck::ToLowerCamelCase;
8use vox_types::{
9 EnumInfo, ShapeKind, StructInfo, VariantKind, classify_shape, classify_variant, is_bytes,
10};
11
12pub fn generate_decode_stmt(shape: &'static Shape, var_name: &str, indent: &str) -> String {
15 generate_decode_stmt_impl(shape, var_name, indent, "buffer")
16}
17
18pub fn generate_decode_stmt_with_cursor(
21 shape: &'static Shape,
22 var_name: &str,
23 indent: &str,
24 _cursor_var: &str,
25) -> String {
26 generate_decode_stmt_impl(shape, var_name, indent, "buffer")
27}
28
29pub fn generate_decode_stmt_from(
32 shape: &'static Shape,
33 var_name: &str,
34 indent: &str,
35 _data_var: &str,
36) -> String {
37 generate_decode_stmt_impl(shape, var_name, indent, "buffer")
38}
39
40pub fn generate_decode_stmt_from_with_cursor(
43 shape: &'static Shape,
44 var_name: &str,
45 indent: &str,
46 _data_var: &str,
47 _cursor_var: &str,
48) -> String {
49 generate_decode_stmt_impl(shape, var_name, indent, "buffer")
50}
51
52pub fn generate_decode_stmt_with_buf(
54 shape: &'static Shape,
55 var_name: &str,
56 indent: &str,
57 buf_name: &str,
58) -> String {
59 generate_decode_stmt_impl(shape, var_name, indent, buf_name)
60}
61
62fn generate_decode_stmt_impl(
63 shape: &'static Shape,
64 var_name: &str,
65 indent: &str,
66 buf_name: &str,
67) -> String {
68 if is_bytes(shape) {
70 return format!(
71 "{indent}var _{var_name}_buf = try decodeBytes(from: &{buf_name})\n{indent}let {var_name} = Data(_{var_name}_buf.readBytes(length: _{var_name}_buf.readableBytes) ?? [])\n"
72 );
73 }
74
75 match classify_shape(shape) {
76 ShapeKind::Scalar(scalar) => {
77 let decode_fn = swift_decode_fn(scalar);
78 format!("{indent}let {var_name} = try {decode_fn}(from: &{buf_name})\n")
79 }
80 ShapeKind::List { element }
81 | ShapeKind::Slice { element }
82 | ShapeKind::Array { element, .. } => {
83 let inner = generate_decode_closure(element);
84 format!("{indent}let {var_name} = try decodeVec(from: &{buf_name}, decoder: {inner})\n")
85 }
86 ShapeKind::Option { inner } => {
87 let inner = generate_decode_closure(inner);
88 format!(
89 "{indent}let {var_name} = try decodeOption(from: &{buf_name}, decoder: {inner})\n"
90 )
91 }
92 ShapeKind::Tuple { elements } if elements.len() == 2 => {
93 let a = generate_decode_closure(elements[0].shape);
94 let b = generate_decode_closure(elements[1].shape);
95 format!(
96 "{indent}let {var_name} = try decodeTuple2(from: &{buf_name}, decoderA: {a}, decoderB: {b})\n"
97 )
98 }
99 ShapeKind::TupleStruct { fields } if fields.len() == 2 => {
100 let a = generate_decode_closure(fields[0].shape());
101 let b = generate_decode_closure(fields[1].shape());
102 format!(
103 "{indent}let {var_name} = try decodeTuple2(from: &{buf_name}, decoderA: {a}, decoderB: {b})\n"
104 )
105 }
106 ShapeKind::Struct(StructInfo {
107 name: Some(name),
108 fields,
109 ..
110 }) => {
111 let mut out = String::new();
113 for f in fields.iter() {
114 let field_name = f.name.to_lower_camel_case();
115 out.push_str(&generate_decode_stmt_impl(
116 f.shape(),
117 &format!("_{var_name}_{field_name}"),
118 indent,
119 buf_name,
120 ));
121 }
122 let field_inits: Vec<String> = fields
123 .iter()
124 .map(|f| {
125 let field_name = f.name.to_lower_camel_case();
126 format!("{field_name}: _{var_name}_{field_name}")
127 })
128 .collect();
129 out.push_str(&format!(
130 "{indent}let {var_name} = {name}({})\n",
131 field_inits.join(", ")
132 ));
133 out
134 }
135 ShapeKind::Enum(EnumInfo {
136 name: Some(name),
137 variants,
138 ..
139 }) => {
140 let mut out = String::new();
141 out.push_str(&format!(
142 "{indent}let _{var_name}_disc = try decodeVarint(from: &{buf_name})\n"
143 ));
144 out.push_str(&format!("{indent}let {var_name}: {name}\n"));
145 out.push_str(&format!("{indent}switch _{var_name}_disc {{\n"));
146 for (i, v) in variants.iter().enumerate() {
147 out.push_str(&format!("{indent}case {i}:\n"));
148 let inner_indent = format!("{indent} ");
149 match classify_variant(v) {
150 VariantKind::Unit => {
151 out.push_str(&format!(
152 "{inner_indent}{var_name} = .{}\n",
153 v.name.to_lower_camel_case()
154 ));
155 }
156 VariantKind::Newtype { inner } => {
157 out.push_str(&generate_decode_stmt_impl(
158 inner,
159 &format!("_{var_name}_val"),
160 &inner_indent,
161 buf_name,
162 ));
163 out.push_str(&format!(
164 "{inner_indent}{var_name} = .{}(_{var_name}_val)\n",
165 v.name.to_lower_camel_case()
166 ));
167 }
168 VariantKind::Tuple { fields } => {
169 for (j, f) in fields.iter().enumerate() {
170 out.push_str(&generate_decode_stmt_impl(
171 f.shape(),
172 &format!("_{var_name}_f{j}"),
173 &inner_indent,
174 buf_name,
175 ));
176 }
177 let args: Vec<String> = (0..fields.len())
178 .map(|j| format!("_{var_name}_f{j}"))
179 .collect();
180 out.push_str(&format!(
181 "{inner_indent}{var_name} = .{}({})\n",
182 v.name.to_lower_camel_case(),
183 args.join(", ")
184 ));
185 }
186 VariantKind::Struct { fields } => {
187 for f in fields.iter() {
188 let field_name = f.name.to_lower_camel_case();
189 out.push_str(&generate_decode_stmt_impl(
190 f.shape(),
191 &format!("_{var_name}_{field_name}"),
192 &inner_indent,
193 buf_name,
194 ));
195 }
196 let args: Vec<String> = fields
197 .iter()
198 .map(|f| {
199 let field_name = f.name.to_lower_camel_case();
200 format!("{field_name}: _{var_name}_{field_name}")
201 })
202 .collect();
203 out.push_str(&format!(
204 "{inner_indent}{var_name} = .{}({})\n",
205 v.name.to_lower_camel_case(),
206 args.join(", ")
207 ));
208 }
209 }
210 }
211 out.push_str(&format!("{indent}default:\n"));
212 out.push_str(&format!(
213 "{indent} throw VoxError.decodeError(\"unknown enum variant\")\n"
214 ));
215 out.push_str(&format!("{indent}}}\n"));
216 out
217 }
218 ShapeKind::Pointer { pointee } => {
219 generate_decode_stmt_impl(pointee, var_name, indent, buf_name)
220 }
221 ShapeKind::Result { ok, err } => {
222 let ok_type = super::types::swift_type_base(ok);
223 let err_type = super::types::swift_type_base(err);
224 let mut out = String::new();
225 out.push_str(&format!(
226 "{indent}let _{var_name}_disc = try decodeVarint(from: &{buf_name})\n"
227 ));
228 out.push_str(&format!(
229 "{indent}let {var_name}: Result<{ok_type}, {err_type}>\n"
230 ));
231 out.push_str(&format!("{indent}switch _{var_name}_disc {{\n"));
232 out.push_str(&format!("{indent}case 0:\n"));
233 let inner_indent = format!("{indent} ");
234 out.push_str(&generate_decode_stmt_impl(
235 ok,
236 &format!("_{var_name}_ok"),
237 &inner_indent,
238 buf_name,
239 ));
240 out.push_str(&format!(
241 "{inner_indent}{var_name} = .success(_{var_name}_ok)\n"
242 ));
243 out.push_str(&format!("{indent}case 1:\n"));
244 out.push_str(&generate_decode_stmt_impl(
245 err,
246 &format!("_{var_name}_err"),
247 &inner_indent,
248 buf_name,
249 ));
250 out.push_str(&format!(
251 "{inner_indent}{var_name} = .failure(_{var_name}_err)\n"
252 ));
253 out.push_str(&format!("{indent}default:\n"));
254 out.push_str(&format!(
255 "{indent} throw VoxError.decodeError(\"invalid Result discriminant\")\n"
256 ));
257 out.push_str(&format!("{indent}}}\n"));
258 out
259 }
260 _ => {
261 format!("{indent}let {var_name}: Any = () // unsupported type\n")
262 }
263 }
264}
265
266pub fn generate_decode_closure(shape: &'static Shape) -> String {
269 if is_bytes(shape) {
270 return "{ buf in var _b = try decodeBytes(from: &buf); return Data(_b.readBytes(length: _b.readableBytes) ?? []) }".into();
272 }
273
274 match classify_shape(shape) {
275 ShapeKind::Scalar(scalar) => {
276 let decode_fn = swift_decode_fn(scalar);
277 format!("{{ buf in try {decode_fn}(from: &buf) }}")
278 }
279 ShapeKind::List { element } | ShapeKind::Slice { element } => {
280 let inner = generate_decode_closure(element);
281 format!("{{ buf in try decodeVec(from: &buf, decoder: {inner}) }}")
282 }
283 ShapeKind::Option { inner } => {
284 let inner = generate_decode_closure(inner);
285 format!("{{ buf in try decodeOption(from: &buf, decoder: {inner}) }}")
286 }
287 ShapeKind::Tuple { elements } if elements.len() == 2 => {
288 let a = generate_decode_closure(elements[0].shape);
289 let b = generate_decode_closure(elements[1].shape);
290 format!("{{ buf in try decodeTuple2(from: &buf, decoderA: {a}, decoderB: {b}) }}")
291 }
292 ShapeKind::TupleStruct { fields } if fields.len() == 2 => {
293 let a = generate_decode_closure(fields[0].shape());
294 let b = generate_decode_closure(fields[1].shape());
295 format!("{{ buf in try decodeTuple2(from: &buf, decoderA: {a}, decoderB: {b}) }}")
296 }
297 ShapeKind::Struct(StructInfo {
298 name: Some(name),
299 fields,
300 ..
301 }) => {
302 let mut code = "{ buf in\n".to_string();
304 for f in fields.iter() {
305 let field_name = f.name.to_lower_camel_case();
306 let inner = generate_decode_closure(f.shape());
307 code.push_str(&format!(" let _{field_name} = try ({inner})(&buf)\n"));
308 }
309 let field_inits: Vec<String> = fields
310 .iter()
311 .map(|f| {
312 let field_name = f.name.to_lower_camel_case();
313 format!("{field_name}: _{field_name}")
314 })
315 .collect();
316 code.push_str(&format!(
317 " return {name}({})\n}}",
318 field_inits.join(", ")
319 ));
320 code
321 }
322 ShapeKind::Enum(EnumInfo {
323 name: Some(name),
324 variants,
325 ..
326 }) => {
327 let mut code = format!(
328 "{{ buf in\n let disc = try decodeVarint(from: &buf)\n let result: {name}\n switch disc {{\n"
329 );
330 for (i, v) in variants.iter().enumerate() {
331 code.push_str(&format!(" case {i}:\n"));
332 match classify_variant(v) {
333 VariantKind::Unit => {
334 code.push_str(&format!(
335 " result = .{}\n",
336 v.name.to_lower_camel_case()
337 ));
338 }
339 VariantKind::Newtype { inner } => {
340 let inner_closure = generate_decode_closure(inner);
341 code.push_str(&format!(
342 " let val = try ({inner_closure})(&buf)\n result = .{}(val)\n",
343 v.name.to_lower_camel_case()
344 ));
345 }
346 VariantKind::Tuple { fields } => {
347 for (j, f) in fields.iter().enumerate() {
348 let inner = generate_decode_closure(f.shape());
349 code.push_str(&format!(" let f{j} = try ({inner})(&buf)\n"));
350 }
351 let args: Vec<String> =
352 (0..fields.len()).map(|j| format!("f{j}")).collect();
353 code.push_str(&format!(
354 " result = .{}({})\n",
355 v.name.to_lower_camel_case(),
356 args.join(", ")
357 ));
358 }
359 VariantKind::Struct { fields } => {
360 for f in fields.iter() {
361 let field_name = f.name.to_lower_camel_case();
362 let inner = generate_decode_closure(f.shape());
363 code.push_str(&format!(
364 " let _{field_name} = try ({inner})(&buf)\n"
365 ));
366 }
367 let args: Vec<String> = fields
368 .iter()
369 .map(|f| {
370 let field_name = f.name.to_lower_camel_case();
371 format!("{field_name}: _{field_name}")
372 })
373 .collect();
374 code.push_str(&format!(
375 " result = .{}({})\n",
376 v.name.to_lower_camel_case(),
377 args.join(", ")
378 ));
379 }
380 }
381 }
382 code.push_str(
383 " default:\n throw VoxError.decodeError(\"unknown enum variant\")\n }\n return result\n}",
384 );
385 code
386 }
387 ShapeKind::Pointer { pointee } => generate_decode_closure(pointee),
388 _ => "{ _ in throw VoxError.decodeError(\"unsupported type\") }".into(),
389 }
390}
391
392pub fn generate_inline_decode(shape: &'static Shape, _data_var: &str, _offset_var: &str) -> String {
395 let closure = generate_decode_closure(shape);
397 format!("({closure})(&buf)")
398}
399
400pub fn swift_decode_fn(scalar: ScalarType) -> &'static str {
402 match scalar {
403 ScalarType::Bool => "decodeBool",
404 ScalarType::U8 => "decodeU8",
405 ScalarType::I8 => "decodeI8",
406 ScalarType::U16 => "decodeU16",
407 ScalarType::I16 => "decodeI16",
408 ScalarType::U32 => "decodeU32",
409 ScalarType::I32 => "decodeI32",
410 ScalarType::U64 | ScalarType::USize => "decodeVarint",
411 ScalarType::I64 | ScalarType::ISize => "decodeI64",
412 ScalarType::F32 => "decodeF32",
413 ScalarType::F64 => "decodeF64",
414 ScalarType::Char | ScalarType::Str | ScalarType::CowStr | ScalarType::String => {
415 "decodeString"
416 }
417 ScalarType::Unit => "{ _ in () }",
418 _ => "decodeBytes",
419 }
420}