Skip to main content

vox_codegen/targets/swift/
decode.rs

1//! Swift decoding statement generation.
2//!
3//! Generates Swift code that decodes values from an `inout ByteBuffer`.
4//! All decode functions take `inout ByteBuffer` and advance its reader index.
5
6use super::types::swift_field_name;
7use facet_core::{ScalarType, Shape};
8use vox_types::{
9    EnumInfo, ShapeKind, StructInfo, VariantKind, classify_shape, classify_variant, is_bytes,
10};
11
12/// Generate a Swift decode statement for a given shape.
13/// Returns code that decodes from `buffer` into a variable named `var_name`.
14pub 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
18/// Generate a Swift decode statement for a given shape using a custom cursor variable name.
19/// (cursor_var is now ignored — kept for call-site compatibility, buffer is always `buffer`)
20pub 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
29/// Generate a Swift decode statement from a specific data variable.
30/// (data_var is now ignored — kept for call-site compatibility, buffer is always `buffer`)
31pub 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
40/// Generate a Swift decode statement from a specific data variable and cursor.
41/// (data_var and cursor_var are now ignored — kept for call-site compatibility)
42pub 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
52/// Core implementation: generate a decode statement that reads from the named buffer variable.
53pub 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    // bytes → ByteBuffer slice, presented as Data for the user-facing type
69    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        // Unit reads zero bytes off the wire. Emit a plain assignment;
77        // calling `swift_decode_fn(Unit)` would produce a closure
78        // expression that the surrounding `try {fn}(from: &buf)`
79        // template can't invoke (gives "extraneous argument label
80        // 'from:' in call").
81        ShapeKind::Scalar(facet_core::ScalarType::Unit) => {
82            format!("{indent}let {var_name}: Void = ()\n")
83        }
84        ShapeKind::Tuple { elements: [] } => {
85            format!("{indent}let {var_name}: Void = ()\n")
86        }
87        ShapeKind::Tuple { elements } if elements.len() == 2 => {
88            let a = generate_decode_closure(elements[0].shape);
89            let b = generate_decode_closure(elements[1].shape);
90            format!(
91                "{indent}let {var_name} = try decodeTuple2(from: &{buf_name}, decoderA: {a}, decoderB: {b})\n"
92            )
93        }
94        ShapeKind::Scalar(scalar) => {
95            let decode_fn = swift_decode_fn(scalar);
96            format!("{indent}let {var_name} = try {decode_fn}(from: &{buf_name})\n")
97        }
98        ShapeKind::List { element }
99        | ShapeKind::Slice { element }
100        | ShapeKind::Array { element, .. } => {
101            let inner = generate_decode_closure(element);
102            format!("{indent}let {var_name} = try decodeVec(from: &{buf_name}, decoder: {inner})\n")
103        }
104        ShapeKind::Option { inner } => {
105            let inner = generate_decode_closure(inner);
106            format!(
107                "{indent}let {var_name} = try decodeOption(from: &{buf_name}, decoder: {inner})\n"
108            )
109        }
110        ShapeKind::TupleStruct { fields } if fields.len() == 2 => {
111            let a = generate_decode_closure(fields[0].shape());
112            let b = generate_decode_closure(fields[1].shape());
113            format!(
114                "{indent}let {var_name} = try decodeTuple2(from: &{buf_name}, decoderA: {a}, decoderB: {b})\n"
115            )
116        }
117        ShapeKind::Struct(StructInfo {
118            name: Some(name),
119            fields,
120            ..
121        }) => {
122            // Named struct — decode each field then construct
123            let mut out = String::new();
124            for f in fields.iter() {
125                let field_name = swift_field_name(f.name);
126                out.push_str(&generate_decode_stmt_impl(
127                    f.shape(),
128                    &format!("_{var_name}_{field_name}"),
129                    indent,
130                    buf_name,
131                ));
132            }
133            let field_inits: Vec<String> = fields
134                .iter()
135                .map(|f| {
136                    let field_name = swift_field_name(f.name);
137                    format!("{field_name}: _{var_name}_{field_name}")
138                })
139                .collect();
140            out.push_str(&format!(
141                "{indent}let {var_name} = {name}({})\n",
142                field_inits.join(", ")
143            ));
144            out
145        }
146        ShapeKind::Enum(EnumInfo {
147            name: Some(name),
148            variants,
149            ..
150        }) => {
151            let mut out = String::new();
152            out.push_str(&format!(
153                "{indent}let _{var_name}_disc = try decodeVarint(from: &{buf_name})\n"
154            ));
155            out.push_str(&format!("{indent}let {var_name}: {name}\n"));
156            out.push_str(&format!("{indent}switch _{var_name}_disc {{\n"));
157            for (i, v) in variants.iter().enumerate() {
158                out.push_str(&format!("{indent}case {i}:\n"));
159                let inner_indent = format!("{indent}    ");
160                match classify_variant(v) {
161                    VariantKind::Unit => {
162                        out.push_str(&format!(
163                            "{inner_indent}{var_name} = .{}\n",
164                            swift_field_name(v.name)
165                        ));
166                    }
167                    VariantKind::Newtype { inner } => {
168                        out.push_str(&generate_decode_stmt_impl(
169                            inner,
170                            &format!("_{var_name}_val"),
171                            &inner_indent,
172                            buf_name,
173                        ));
174                        out.push_str(&format!(
175                            "{inner_indent}{var_name} = .{}(_{var_name}_val)\n",
176                            swift_field_name(v.name)
177                        ));
178                    }
179                    VariantKind::Tuple { fields } => {
180                        for (j, f) in fields.iter().enumerate() {
181                            out.push_str(&generate_decode_stmt_impl(
182                                f.shape(),
183                                &format!("_{var_name}_f{j}"),
184                                &inner_indent,
185                                buf_name,
186                            ));
187                        }
188                        let args: Vec<String> = (0..fields.len())
189                            .map(|j| format!("_{var_name}_f{j}"))
190                            .collect();
191                        out.push_str(&format!(
192                            "{inner_indent}{var_name} = .{}({})\n",
193                            swift_field_name(v.name),
194                            args.join(", ")
195                        ));
196                    }
197                    VariantKind::Struct { fields } => {
198                        for f in fields.iter() {
199                            let field_name = swift_field_name(f.name);
200                            out.push_str(&generate_decode_stmt_impl(
201                                f.shape(),
202                                &format!("_{var_name}_{field_name}"),
203                                &inner_indent,
204                                buf_name,
205                            ));
206                        }
207                        let args: Vec<String> = fields
208                            .iter()
209                            .map(|f| {
210                                let field_name = swift_field_name(f.name);
211                                format!("{field_name}: _{var_name}_{field_name}")
212                            })
213                            .collect();
214                        out.push_str(&format!(
215                            "{inner_indent}{var_name} = .{}({})\n",
216                            swift_field_name(v.name),
217                            args.join(", ")
218                        ));
219                    }
220                }
221            }
222            out.push_str(&format!("{indent}default:\n"));
223            out.push_str(&format!(
224                "{indent}    throw VoxError.decodeError(\"unknown enum variant\")\n"
225            ));
226            out.push_str(&format!("{indent}}}\n"));
227            out
228        }
229        ShapeKind::Pointer { pointee } => {
230            generate_decode_stmt_impl(pointee, var_name, indent, buf_name)
231        }
232        ShapeKind::Result { ok, err } => {
233            let ok_type = super::types::swift_type_base(ok);
234            let err_type = super::types::swift_type_base(err);
235            let mut out = String::new();
236            out.push_str(&format!(
237                "{indent}let _{var_name}_disc = try decodeVarint(from: &{buf_name})\n"
238            ));
239            out.push_str(&format!(
240                "{indent}let {var_name}: Result<{ok_type}, {err_type}>\n"
241            ));
242            out.push_str(&format!("{indent}switch _{var_name}_disc {{\n"));
243            out.push_str(&format!("{indent}case 0:\n"));
244            let inner_indent = format!("{indent}    ");
245            out.push_str(&generate_decode_stmt_impl(
246                ok,
247                &format!("_{var_name}_ok"),
248                &inner_indent,
249                buf_name,
250            ));
251            out.push_str(&format!(
252                "{inner_indent}{var_name} = .success(_{var_name}_ok)\n"
253            ));
254            out.push_str(&format!("{indent}case 1:\n"));
255            out.push_str(&generate_decode_stmt_impl(
256                err,
257                &format!("_{var_name}_err"),
258                &inner_indent,
259                buf_name,
260            ));
261            out.push_str(&format!(
262                "{inner_indent}{var_name} = .failure(_{var_name}_err)\n"
263            ));
264            out.push_str(&format!("{indent}default:\n"));
265            out.push_str(&format!(
266                "{indent}    throw VoxError.decodeError(\"invalid Result discriminant\")\n"
267            ));
268            out.push_str(&format!("{indent}}}\n"));
269            out
270        }
271        _ => {
272            format!("{indent}let {var_name}: Any = () // unsupported type\n")
273        }
274    }
275}
276
277/// Generate a Swift decode closure `(inout ByteBuffer) throws -> T` for use with
278/// `decodeVec`, `decodeOption`, etc.
279pub fn generate_decode_closure(shape: &'static Shape) -> String {
280    if is_bytes(shape) {
281        // decodeBytes returns ByteBuffer; convert to Data for user-facing type
282        return "{ buf in var _b = try decodeBytes(from: &buf); return Data(_b.readBytes(length: _b.readableBytes) ?? []) }".into();
283    }
284
285    match classify_shape(shape) {
286        ShapeKind::Scalar(scalar) => {
287            let decode_fn = swift_decode_fn(scalar);
288            format!("{{ buf in try {decode_fn}(from: &buf) }}")
289        }
290        ShapeKind::List { element } | ShapeKind::Slice { element } => {
291            let inner = generate_decode_closure(element);
292            format!("{{ buf in try decodeVec(from: &buf, decoder: {inner}) }}")
293        }
294        ShapeKind::Option { inner } => {
295            let inner = generate_decode_closure(inner);
296            format!("{{ buf in try decodeOption(from: &buf, decoder: {inner}) }}")
297        }
298        ShapeKind::Tuple { elements } if elements.len() == 2 => {
299            let a = generate_decode_closure(elements[0].shape);
300            let b = generate_decode_closure(elements[1].shape);
301            format!("{{ buf in try decodeTuple2(from: &buf, decoderA: {a}, decoderB: {b}) }}")
302        }
303        ShapeKind::TupleStruct { fields } if fields.len() == 2 => {
304            let a = generate_decode_closure(fields[0].shape());
305            let b = generate_decode_closure(fields[1].shape());
306            format!("{{ buf in try decodeTuple2(from: &buf, decoderA: {a}, decoderB: {b}) }}")
307        }
308        ShapeKind::Struct(StructInfo {
309            name: Some(name), ..
310        }) => {
311            // Named struct — delegate to the top-level decoder so we
312            // don't recurse infinitely on self-referential types
313            // (FlameNode { children: Vec<FlameNode> }).
314            let fn_name = named_type_decode_fn_name(name);
315            format!("{{ buf in try {fn_name}(from: &buf) }}")
316        }
317        ShapeKind::Enum(EnumInfo {
318            name: Some(name), ..
319        }) => {
320            let fn_name = named_type_decode_fn_name(name);
321            format!("{{ buf in try {fn_name}(from: &buf) }}")
322        }
323        // Anonymous enums aren't expressible in Swift — fall through to
324        // the unsupported branch.
325        ShapeKind::Enum(EnumInfo { name: None, .. }) => {
326            "{ _ in throw VoxError.decodeError(\"anonymous enum unsupported\") }".into()
327        }
328        ShapeKind::Pointer { pointee } => generate_decode_closure(pointee),
329        _ => "{ _ in throw VoxError.decodeError(\"unsupported type\") }".into(),
330    }
331}
332
333/// The name of the generated decode function for a named type.
334pub fn named_type_decode_fn_name(name: &str) -> String {
335    format!("decode{name}")
336}
337
338/// Generate a top-level `decode<Name>(from:)` function for a named struct or enum.
339pub fn generate_named_type_decode_fn(name: &str, shape: &'static Shape) -> String {
340    let mut out = String::new();
341    let fn_name = named_type_decode_fn_name(name);
342    out.push_str(&format!(
343        "nonisolated internal func {fn_name}(from buffer: inout ByteBuffer) throws -> {name} {{\n"
344    ));
345
346    match classify_shape(shape) {
347        ShapeKind::Struct(StructInfo { fields, .. }) => {
348            for f in fields.iter() {
349                let field_name = swift_field_name(f.name);
350                let inner = generate_decode_closure(f.shape());
351                out.push_str(&format!("    let _{field_name} = try ({inner})(&buffer)\n"));
352            }
353            let inits: Vec<String> = fields
354                .iter()
355                .map(|f| {
356                    let n = swift_field_name(f.name);
357                    format!("{n}: _{n}")
358                })
359                .collect();
360            out.push_str(&format!("    return {name}({})\n", inits.join(", ")));
361        }
362        ShapeKind::Enum(EnumInfo { variants, .. }) => {
363            out.push_str("    let disc = try decodeVarint(from: &buffer)\n");
364            out.push_str(&format!("    let result: {name}\n"));
365            out.push_str("    switch disc {\n");
366            for (i, v) in variants.iter().enumerate() {
367                out.push_str(&format!("    case {i}:\n"));
368                match classify_variant(v) {
369                    VariantKind::Unit => {
370                        out.push_str(&format!("        result = .{}\n", swift_field_name(v.name)));
371                    }
372                    VariantKind::Newtype { inner } => {
373                        let inner_closure = generate_decode_closure(inner);
374                        out.push_str(&format!(
375                            "        let val = try ({inner_closure})(&buffer)\n        result = .{}(val)\n",
376                            swift_field_name(v.name)
377                        ));
378                    }
379                    VariantKind::Tuple { fields } => {
380                        for (j, f) in fields.iter().enumerate() {
381                            let inner = generate_decode_closure(f.shape());
382                            out.push_str(&format!("        let f{j} = try ({inner})(&buffer)\n"));
383                        }
384                        let args: Vec<String> =
385                            (0..fields.len()).map(|j| format!("f{j}")).collect();
386                        out.push_str(&format!(
387                            "        result = .{}({})\n",
388                            swift_field_name(v.name),
389                            args.join(", ")
390                        ));
391                    }
392                    VariantKind::Struct { fields } => {
393                        for f in fields.iter() {
394                            let field_name = swift_field_name(f.name);
395                            let inner = generate_decode_closure(f.shape());
396                            out.push_str(&format!(
397                                "        let _{field_name} = try ({inner})(&buffer)\n"
398                            ));
399                        }
400                        let args: Vec<String> = fields
401                            .iter()
402                            .map(|f| {
403                                let n = swift_field_name(f.name);
404                                format!("{n}: _{n}")
405                            })
406                            .collect();
407                        out.push_str(&format!(
408                            "        result = .{}({})\n",
409                            swift_field_name(v.name),
410                            args.join(", ")
411                        ));
412                    }
413                }
414            }
415            out.push_str(
416                "    default:\n        throw VoxError.decodeError(\"unknown enum variant\")\n    }\n    return result\n",
417            );
418        }
419        _ => {}
420    }
421
422    out.push_str("}\n");
423    out
424}
425
426/// Generate decode functions for every named type.
427pub fn generate_named_type_decode_fns(named_types: &[(String, &'static Shape)]) -> String {
428    named_types
429        .iter()
430        .map(|(name, shape)| generate_named_type_decode_fn(name, shape))
431        .collect::<Vec<_>>()
432        .join("\n")
433}
434
435/// Generate inline decode expression — just the expression part, no `let x =`.
436/// Used internally where a closure calls another closure.
437pub fn generate_inline_decode(shape: &'static Shape, _data_var: &str, _offset_var: &str) -> String {
438    // data_var and offset_var are ignored — we always use `buf` (the closure parameter)
439    let closure = generate_decode_closure(shape);
440    format!("({closure})(&buf)")
441}
442
443/// Get the Swift decode function name for a scalar type.
444pub fn swift_decode_fn(scalar: ScalarType) -> &'static str {
445    match scalar {
446        ScalarType::Bool => "decodeBool",
447        ScalarType::U8 => "decodeU8",
448        ScalarType::I8 => "decodeI8",
449        ScalarType::U16 => "decodeU16",
450        ScalarType::I16 => "decodeI16",
451        ScalarType::U32 => "decodeU32",
452        ScalarType::I32 => "decodeI32",
453        ScalarType::U64 | ScalarType::USize => "decodeVarint",
454        ScalarType::I64 | ScalarType::ISize => "decodeI64",
455        ScalarType::F32 => "decodeF32",
456        ScalarType::F64 => "decodeF64",
457        ScalarType::Char | ScalarType::Str | ScalarType::CowStr | ScalarType::String => {
458            "decodeString"
459        }
460        ScalarType::Unit => "{ _ in () }",
461        _ => "decodeBytes",
462    }
463}