vox_codegen/targets/swift/
encode.rs1use facet_core::{ScalarType, Shape};
8use heck::ToLowerCamelCase;
9use vox_types::{
10 EnumInfo, ShapeKind, StructInfo, VariantKind, classify_shape, classify_variant, is_bytes,
11};
12
13pub fn generate_encode_stmt(shape: &'static Shape, value: &str) -> String {
16 if is_bytes(shape) {
17 return format!("encodeByteSeq({value}, into: &buffer)");
18 }
19
20 match classify_shape(shape) {
21 ShapeKind::Scalar(scalar) => {
22 let fn_name = swift_encode_fn(scalar);
23 format!("{fn_name}({value}, into: &buffer)")
24 }
25 ShapeKind::List { element }
26 | ShapeKind::Slice { element }
27 | ShapeKind::Array { element, .. } => {
28 let inner = generate_encode_closure(element);
29 format!("encodeVec({value}, into: &buffer, encoder: {inner})")
30 }
31 ShapeKind::Option { inner } => {
32 let inner = generate_encode_closure(inner);
33 format!("encodeOption({value}, into: &buffer, encoder: {inner})")
34 }
35 ShapeKind::Tx { .. } | ShapeKind::Rx { .. } => {
36 format!("encodeVarint({value}.channelId, into: &buffer)")
37 }
38 ShapeKind::Tuple { elements } if elements.len() == 2 => {
39 let a = generate_encode_stmt(elements[0].shape, &format!("{value}.0"));
40 let b = generate_encode_stmt(elements[1].shape, &format!("{value}.1"));
41 format!("{a}\n{b}")
42 }
43 ShapeKind::TupleStruct { fields } if fields.len() == 2 => {
44 let a = generate_encode_stmt(fields[0].shape(), &format!("{value}.0"));
45 let b = generate_encode_stmt(fields[1].shape(), &format!("{value}.1"));
46 format!("{a}\n{b}")
47 }
48 ShapeKind::Struct(StructInfo {
49 name: Some(name), ..
50 }) => {
51 let fn_name = named_type_encode_fn_name(name);
52 format!("{fn_name}({value}, into: &buffer)")
53 }
54 ShapeKind::Struct(StructInfo {
55 name: None, fields, ..
56 }) => {
57 let stmts: Vec<String> = fields
59 .iter()
60 .map(|f| {
61 let field_name = f.name.to_lower_camel_case();
62 generate_encode_stmt(f.shape(), &format!("{value}.{field_name}"))
63 })
64 .collect();
65 stmts.join("\n")
66 }
67 ShapeKind::Enum(EnumInfo {
68 name: Some(name), ..
69 }) => {
70 let fn_name = named_type_encode_fn_name(name);
71 format!("{fn_name}({value}, into: &buffer)")
72 }
73 ShapeKind::Enum(EnumInfo { name: None, .. }) => {
74 let closure = generate_encode_closure(shape);
76 format!("{closure}({value}, &buffer)")
77 }
78 ShapeKind::Pointer { pointee } => generate_encode_stmt(pointee, value),
79 ShapeKind::Result { ok, err } => {
80 let ok_stmt = generate_encode_stmt(ok, "v");
81 let err_stmt = generate_encode_stmt(err, "e");
82 format!(
83 "switch {value} {{\ncase .success(let v):\n encodeVarint(UInt64(0), into: &buffer)\n {ok_stmt}\ncase .failure(let e):\n encodeVarint(UInt64(1), into: &buffer)\n {err_stmt}\n}}"
84 )
85 }
86 _ => format!("/* unsupported encode for {value} */"),
87 }
88}
89
90pub fn generate_encode_closure(shape: &'static Shape) -> String {
93 if is_bytes(shape) {
94 return "{ val, buf in encodeByteSeq(val, into: &buf) }".into();
95 }
96
97 match classify_shape(shape) {
98 ShapeKind::Scalar(scalar) => {
99 let fn_name = swift_encode_fn(scalar);
100 format!("{{ val, buf in {fn_name}(val, into: &buf) }}")
101 }
102 ShapeKind::List { element } | ShapeKind::Slice { element } => {
103 let inner = generate_encode_closure(element);
104 format!("{{ val, buf in encodeVec(val, into: &buf, encoder: {inner}) }}")
105 }
106 ShapeKind::Option { inner } => {
107 let inner = generate_encode_closure(inner);
108 format!("{{ val, buf in encodeOption(val, into: &buf, encoder: {inner}) }}")
109 }
110 ShapeKind::Tx { .. } | ShapeKind::Rx { .. } => {
111 "{ val, buf in encodeVarint(val.channelId, into: &buf) }".into()
112 }
113 ShapeKind::Tuple { elements } if elements.len() == 2 => {
114 let a = encode_call_expr(elements[0].shape, "val.0", "buf");
115 let b = encode_call_expr(elements[1].shape, "val.1", "buf");
116 format!("{{ val, buf in {a}; {b} }}")
117 }
118 ShapeKind::TupleStruct { fields } if fields.len() == 2 => {
119 let a = encode_call_expr(fields[0].shape(), "val.0", "buf");
120 let b = encode_call_expr(fields[1].shape(), "val.1", "buf");
121 format!("{{ val, buf in {a}; {b} }}")
122 }
123 ShapeKind::Struct(StructInfo {
124 name: Some(name), ..
125 }) => {
126 let fn_name = named_type_encode_fn_name(name);
127 format!("{{ val, buf in {fn_name}(val, into: &buf) }}")
128 }
129 ShapeKind::Struct(StructInfo {
130 name: None, fields, ..
131 }) => {
132 let stmts: Vec<String> = fields
134 .iter()
135 .map(|f| {
136 let field_name = f.name.to_lower_camel_case();
137 let inner = generate_encode_closure(f.shape());
138 format!("{inner}(val.{field_name}, &buf)")
139 })
140 .collect();
141 if stmts.is_empty() {
142 "{ _, _ in }".into()
143 } else {
144 format!("{{ val, buf in {} }}", stmts.join("; "))
145 }
146 }
147 ShapeKind::Enum(EnumInfo {
148 name: Some(name), ..
149 }) => {
150 let fn_name = named_type_encode_fn_name(name);
151 format!("{{ val, buf in {fn_name}(val, into: &buf) }}")
152 }
153 ShapeKind::Enum(EnumInfo {
154 name: None,
155 variants,
156 }) => {
157 let mut code = "{ val, buf in\nswitch val {\n".to_string();
159 for (i, v) in variants.iter().enumerate() {
160 let variant_name = v.name.to_lower_camel_case();
161 match classify_variant(v) {
162 VariantKind::Unit => {
163 code.push_str(&format!(
164 "case .{variant_name}: encodeVarint(UInt64({i}), into: &buf)\n"
165 ));
166 }
167 VariantKind::Newtype { inner } => {
168 let inner_closure = generate_encode_closure(inner);
169 code.push_str(&format!(
170 "case .{variant_name}(let v): encodeVarint(UInt64({i}), into: &buf); {inner_closure}(v, &buf)\n"
171 ));
172 }
173 VariantKind::Tuple { fields } => {
174 let bindings: Vec<String> =
175 (0..fields.len()).map(|j| format!("f{j}")).collect();
176 let stmts: Vec<String> = fields
177 .iter()
178 .enumerate()
179 .map(|(j, f)| {
180 let c = generate_encode_closure(f.shape());
181 format!("{c}(f{j}, &buf)")
182 })
183 .collect();
184 code.push_str(&format!(
185 "case .{variant_name}({}): encodeVarint(UInt64({i}), into: &buf); {}\n",
186 bindings
187 .iter()
188 .map(|b| format!("let {b}"))
189 .collect::<Vec<_>>()
190 .join(", "),
191 stmts.join("; ")
192 ));
193 }
194 VariantKind::Struct { fields } => {
195 let bindings: Vec<String> = fields
196 .iter()
197 .map(|f| f.name.to_lower_camel_case())
198 .collect();
199 let stmts: Vec<String> = fields
200 .iter()
201 .map(|f| {
202 let field_name = f.name.to_lower_camel_case();
203 let c = generate_encode_closure(f.shape());
204 format!("{c}({field_name}, &buf)")
205 })
206 .collect();
207 code.push_str(&format!(
208 "case .{variant_name}({}): encodeVarint(UInt64({i}), into: &buf); {}\n",
209 bindings
210 .iter()
211 .map(|b| format!("let {b}"))
212 .collect::<Vec<_>>()
213 .join(", "),
214 stmts.join("; ")
215 ));
216 }
217 }
218 }
219 code.push_str("} }");
220 code
221 }
222 ShapeKind::Pointer { pointee } => generate_encode_closure(pointee),
223 ShapeKind::Result { ok, err } => {
224 let ok_closure = generate_encode_closure(ok);
225 let err_closure = generate_encode_closure(err);
226 format!(
227 "{{ val, buf in switch val {{ case .success(let v): encodeVarint(UInt64(0), into: &buf); {ok_closure}(v, &buf); case .failure(let e): encodeVarint(UInt64(1), into: &buf); {err_closure}(e, &buf) }} }}"
228 )
229 }
230 _ => "{ _, _ in /* unsupported */ }".into(),
231 }
232}
233
234pub fn generate_named_type_encode_fn(name: &str, shape: &'static Shape) -> String {
237 let fn_name = named_type_encode_fn_name(name);
238 let mut out = String::new();
239 out.push_str(&format!(
240 "nonisolated internal func {fn_name}(_ value: {name}, into buffer: inout ByteBuffer) {{\n"
241 ));
242
243 match classify_shape(shape) {
244 ShapeKind::Struct(StructInfo { fields, .. }) => {
245 for f in fields {
246 let field_name = f.name.to_lower_camel_case();
247 let stmt = generate_encode_stmt(f.shape(), &format!("value.{field_name}"));
248 for line in stmt.lines() {
249 out.push_str(&format!(" {line}\n"));
250 }
251 }
252 }
253 ShapeKind::Enum(EnumInfo { variants, .. }) => {
254 out.push_str(" switch value {\n");
255 for (i, v) in variants.iter().enumerate() {
256 let variant_name = v.name.to_lower_camel_case();
257 match classify_variant(v) {
258 VariantKind::Unit => {
259 out.push_str(&format!(
260 " case .{variant_name}:\n encodeVarint(UInt64({i}), into: &buffer)\n"
261 ));
262 }
263 VariantKind::Newtype { inner } => {
264 let stmt = generate_encode_stmt(inner, "val");
265 out.push_str(&format!(
266 " case .{variant_name}(let val):\n encodeVarint(UInt64({i}), into: &buffer)\n"
267 ));
268 for line in stmt.lines() {
269 out.push_str(&format!(" {line}\n"));
270 }
271 }
272 VariantKind::Tuple { fields } => {
273 let bindings: Vec<String> =
274 (0..fields.len()).map(|j| format!("f{j}")).collect();
275 let binding_str = bindings
276 .iter()
277 .map(|b| format!("let {b}"))
278 .collect::<Vec<_>>()
279 .join(", ");
280 out.push_str(&format!(
281 " case .{variant_name}({binding_str}):\n encodeVarint(UInt64({i}), into: &buffer)\n"
282 ));
283 for (j, f) in fields.iter().enumerate() {
284 let stmt = generate_encode_stmt(f.shape(), &format!("f{j}"));
285 for line in stmt.lines() {
286 out.push_str(&format!(" {line}\n"));
287 }
288 }
289 }
290 VariantKind::Struct { fields } => {
291 let bindings: Vec<String> = fields
292 .iter()
293 .map(|f| f.name.to_lower_camel_case())
294 .collect();
295 let binding_str = bindings
296 .iter()
297 .map(|b| format!("let {b}"))
298 .collect::<Vec<_>>()
299 .join(", ");
300 out.push_str(&format!(
301 " case .{variant_name}({binding_str}):\n encodeVarint(UInt64({i}), into: &buffer)\n"
302 ));
303 for f in fields {
304 let field_name = f.name.to_lower_camel_case();
305 let stmt = generate_encode_stmt(f.shape(), &field_name);
306 for line in stmt.lines() {
307 out.push_str(&format!(" {line}\n"));
308 }
309 }
310 }
311 }
312 }
313 out.push_str(" }\n");
314 }
315 _ => {}
316 }
317
318 out.push_str("}\n");
319 out
320}
321
322pub fn generate_named_type_encode_fns(named_types: &[(String, &'static Shape)]) -> String {
324 named_types
325 .iter()
326 .map(|(name, shape)| generate_named_type_encode_fn(name, shape))
327 .collect::<Vec<_>>()
328 .join("\n")
329}
330
331pub fn named_type_encode_fn_name(name: &str) -> String {
333 format!("encode{name}")
334}
335
336fn encode_call_expr(shape: &'static Shape, value: &str, buf: &str) -> String {
339 if is_bytes(shape) {
340 return format!("encodeByteSeq({value}, into: &{buf})");
341 }
342 match classify_shape(shape) {
343 ShapeKind::Scalar(scalar) => {
344 let fn_name = swift_encode_fn(scalar);
345 format!("{fn_name}({value}, into: &{buf})")
346 }
347 ShapeKind::Struct(StructInfo {
348 name: Some(name), ..
349 })
350 | ShapeKind::Enum(EnumInfo {
351 name: Some(name), ..
352 }) => {
353 let fn_name = named_type_encode_fn_name(name);
354 format!("{fn_name}({value}, into: &{buf})")
355 }
356 ShapeKind::List { element } | ShapeKind::Slice { element } => {
357 let inner = generate_encode_closure(element);
358 format!("encodeVec({value}, into: &{buf}, encoder: {inner})")
359 }
360 ShapeKind::Option { inner } => {
361 let inner = generate_encode_closure(inner);
362 format!("encodeOption({value}, into: &{buf}, encoder: {inner})")
363 }
364 ShapeKind::Pointer { pointee } => encode_call_expr(pointee, value, buf),
365 ShapeKind::Tx { .. } | ShapeKind::Rx { .. } => {
366 format!("encodeVarint({value}.channelId, into: &{buf})")
367 }
368 _ => {
369 let closure = generate_encode_closure(shape);
371 format!("({closure})({value}, &{buf})")
372 }
373 }
374}
375
376pub fn swift_encode_fn(scalar: ScalarType) -> &'static str {
378 match scalar {
379 ScalarType::Bool => "encodeBool",
380 ScalarType::U8 => "encodeU8",
381 ScalarType::I8 => "encodeI8",
382 ScalarType::U16 => "encodeU16",
383 ScalarType::I16 => "encodeI16",
384 ScalarType::U32 => "encodeU32",
385 ScalarType::I32 => "encodeI32",
386 ScalarType::U64 | ScalarType::USize => "encodeVarint",
387 ScalarType::I64 | ScalarType::ISize => "encodeI64",
388 ScalarType::F32 => "encodeF32",
389 ScalarType::F64 => "encodeF64",
390 ScalarType::Char | ScalarType::Str | ScalarType::CowStr | ScalarType::String => {
391 "encodeString"
392 }
393 ScalarType::Unit => "{ _, _ in }",
394 _ => "encodeByteSeq",
395 }
396}