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
61pub fn render_enum_decl(out: &mut String, e: &EnumBinding) {
63 emit_doc(out, &e.doc, "");
64 if e.variants.iter().any(|v| v.doc.is_some()) {
65 out.push_str("typedef enum {\n");
66 for (i, v) in e.variants.iter().enumerate() {
67 emit_doc(out, &v.doc, " ");
68 let comma = if i + 1 == e.variants.len() { "" } else { "," };
69 let _ = writeln!(out, " {} = {}{comma}", v.c_const, v.value);
70 }
71 let _ = writeln!(out, "}} {};", e.c_tag);
72 } else {
73 let variants: Vec<String> = e
74 .variants
75 .iter()
76 .map(|v| format!("{} = {}", v.c_const, v.value))
77 .collect();
78 let _ = writeln!(
79 out,
80 "typedef enum {{ {} }} {};",
81 variants.join(", "),
82 e.c_tag
83 );
84 }
85}
86
87fn render_struct_tags(out: &mut String, s: &StructBinding) {
93 let tag = &s.c_tag;
94 let _ = writeln!(out, "typedef struct {tag} {tag};");
95 if let Some(b) = &s.builder {
96 let bt = &b.builder_tag;
97 let _ = writeln!(out, "typedef struct {bt} {bt};");
98 }
99}
100
101fn render_struct_fn_decls(out: &mut String, s: &StructBinding, prefix: &str) {
106 let tag = &s.c_tag;
107 emit_doc(out, &s.doc, "");
108 fn_decl(out, &s.create, prefix);
109 let _ = writeln!(out, "void {}({tag}* ptr);", s.destroy_symbol);
110 for field in &s.fields {
111 emit_doc(out, &field.doc, "");
112 let mut parts = vec![format!("const {tag}* ptr")];
113 parts.extend(
114 field
115 .getter_out_params
116 .iter()
117 .map(|p| format!("{} {}", p.ty.render_c(prefix), p.name)),
118 );
119 let _ = writeln!(
120 out,
121 "{} {}({});",
122 field.getter_ret.render_c(prefix),
123 field.getter_symbol,
124 parts.join(", ")
125 );
126 }
127 out.push('\n');
128
129 if let Some(b) = &s.builder {
130 let bt = &b.builder_tag;
131 let _ = writeln!(out, "{bt}* {}(void);", b.new_symbol);
132 for (field, (_, setter)) in s.fields.iter().zip(&b.setters) {
133 emit_doc(out, &field.doc, "");
134 let _ = writeln!(
135 out,
136 "void {setter}({bt}* builder, {});",
137 params_str(&field.value_params, prefix)
138 );
139 }
140 let _ = writeln!(
141 out,
142 "{tag}* {}({bt}* builder, {prefix}_error* out_err);",
143 b.build_symbol
144 );
145 let _ = writeln!(out, "void {}({bt}* builder);", b.destroy_symbol);
146 out.push('\n');
147 }
148}
149
150pub fn render_module_enum_defs(out: &mut String, module: &ModuleBinding) {
153 for e in &module.enums {
154 render_enum_decl(out, e);
155 }
156}
157
158pub fn render_module_type_tags(out: &mut String, module: &ModuleBinding) {
162 for s in &module.structs {
163 render_struct_tags(out, s);
164 }
165 for f in &module.functions {
166 if let CallShape::Iterator(it) = &f.shape {
167 let t = &it.iter_tag;
168 let _ = writeln!(out, "typedef struct {t} {t};");
169 }
170 }
171}
172
173pub fn render_module_callback_types(out: &mut String, module: &ModuleBinding, prefix: &str) {
177 for cb in &module.callbacks {
178 emit_doc(out, &cb.doc, "");
179 let _ = writeln!(
180 out,
181 "typedef void (*{})({});",
182 cb.c_fn_type,
183 params_str(&cb.abi_params, prefix)
184 );
185 }
186 for f in &module.functions {
187 if let CallShape::Async(a) = &f.shape {
188 let _ = writeln!(
189 out,
190 "typedef void (*{})({});",
191 a.callback_type,
192 params_str(&a.callback_params, prefix)
193 );
194 }
195 }
196}
197
198pub fn render_module_fn_decls(out: &mut String, module: &ModuleBinding, prefix: &str) {
203 for s in &module.structs {
204 render_struct_fn_decls(out, s, prefix);
205 }
206 for l in &module.listeners {
207 emit_doc(out, &l.doc, "");
208 let _ = writeln!(
209 out,
210 "uint64_t {}({} callback, void* context);",
211 l.register_symbol, l.callback_c_fn_type
212 );
213 emit_doc(out, &l.doc, "");
214 let _ = writeln!(out, "void {}(uint64_t id);", l.unregister_symbol);
215 }
216 for f in &module.functions {
217 emit_doc(out, &f.doc, "");
218 if let Some(msg) = &f.deprecated {
219 let _ = writeln!(
220 out,
221 "__attribute__((deprecated(\"{}\")))",
222 msg.replace('"', "\\\"")
223 );
224 }
225 match &f.shape {
226 CallShape::Iterator(it) => {
227 let t = &it.iter_tag;
228 fn_decl(out, &it.launch, prefix);
229 fn_decl(out, &it.next, prefix);
230 let _ = writeln!(out, "void {}({t}* iter);", it.destroy_symbol);
231 }
232 CallShape::Async(a) => {
233 fn_decl(out, &a.launch, prefix);
234 }
235 CallShape::Sync(abi) => {
236 fn_decl(out, abi, prefix);
237 }
238 }
239 }
240}
241
242pub fn render_decls(
253 out: &mut String,
254 modules: &[ModuleBinding],
255 prefix: &str,
256 module_comments: bool,
257) {
258 for m in modules {
259 render_module_enum_defs(out, m);
260 }
261 for m in modules {
262 render_module_type_tags(out, m);
263 }
264 for m in modules {
265 render_module_callback_types(out, m, prefix);
266 }
267 out.push('\n');
268 for m in modules {
269 if module_comments {
270 let _ = writeln!(out, "// Module: {}", m.path);
271 }
272 render_module_fn_decls(out, m, prefix);
273 out.push('\n');
274 }
275}