vox_codegen/targets/swift/
encode.rs1use facet_core::{ScalarType, Shape};
6use heck::ToLowerCamelCase;
7use vox_types::{
8 EnumInfo, ShapeKind, StructInfo, VariantKind, classify_shape, classify_variant, is_bytes,
9};
10
11pub fn generate_encode_expr(shape: &'static Shape, value: &str) -> String {
13 if is_bytes(shape) {
14 return format!("encodeBytes(Array({value}))");
15 }
16
17 match classify_shape(shape) {
18 ShapeKind::Scalar(scalar) => {
19 let encode_fn = swift_encode_fn(scalar);
20 format!("{encode_fn}({value})")
21 }
22 ShapeKind::List { element }
23 | ShapeKind::Slice { element }
24 | ShapeKind::Array { element, .. } => {
25 let inner_encode = generate_encode_closure(element);
26 format!("encodeVec({value}, encoder: {inner_encode})")
27 }
28 ShapeKind::Option { inner } => {
29 let inner_encode = generate_encode_closure(inner);
30 format!("encodeOption({value}, encoder: {inner_encode})")
31 }
32 ShapeKind::Tx { .. } | ShapeKind::Rx { .. } => {
33 format!("encodeVarint({value}.channelId)")
34 }
35 ShapeKind::Tuple { elements } if elements.len() == 2 => {
36 let a_encode = generate_encode_closure(elements[0].shape);
37 let b_encode = generate_encode_closure(elements[1].shape);
38 format!("{a_encode}({value}.0) + {b_encode}({value}.1)")
39 }
40 ShapeKind::TupleStruct { fields } if fields.len() == 2 => {
41 let a_encode = generate_encode_closure(fields[0].shape());
42 let b_encode = generate_encode_closure(fields[1].shape());
43 format!("{a_encode}({value}.0) + {b_encode}({value}.1)")
44 }
45 ShapeKind::Struct(StructInfo { fields, .. }) => {
46 let field_encodes: Vec<String> = fields
48 .iter()
49 .map(|f| {
50 let field_name = f.name.to_lower_camel_case();
51 generate_encode_expr(f.shape(), &format!("{value}.{field_name}"))
52 })
53 .collect();
54 if field_encodes.is_empty() {
55 "[]".into()
56 } else {
57 field_encodes.join(" + ")
58 }
59 }
60 ShapeKind::Enum(EnumInfo { .. }) => {
61 let encode_closure = generate_encode_closure(shape);
62 format!("{encode_closure}({value})")
63 }
64 ShapeKind::Pointer { pointee } => generate_encode_expr(pointee, value),
65 ShapeKind::Result { ok, err } => {
66 let ok_encode = generate_encode_closure(ok);
68 let err_encode = generate_encode_closure(err);
69 format!(
70 "{{ switch {value} {{ case .success(let v): return encodeVarint(UInt64(0)) + {ok_encode}(v); case .failure(let e): return encodeVarint(UInt64(1)) + {err_encode}(e) }} }}()"
71 )
72 }
73 _ => "[]".into(), }
75}
76
77pub fn generate_encode_closure(shape: &'static Shape) -> String {
79 if is_bytes(shape) {
80 return "{ encodeBytes(Array($0)) }".into();
81 }
82
83 match classify_shape(shape) {
84 ShapeKind::Scalar(scalar) => {
85 let encode_fn = swift_encode_fn(scalar);
86 format!("{{ {encode_fn}($0) }}")
87 }
88 ShapeKind::List { element } | ShapeKind::Slice { element } => {
89 let inner = generate_encode_closure(element);
90 format!("{{ encodeVec($0, encoder: {inner}) }}")
91 }
92 ShapeKind::Option { inner } => {
93 let inner_closure = generate_encode_closure(inner);
94 format!("{{ encodeOption($0, encoder: {inner_closure}) }}")
95 }
96 ShapeKind::Tx { .. } | ShapeKind::Rx { .. } => "{ encodeVarint($0.channelId) }".into(),
97 ShapeKind::Tuple { elements } if elements.len() == 2 => {
98 let a_encode = generate_encode_closure(elements[0].shape);
99 let b_encode = generate_encode_closure(elements[1].shape);
100 format!("{{ {a_encode}($0.0) + {b_encode}($0.1) }}")
101 }
102 ShapeKind::TupleStruct { fields } if fields.len() == 2 => {
103 let a_encode = generate_encode_closure(fields[0].shape());
104 let b_encode = generate_encode_closure(fields[1].shape());
105 format!("{{ {a_encode}($0.0) + {b_encode}($0.1) }}")
106 }
107 ShapeKind::Struct(StructInfo { fields, .. }) => {
108 let field_encodes: Vec<String> = fields
110 .iter()
111 .map(|f| {
112 let field_name = f.name.to_lower_camel_case();
113 generate_encode_expr(f.shape(), &format!("$0.{field_name}"))
114 })
115 .collect();
116 if field_encodes.is_empty() {
117 "{ _ in [] }".into()
118 } else {
119 format!("{{ {} }}", field_encodes.join(" + "))
120 }
121 }
122 ShapeKind::Enum(EnumInfo {
123 name: Some(_name),
124 variants,
125 ..
126 }) => {
127 let mut code = "{ v in\n switch v {\n".to_string();
129 for (i, v) in variants.iter().enumerate() {
130 let variant_name = v.name.to_lower_camel_case();
131 match classify_variant(v) {
132 VariantKind::Unit => {
133 code.push_str(&format!(
134 " case .{variant_name}:\n return encodeVarint(UInt64({i}))\n"
135 ));
136 }
137 VariantKind::Newtype { inner } => {
138 let inner_encode = generate_encode_expr(inner, "val");
139 code.push_str(&format!(
140 " case .{variant_name}(let val):\n return encodeVarint(UInt64({i})) + {inner_encode}\n"
141 ));
142 }
143 VariantKind::Tuple { fields } => {
144 let bindings: Vec<String> =
145 (0..fields.len()).map(|j| format!("f{j}")).collect();
146 let field_encodes: Vec<String> = fields
147 .iter()
148 .enumerate()
149 .map(|(j, f)| generate_encode_expr(f.shape(), &format!("f{j}")))
150 .collect();
151 code.push_str(&format!(
152 " case .{variant_name}({}):\n return encodeVarint(UInt64({i})) + {}\n",
153 bindings
154 .iter()
155 .map(|b| format!("let {b}"))
156 .collect::<Vec<_>>()
157 .join(", "),
158 field_encodes.join(" + ")
159 ));
160 }
161 VariantKind::Struct { fields } => {
162 let bindings: Vec<String> = fields
163 .iter()
164 .map(|f| f.name.to_lower_camel_case())
165 .collect();
166 let field_encodes: Vec<String> = fields
167 .iter()
168 .map(|f| {
169 let field_name = f.name.to_lower_camel_case();
170 generate_encode_expr(f.shape(), &field_name)
171 })
172 .collect();
173 code.push_str(&format!(
174 " case .{variant_name}({}):\n return encodeVarint(UInt64({i})) + {}\n",
175 bindings
176 .iter()
177 .map(|b| format!("let {b}"))
178 .collect::<Vec<_>>()
179 .join(", "),
180 field_encodes.join(" + ")
181 ));
182 }
183 }
184 }
185 code.push_str(" }\n}");
186 code
187 }
188 ShapeKind::Pointer { pointee } => generate_encode_closure(pointee),
189 ShapeKind::Result { ok, err } => {
190 let ok_encode = generate_encode_closure(ok);
191 let err_encode = generate_encode_closure(err);
192 format!(
193 "{{ switch $0 {{ case .success(let v): return encodeVarint(UInt64(0)) + {ok_encode}(v); case .failure(let e): return encodeVarint(UInt64(1)) + {err_encode}(e) }} }}"
194 )
195 }
196 _ => "{ _ in [] }".into(), }
198}
199
200pub fn swift_encode_fn(scalar: ScalarType) -> &'static str {
202 match scalar {
203 ScalarType::Bool => "encodeBool",
204 ScalarType::U8 => "encodeU8",
205 ScalarType::I8 => "encodeI8",
206 ScalarType::U16 => "encodeU16",
207 ScalarType::I16 => "encodeI16",
208 ScalarType::U32 => "encodeU32",
209 ScalarType::I32 => "encodeI32",
210 ScalarType::U64 | ScalarType::USize => "encodeVarint",
211 ScalarType::I64 | ScalarType::ISize => "encodeI64",
212 ScalarType::F32 => "encodeF32",
213 ScalarType::F64 => "encodeF64",
214 ScalarType::Char | ScalarType::Str | ScalarType::CowStr | ScalarType::String => {
215 "encodeString"
216 }
217 ScalarType::Unit => "{ _ in [] }",
218 _ => "encodeBytes", }
220}