1use std::fmt::Write;
13
14use crate::abi::AbiParam;
15use crate::codegen::common::{emit_doc as common_emit_doc, DocCommentStyle};
16use crate::model::{AbiFn, CallShape, EnumBinding, ModuleBinding, StructBinding};
17
18pub fn emit_doc(out: &mut String, doc: &Option<String>, indent: &str) {
20 common_emit_doc(out, doc, indent, DocCommentStyle::Javadoc);
21}
22
23pub fn params_str(params: &[AbiParam], prefix: &str) -> String {
25 params
26 .iter()
27 .map(|p| format!("{} {}", p.ty.render_c(prefix), p.name))
28 .collect::<Vec<_>>()
29 .join(", ")
30}
31
32pub fn fn_decl(out: &mut String, f: &AbiFn, prefix: &str) {
34 let _ = writeln!(
35 out,
36 "{} {}({});",
37 f.ret.render_c(prefix),
38 f.symbol,
39 params_str(&f.params, prefix)
40 );
41}
42
43pub fn render_runtime_decls(out: &mut String, prefix: &str) {
46 let _ = write!(
47 out,
48 "typedef uint64_t {prefix}_handle_t;\n\n\
49 typedef struct {prefix}_error {{ int32_t code; const char* message; }} {prefix}_error;\n\n\
50 void {prefix}_error_clear({prefix}_error* err);\n\
51 void {prefix}_free_string(const char* ptr);\n\
52 void {prefix}_free_bytes(uint8_t* ptr, size_t len);\n\n\
53 typedef struct {prefix}_cancel_token {prefix}_cancel_token;\n\
54 {prefix}_cancel_token* {prefix}_cancel_token_create(void);\n\
55 void {prefix}_cancel_token_cancel({prefix}_cancel_token* token);\n\
56 bool {prefix}_cancel_token_is_cancelled(const {prefix}_cancel_token* token);\n\
57 void {prefix}_cancel_token_destroy({prefix}_cancel_token* token);\n\n",
58 );
59}
60
61fn render_enum_constants(out: &mut String, e: &EnumBinding, type_name: &str) {
64 emit_doc(out, &e.doc, "");
65 if e.variants.iter().any(|v| v.doc.is_some()) {
66 out.push_str("typedef enum {\n");
67 for (i, v) in e.variants.iter().enumerate() {
68 emit_doc(out, &v.doc, " ");
69 let comma = if i + 1 == e.variants.len() { "" } else { "," };
70 let _ = writeln!(out, " {} = {}{comma}", v.c_const, v.value);
71 }
72 let _ = writeln!(out, "}} {type_name};");
73 } else {
74 let variants: Vec<String> = e
75 .variants
76 .iter()
77 .map(|v| format!("{} = {}", v.c_const, v.value))
78 .collect();
79 let _ = writeln!(
80 out,
81 "typedef enum {{ {} }} {type_name};",
82 variants.join(", ")
83 );
84 }
85}
86
87pub fn render_enum_decl(out: &mut String, e: &EnumBinding) {
89 render_enum_constants(out, e, &e.c_tag);
90}
91
92fn render_rich_enum_tag_decl(out: &mut String, e: &EnumBinding) {
97 let tag_enum = format!("{}_Tag", e.c_tag);
98 render_enum_constants(out, e, &tag_enum);
99}
100
101fn render_rich_enum_fn_decls(out: &mut String, e: &EnumBinding, prefix: &str) {
105 let Some(rich) = &e.rich else {
106 return;
107 };
108 let tag = &e.c_tag;
109 emit_doc(out, &e.doc, "");
110 let _ = writeln!(out, "int32_t {}(const {tag}* self);", rich.tag_symbol);
111 for v in &rich.variants {
112 emit_doc(out, &v.doc, "");
113 fn_decl(out, &v.create, prefix);
114 for field in &v.fields {
115 emit_doc(out, &field.doc, "");
116 let mut parts = vec![format!("const {tag}* self")];
117 parts.extend(
118 field
119 .getter_out_params
120 .iter()
121 .map(|p| format!("{} {}", p.ty.render_c(prefix), p.name)),
122 );
123 let _ = writeln!(
124 out,
125 "{} {}({});",
126 field.getter_ret.render_c(prefix),
127 field.getter_symbol,
128 parts.join(", ")
129 );
130 }
131 }
132 let _ = writeln!(out, "void {}({tag}* self);", rich.destroy_symbol);
133 out.push('\n');
134}
135
136fn render_struct_tags(out: &mut String, s: &StructBinding) {
142 let tag = &s.c_tag;
143 let _ = writeln!(out, "typedef struct {tag} {tag};");
144 if let Some(b) = &s.builder {
145 let bt = &b.builder_tag;
146 let _ = writeln!(out, "typedef struct {bt} {bt};");
147 }
148}
149
150fn render_struct_fn_decls(out: &mut String, s: &StructBinding, prefix: &str) {
155 let tag = &s.c_tag;
156 emit_doc(out, &s.doc, "");
157 fn_decl(out, &s.create, prefix);
158 let _ = writeln!(out, "void {}({tag}* ptr);", s.destroy_symbol);
159 for field in &s.fields {
160 emit_doc(out, &field.doc, "");
161 let mut parts = vec![format!("const {tag}* ptr")];
162 parts.extend(
163 field
164 .getter_out_params
165 .iter()
166 .map(|p| format!("{} {}", p.ty.render_c(prefix), p.name)),
167 );
168 let _ = writeln!(
169 out,
170 "{} {}({});",
171 field.getter_ret.render_c(prefix),
172 field.getter_symbol,
173 parts.join(", ")
174 );
175 }
176 out.push('\n');
177
178 if let Some(b) = &s.builder {
179 let bt = &b.builder_tag;
180 let _ = writeln!(out, "{bt}* {}(void);", b.new_symbol);
181 for (field, (_, setter)) in s.fields.iter().zip(&b.setters) {
182 emit_doc(out, &field.doc, "");
183 let _ = writeln!(
184 out,
185 "void {setter}({bt}* builder, {});",
186 params_str(&field.value_params, prefix)
187 );
188 }
189 let _ = writeln!(
190 out,
191 "{tag}* {}({bt}* builder, {prefix}_error* out_err);",
192 b.build_symbol
193 );
194 let _ = writeln!(out, "void {}({bt}* builder);", b.destroy_symbol);
195 out.push('\n');
196 }
197}
198
199pub fn render_module_enum_defs(out: &mut String, module: &ModuleBinding) {
202 for e in &module.enums {
203 if e.is_rich() {
204 render_rich_enum_tag_decl(out, e);
205 } else {
206 render_enum_decl(out, e);
207 }
208 }
209}
210
211pub fn render_module_type_tags(out: &mut String, module: &ModuleBinding) {
215 for e in &module.enums {
217 if e.is_rich() {
218 let t = &e.c_tag;
219 let _ = writeln!(out, "typedef struct {t} {t};");
220 }
221 }
222 for s in &module.structs {
223 render_struct_tags(out, s);
224 }
225 for f in &module.functions {
226 if let CallShape::Iterator(it) = &f.shape {
227 let t = &it.iter_tag;
228 let _ = writeln!(out, "typedef struct {t} {t};");
229 }
230 }
231}
232
233pub fn render_module_callback_types(out: &mut String, module: &ModuleBinding, prefix: &str) {
237 for cb in &module.callbacks {
238 emit_doc(out, &cb.doc, "");
239 let _ = writeln!(
240 out,
241 "typedef void (*{})({});",
242 cb.c_fn_type,
243 params_str(&cb.abi_params, prefix)
244 );
245 }
246 for f in &module.functions {
247 if let CallShape::Async(a) = &f.shape {
248 let _ = writeln!(
249 out,
250 "typedef void (*{})({});",
251 a.callback_type,
252 params_str(&a.callback_params, prefix)
253 );
254 }
255 }
256}
257
258pub fn render_module_fn_decls(out: &mut String, module: &ModuleBinding, prefix: &str) {
263 for e in &module.enums {
264 render_rich_enum_fn_decls(out, e, prefix);
265 }
266 for s in &module.structs {
267 render_struct_fn_decls(out, s, prefix);
268 }
269 for l in &module.listeners {
270 emit_doc(out, &l.doc, "");
271 let _ = writeln!(
272 out,
273 "uint64_t {}({} callback, void* context);",
274 l.register_symbol, l.callback_c_fn_type
275 );
276 emit_doc(out, &l.doc, "");
277 let _ = writeln!(out, "void {}(uint64_t id);", l.unregister_symbol);
278 }
279 for f in &module.functions {
280 emit_doc(out, &f.doc, "");
281 if let Some(msg) = &f.deprecated {
282 let _ = writeln!(
283 out,
284 "__attribute__((deprecated(\"{}\")))",
285 msg.replace('"', "\\\"")
286 );
287 }
288 match &f.shape {
289 CallShape::Iterator(it) => {
290 let t = &it.iter_tag;
291 fn_decl(out, &it.launch, prefix);
292 fn_decl(out, &it.next, prefix);
293 let _ = writeln!(out, "void {}({t}* iter);", it.destroy_symbol);
294 }
295 CallShape::Async(a) => {
296 fn_decl(out, &a.launch, prefix);
297 }
298 CallShape::Sync(abi) => {
299 fn_decl(out, abi, prefix);
300 }
301 }
302 }
303}
304
305pub fn render_decls(
316 out: &mut String,
317 modules: &[ModuleBinding],
318 prefix: &str,
319 module_comments: bool,
320) {
321 for m in modules {
322 render_module_enum_defs(out, m);
323 }
324 for m in modules {
325 render_module_type_tags(out, m);
326 }
327 for m in modules {
328 render_module_callback_types(out, m, prefix);
329 }
330 out.push('\n');
331 for m in modules {
332 if module_comments {
333 let _ = writeln!(out, "// Module: {}", m.path);
334 }
335 render_module_fn_decls(out, m, prefix);
336 out.push('\n');
337 }
338}