blob: 4df404cfc77ac99f48e0afd16598e65cf2ea82bd [file] [log] [blame]
David Tolnay7db73692019-10-20 14:51:12 -04001use crate::gen::out::OutFile;
David Tolnay33d30292020-03-18 18:02:02 -07002use crate::gen::{include, Opt};
David Tolnay7db73692019-10-20 14:51:12 -04003use crate::syntax::atom::Atom::{self, *};
David Tolnay08419302020-04-19 20:38:20 -07004use crate::syntax::namespace::Namespace;
David Tolnay3caa50a2020-04-19 21:25:34 -07005use crate::syntax::{
6 mangle, Api, ExternFn, ExternType, Receiver, Signature, Struct, Type, Types, Var,
7};
David Tolnay7db73692019-10-20 14:51:12 -04008use proc_macro2::Ident;
David Tolnayf94bef12020-04-17 14:46:42 -07009use std::collections::HashMap;
David Tolnay7db73692019-10-20 14:51:12 -040010
David Tolnay33d30292020-03-18 18:02:02 -070011pub(super) fn gen(
David Tolnay754e21c2020-03-29 20:58:46 -070012 namespace: Namespace,
David Tolnay33d30292020-03-18 18:02:02 -070013 apis: &[Api],
14 types: &Types,
15 opt: Opt,
16 header: bool,
17) -> OutFile {
David Tolnay7db73692019-10-20 14:51:12 -040018 let mut out_file = OutFile::new(namespace.clone(), header);
19 let out = &mut out_file;
20
21 if header {
22 writeln!(out, "#pragma once");
23 }
24
David Tolnay33d30292020-03-18 18:02:02 -070025 out.include.extend(opt.include);
David Tolnay7db73692019-10-20 14:51:12 -040026 for api in apis {
27 if let Api::Include(include) = api {
David Tolnay9c68b1a2020-03-06 11:12:55 -080028 out.include.insert(include.value());
David Tolnay7db73692019-10-20 14:51:12 -040029 }
30 }
31
32 write_includes(out, types);
David Tolnayf51447e2020-03-06 14:14:27 -080033 write_include_cxxbridge(out, apis, types);
David Tolnay7db73692019-10-20 14:51:12 -040034
David Tolnay7db73692019-10-20 14:51:12 -040035 out.next_section();
36 for name in &namespace {
37 writeln!(out, "namespace {} {{", name);
38 }
39
David Tolnay7db73692019-10-20 14:51:12 -040040 out.next_section();
41 for api in apis {
42 match api {
43 Api::Struct(strct) => write_struct_decl(out, &strct.ident),
David Tolnay8861bee2020-01-20 18:39:24 -080044 Api::CxxType(ety) => write_struct_using(out, &ety.ident),
45 Api::RustType(ety) => write_struct_decl(out, &ety.ident),
David Tolnay7db73692019-10-20 14:51:12 -040046 _ => {}
47 }
48 }
49
David Tolnayf94bef12020-04-17 14:46:42 -070050 let mut methods_for_type = HashMap::new();
51 for api in apis {
52 if let Api::RustFunction(efn) = api {
53 if let Some(receiver) = &efn.sig.receiver {
54 methods_for_type
55 .entry(&receiver.ident)
56 .or_insert_with(Vec::new)
57 .push(efn);
58 }
59 }
60 }
Joel Galenson968738f2020-04-15 14:19:33 -070061
David Tolnay7db73692019-10-20 14:51:12 -040062 for api in apis {
Joel Galensonc1c4e7a2020-04-15 10:21:00 -070063 match api {
64 Api::Struct(strct) => {
65 out.next_section();
66 write_struct(out, strct);
67 }
David Tolnayc1fe0052020-04-17 15:15:06 -070068 Api::RustType(ety) => {
69 if let Some(methods) = methods_for_type.get(&ety.ident) {
David Tolnay46a54e72020-04-17 14:48:21 -070070 out.next_section();
71 write_struct_with_methods(out, ety, methods);
Joel Galensonc1c4e7a2020-04-15 10:21:00 -070072 }
David Tolnayc1fe0052020-04-17 15:15:06 -070073 }
Joel Galensonc1c4e7a2020-04-15 10:21:00 -070074 _ => {}
David Tolnay7db73692019-10-20 14:51:12 -040075 }
76 }
77
78 if !header {
79 out.begin_block("extern \"C\"");
David Tolnayebef4a22020-03-17 15:33:47 -070080 write_exception_glue(out, apis);
David Tolnay7db73692019-10-20 14:51:12 -040081 for api in apis {
82 let (efn, write): (_, fn(_, _, _)) = match api {
83 Api::CxxFunction(efn) => (efn, write_cxx_function_shim),
84 Api::RustFunction(efn) => (efn, write_rust_function_decl),
85 _ => continue,
86 };
87 out.next_section();
88 write(out, efn, types);
89 }
David Tolnay9ad1fbc2020-03-01 14:01:24 -080090 out.end_block("extern \"C\"");
David Tolnay7db73692019-10-20 14:51:12 -040091 }
92
93 for api in apis {
94 if let Api::RustFunction(efn) = api {
95 out.next_section();
96 write_rust_function_shim(out, efn, types);
97 }
98 }
99
100 out.next_section();
101 for name in namespace.iter().rev() {
102 writeln!(out, "}} // namespace {}", name);
103 }
104
105 if !header {
106 out.next_section();
107 write_generic_instantiations(out, types);
108 }
109
David Tolnay9c68b1a2020-03-06 11:12:55 -0800110 out.prepend(out.include.to_string());
111
David Tolnay7db73692019-10-20 14:51:12 -0400112 out_file
113}
114
115fn write_includes(out: &mut OutFile, types: &Types) {
David Tolnay7db73692019-10-20 14:51:12 -0400116 for ty in types {
117 match ty {
118 Type::Ident(ident) => match Atom::from(ident) {
David Tolnay30430f12020-03-19 20:49:00 -0700119 Some(U8) | Some(U16) | Some(U32) | Some(U64) | Some(I8) | Some(I16) | Some(I32)
120 | Some(I64) => out.include.cstdint = true,
121 Some(Usize) => out.include.cstddef = true,
David Tolnay9c68b1a2020-03-06 11:12:55 -0800122 Some(CxxString) => out.include.string = true,
David Tolnay30430f12020-03-19 20:49:00 -0700123 Some(Bool) | Some(Isize) | Some(F32) | Some(F64) | Some(RustString) | None => {}
David Tolnay7db73692019-10-20 14:51:12 -0400124 },
David Tolnay9c68b1a2020-03-06 11:12:55 -0800125 Type::RustBox(_) => out.include.type_traits = true,
126 Type::UniquePtr(_) => out.include.memory = true,
David Tolnay4770b472020-04-14 16:32:59 -0700127 Type::SliceRefU8(_) => out.include.cstdint = true,
David Tolnay7db73692019-10-20 14:51:12 -0400128 _ => {}
129 }
130 }
David Tolnay7db73692019-10-20 14:51:12 -0400131}
132
David Tolnayf51447e2020-03-06 14:14:27 -0800133fn write_include_cxxbridge(out: &mut OutFile, apis: &[Api], types: &Types) {
David Tolnayb7a7cb62020-03-17 21:18:40 -0700134 let mut needs_rust_string = false;
135 let mut needs_rust_str = false;
David Tolnay4770b472020-04-14 16:32:59 -0700136 let mut needs_rust_slice = false;
David Tolnay7db73692019-10-20 14:51:12 -0400137 let mut needs_rust_box = false;
David Tolnay75dca2e2020-03-25 20:17:52 -0700138 let mut needs_rust_fn = false;
David Tolnayb8a6fb22020-04-10 11:17:28 -0700139 let mut needs_rust_isize = false;
David Tolnay7db73692019-10-20 14:51:12 -0400140 for ty in types {
David Tolnayb7a7cb62020-03-17 21:18:40 -0700141 match ty {
142 Type::RustBox(_) => {
143 out.include.type_traits = true;
144 needs_rust_box = true;
145 }
146 Type::Str(_) => {
147 out.include.cstdint = true;
148 out.include.string = true;
149 needs_rust_str = true;
150 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700151 Type::Fn(_) => {
152 needs_rust_fn = true;
153 }
David Tolnay4770b472020-04-14 16:32:59 -0700154 Type::Slice(_) | Type::SliceRefU8(_) => {
155 needs_rust_slice = true;
156 }
David Tolnayb8a6fb22020-04-10 11:17:28 -0700157 ty if ty == Isize => {
David Tolnay59b5ba12020-04-10 11:32:19 -0700158 out.include.base_tsd = true;
David Tolnayb8a6fb22020-04-10 11:17:28 -0700159 needs_rust_isize = true;
160 }
David Tolnayb7a7cb62020-03-17 21:18:40 -0700161 ty if ty == RustString => {
162 out.include.array = true;
163 out.include.cstdint = true;
164 out.include.string = true;
165 needs_rust_string = true;
166 }
167 _ => {}
David Tolnay7db73692019-10-20 14:51:12 -0400168 }
169 }
170
David Tolnayb7a7cb62020-03-17 21:18:40 -0700171 let mut needs_rust_error = false;
172 let mut needs_unsafe_bitcopy = false;
David Tolnayf51447e2020-03-06 14:14:27 -0800173 let mut needs_manually_drop = false;
David Tolnay09011c32020-03-06 14:40:28 -0800174 let mut needs_maybe_uninit = false;
David Tolnay5d121442020-03-17 22:14:40 -0700175 let mut needs_trycatch = false;
David Tolnay09011c32020-03-06 14:40:28 -0800176 for api in apis {
David Tolnayb7a7cb62020-03-17 21:18:40 -0700177 match api {
178 Api::CxxFunction(efn) if !out.header => {
David Tolnay5d121442020-03-17 22:14:40 -0700179 if efn.throws {
180 needs_trycatch = true;
181 }
David Tolnayb7a7cb62020-03-17 21:18:40 -0700182 for arg in &efn.args {
183 if arg.ty == RustString {
184 needs_unsafe_bitcopy = true;
185 break;
186 }
David Tolnay09011c32020-03-06 14:40:28 -0800187 }
188 }
David Tolnayb7a7cb62020-03-17 21:18:40 -0700189 Api::RustFunction(efn) if !out.header => {
190 if efn.throws {
191 out.include.exception = true;
192 needs_rust_error = true;
193 }
194 for arg in &efn.args {
195 if arg.ty != RustString && types.needs_indirect_abi(&arg.ty) {
196 needs_manually_drop = true;
197 break;
198 }
199 }
200 if let Some(ret) = &efn.ret {
201 if types.needs_indirect_abi(ret) {
202 needs_maybe_uninit = true;
203 }
David Tolnayf51447e2020-03-06 14:14:27 -0800204 }
205 }
David Tolnayb7a7cb62020-03-17 21:18:40 -0700206 _ => {}
David Tolnayf51447e2020-03-06 14:14:27 -0800207 }
208 }
209
David Tolnay750755e2020-03-01 13:04:08 -0800210 out.begin_block("namespace rust");
David Tolnay8c730492020-03-13 01:29:06 -0700211 out.begin_block("inline namespace cxxbridge02");
David Tolnayf51447e2020-03-06 14:14:27 -0800212
David Tolnayb7a7cb62020-03-17 21:18:40 -0700213 if needs_rust_string
214 || needs_rust_str
David Tolnay4770b472020-04-14 16:32:59 -0700215 || needs_rust_slice
David Tolnayb7a7cb62020-03-17 21:18:40 -0700216 || needs_rust_box
David Tolnay75dca2e2020-03-25 20:17:52 -0700217 || needs_rust_fn
David Tolnayb7a7cb62020-03-17 21:18:40 -0700218 || needs_rust_error
David Tolnayb8a6fb22020-04-10 11:17:28 -0700219 || needs_rust_isize
David Tolnayb7a7cb62020-03-17 21:18:40 -0700220 || needs_unsafe_bitcopy
221 || needs_manually_drop
222 || needs_maybe_uninit
David Tolnay5d121442020-03-17 22:14:40 -0700223 || needs_trycatch
David Tolnayb7a7cb62020-03-17 21:18:40 -0700224 {
David Tolnay736cbca2020-03-11 16:49:18 -0700225 writeln!(out, "// #include \"rust/cxx.h\"");
David Tolnayf51447e2020-03-06 14:14:27 -0800226 }
227
David Tolnayd1402742020-03-25 22:21:42 -0700228 if needs_rust_string {
229 out.next_section();
230 writeln!(out, "struct unsafe_bitcopy_t;");
231 }
232
David Tolnayb7a7cb62020-03-17 21:18:40 -0700233 write_header_section(out, needs_rust_string, "CXXBRIDGE02_RUST_STRING");
234 write_header_section(out, needs_rust_str, "CXXBRIDGE02_RUST_STR");
David Tolnay4770b472020-04-14 16:32:59 -0700235 write_header_section(out, needs_rust_slice, "CXXBRIDGE02_RUST_SLICE");
David Tolnayb7a7cb62020-03-17 21:18:40 -0700236 write_header_section(out, needs_rust_box, "CXXBRIDGE02_RUST_BOX");
David Tolnay75dca2e2020-03-25 20:17:52 -0700237 write_header_section(out, needs_rust_fn, "CXXBRIDGE02_RUST_FN");
David Tolnayb7a7cb62020-03-17 21:18:40 -0700238 write_header_section(out, needs_rust_error, "CXXBRIDGE02_RUST_ERROR");
David Tolnayb8a6fb22020-04-10 11:17:28 -0700239 write_header_section(out, needs_rust_isize, "CXXBRIDGE02_RUST_ISIZE");
David Tolnayb7a7cb62020-03-17 21:18:40 -0700240 write_header_section(out, needs_unsafe_bitcopy, "CXXBRIDGE02_RUST_BITCOPY");
David Tolnayf51447e2020-03-06 14:14:27 -0800241
242 if needs_manually_drop {
243 out.next_section();
David Tolnay4791f1c2020-03-17 21:53:16 -0700244 out.include.utility = true;
David Tolnayf51447e2020-03-06 14:14:27 -0800245 writeln!(out, "template <typename T>");
246 writeln!(out, "union ManuallyDrop {{");
247 writeln!(out, " T value;");
248 writeln!(
249 out,
250 " ManuallyDrop(T &&value) : value(::std::move(value)) {{}}",
251 );
252 writeln!(out, " ~ManuallyDrop() {{}}");
253 writeln!(out, "}};");
254 }
255
David Tolnay09011c32020-03-06 14:40:28 -0800256 if needs_maybe_uninit {
257 out.next_section();
258 writeln!(out, "template <typename T>");
259 writeln!(out, "union MaybeUninit {{");
260 writeln!(out, " T value;");
261 writeln!(out, " MaybeUninit() {{}}");
262 writeln!(out, " ~MaybeUninit() {{}}");
263 writeln!(out, "}};");
264 }
265
David Tolnay3e3e0af2020-03-17 22:42:49 -0700266 out.end_block("namespace cxxbridge02");
267
David Tolnay5d121442020-03-17 22:14:40 -0700268 if needs_trycatch {
David Tolnay3e3e0af2020-03-17 22:42:49 -0700269 out.begin_block("namespace behavior");
David Tolnay5d121442020-03-17 22:14:40 -0700270 out.include.exception = true;
David Tolnay04722332020-03-18 11:31:54 -0700271 out.include.type_traits = true;
272 out.include.utility = true;
273 writeln!(out, "class missing {{}};");
274 writeln!(out, "missing trycatch(...);");
David Tolnay3e3e0af2020-03-17 22:42:49 -0700275 writeln!(out);
David Tolnay04722332020-03-18 11:31:54 -0700276 writeln!(out, "template <typename Try, typename Fail>");
277 writeln!(out, "static typename std::enable_if<");
David Tolnay3e3e0af2020-03-17 22:42:49 -0700278 writeln!(
279 out,
David Tolnay04722332020-03-18 11:31:54 -0700280 " std::is_same<decltype(trycatch(std::declval<Try>(), std::declval<Fail>())),",
David Tolnay3e3e0af2020-03-17 22:42:49 -0700281 );
David Tolnay04722332020-03-18 11:31:54 -0700282 writeln!(out, " missing>::value>::type");
283 writeln!(out, "trycatch(Try &&func, Fail &&fail) noexcept try {{");
David Tolnay5d121442020-03-17 22:14:40 -0700284 writeln!(out, " func();");
285 writeln!(out, "}} catch (const ::std::exception &e) {{");
286 writeln!(out, " fail(e.what());");
287 writeln!(out, "}}");
David Tolnay3e3e0af2020-03-17 22:42:49 -0700288 out.end_block("namespace behavior");
David Tolnay5d121442020-03-17 22:14:40 -0700289 }
290
David Tolnay9ad1fbc2020-03-01 14:01:24 -0800291 out.end_block("namespace rust");
David Tolnay7db73692019-10-20 14:51:12 -0400292}
293
David Tolnayb7a7cb62020-03-17 21:18:40 -0700294fn write_header_section(out: &mut OutFile, needed: bool, section: &str) {
David Tolnay8e086612020-04-10 12:20:46 -0700295 let section = include::get(section);
David Tolnayb7a7cb62020-03-17 21:18:40 -0700296 if needed {
297 out.next_section();
David Tolnay8e086612020-04-10 12:20:46 -0700298 for line in section.lines() {
David Tolnayb7a7cb62020-03-17 21:18:40 -0700299 if !line.trim_start().starts_with("//") {
300 writeln!(out, "{}", line);
301 }
302 }
303 }
304}
305
David Tolnay7db73692019-10-20 14:51:12 -0400306fn write_struct(out: &mut OutFile, strct: &Struct) {
307 for line in strct.doc.to_string().lines() {
308 writeln!(out, "//{}", line);
309 }
310 writeln!(out, "struct {} final {{", strct.ident);
311 for field in &strct.fields {
312 write!(out, " ");
313 write_type_space(out, &field.ty);
314 writeln!(out, "{};", field.ident);
315 }
316 writeln!(out, "}};");
317}
318
319fn write_struct_decl(out: &mut OutFile, ident: &Ident) {
320 writeln!(out, "struct {};", ident);
321}
322
David Tolnay8861bee2020-01-20 18:39:24 -0800323fn write_struct_using(out: &mut OutFile, ident: &Ident) {
324 writeln!(out, "using {} = {};", ident, ident);
325}
326
David Tolnayc1fe0052020-04-17 15:15:06 -0700327fn write_struct_with_methods(out: &mut OutFile, ety: &ExternType, methods: &[&ExternFn]) {
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700328 for line in ety.doc.to_string().lines() {
329 writeln!(out, "//{}", line);
330 }
331 writeln!(out, "struct {} final {{", ety.ident);
Joel Galenson187588e2020-04-17 16:19:54 -0700332 writeln!(out, " {}() = delete;", ety.ident);
David Tolnay44395e32020-04-19 14:52:49 -0700333 writeln!(out, " {}(const {} &) = delete;", ety.ident, ety.ident);
Joel Galenson968738f2020-04-15 14:19:33 -0700334 for method in methods {
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700335 write!(out, " ");
336 let sig = &method.sig;
337 let local_name = method.ident.to_string();
338 write_rust_function_shim_decl(out, &local_name, sig, None, false);
339 writeln!(out, ";");
340 }
341 writeln!(out, "}};");
342}
343
David Tolnayebef4a22020-03-17 15:33:47 -0700344fn write_exception_glue(out: &mut OutFile, apis: &[Api]) {
345 let mut has_cxx_throws = false;
346 for api in apis {
347 if let Api::CxxFunction(efn) = api {
348 if efn.throws {
349 has_cxx_throws = true;
350 break;
351 }
352 }
353 }
354
355 if has_cxx_throws {
356 out.next_section();
David Tolnaye68634c2020-03-18 12:03:40 -0700357 writeln!(
David Tolnayebef4a22020-03-17 15:33:47 -0700358 out,
359 "const char *cxxbridge02$exception(const char *, size_t);",
360 );
361 }
362}
363
David Tolnay7db73692019-10-20 14:51:12 -0400364fn write_cxx_function_shim(out: &mut OutFile, efn: &ExternFn, types: &Types) {
David Tolnayebef4a22020-03-17 15:33:47 -0700365 if efn.throws {
366 write!(out, "::rust::Str::Repr ");
367 } else {
David Tolnay99642622020-03-25 13:07:35 -0700368 write_extern_return_type_space(out, &efn.ret, types);
David Tolnayebef4a22020-03-17 15:33:47 -0700369 }
David Tolnay3caa50a2020-04-19 21:25:34 -0700370 let mangled = mangle::extern_fn(&out.namespace, efn);
371 write!(out, "{}(", mangled);
Joel Galenson3d4f6122020-04-07 15:54:05 -0700372 if let Some(base) = &efn.receiver {
David Tolnay26804bd2020-04-19 20:06:51 -0700373 write!(out, "{} *self$", base.ident);
Joel Galenson3d4f6122020-04-07 15:54:05 -0700374 }
David Tolnay7db73692019-10-20 14:51:12 -0400375 for (i, arg) in efn.args.iter().enumerate() {
Joel Galenson3d4f6122020-04-07 15:54:05 -0700376 if i > 0 || efn.receiver.is_some() {
David Tolnay7db73692019-10-20 14:51:12 -0400377 write!(out, ", ");
378 }
David Tolnaya46a2372020-03-06 10:03:48 -0800379 if arg.ty == RustString {
380 write!(out, "const ");
381 }
David Tolnay7db73692019-10-20 14:51:12 -0400382 write_extern_arg(out, arg, types);
383 }
David Tolnay277e3cc2020-03-17 00:11:01 -0700384 let indirect_return = indirect_return(efn, types);
David Tolnay7db73692019-10-20 14:51:12 -0400385 if indirect_return {
386 if !efn.args.is_empty() {
387 write!(out, ", ");
388 }
David Tolnay99642622020-03-25 13:07:35 -0700389 write_indirect_return_type_space(out, efn.ret.as_ref().unwrap());
David Tolnay7db73692019-10-20 14:51:12 -0400390 write!(out, "*return$");
391 }
392 writeln!(out, ") noexcept {{");
393 write!(out, " ");
394 write_return_type(out, &efn.ret);
Joel Galenson3d4f6122020-04-07 15:54:05 -0700395 match &efn.receiver {
396 None => write!(out, "(*{}$)(", efn.ident),
397 Some(base) => write!(out, "({}::*{}$)(", base.ident, efn.ident),
398 }
David Tolnay7db73692019-10-20 14:51:12 -0400399 for (i, arg) in efn.args.iter().enumerate() {
400 if i > 0 {
401 write!(out, ", ");
402 }
403 write_type(out, &arg.ty);
404 }
Joel Galenson3d4f6122020-04-07 15:54:05 -0700405 write!(out, ")");
David Tolnay4e7123f2020-04-19 21:11:37 -0700406 if let Some(receiver) = &efn.receiver {
407 if receiver.mutability.is_none() {
408 write!(out, " const");
409 }
Joel Galenson3d4f6122020-04-07 15:54:05 -0700410 }
411 write!(out, " = ");
412 match &efn.receiver {
413 None => write!(out, "{}", efn.ident),
414 Some(base) => write!(out, "&{}::{}", base.ident, efn.ident),
415 }
416 writeln!(out, ";");
David Tolnay7db73692019-10-20 14:51:12 -0400417 write!(out, " ");
David Tolnayebef4a22020-03-17 15:33:47 -0700418 if efn.throws {
419 writeln!(out, "::rust::Str::Repr throw$;");
David Tolnay3e3e0af2020-03-17 22:42:49 -0700420 writeln!(out, " ::rust::behavior::trycatch(");
David Tolnay5d121442020-03-17 22:14:40 -0700421 writeln!(out, " [&] {{");
422 write!(out, " ");
David Tolnayebef4a22020-03-17 15:33:47 -0700423 }
David Tolnay7db73692019-10-20 14:51:12 -0400424 if indirect_return {
425 write!(out, "new (return$) ");
David Tolnay99642622020-03-25 13:07:35 -0700426 write_indirect_return_type(out, efn.ret.as_ref().unwrap());
David Tolnay7db73692019-10-20 14:51:12 -0400427 write!(out, "(");
David Tolnay99642622020-03-25 13:07:35 -0700428 } else if efn.ret.is_some() {
David Tolnay7db73692019-10-20 14:51:12 -0400429 write!(out, "return ");
David Tolnay99642622020-03-25 13:07:35 -0700430 }
431 match &efn.ret {
432 Some(Type::Ref(_)) => write!(out, "&"),
433 Some(Type::Str(_)) if !indirect_return => write!(out, "::rust::Str::Repr("),
David Tolnayeb952ba2020-04-14 15:02:24 -0700434 Some(Type::SliceRefU8(_)) if !indirect_return => {
435 write!(out, "::rust::Slice<uint8_t>::Repr(")
436 }
David Tolnay99642622020-03-25 13:07:35 -0700437 _ => {}
David Tolnay7db73692019-10-20 14:51:12 -0400438 }
Joel Galenson3d4f6122020-04-07 15:54:05 -0700439 match &efn.receiver {
440 None => write!(out, "{}$(", efn.ident),
David Tolnay26804bd2020-04-19 20:06:51 -0700441 Some(_) => write!(out, "(self$->*{}$)(", efn.ident),
Joel Galenson3d4f6122020-04-07 15:54:05 -0700442 }
David Tolnay7db73692019-10-20 14:51:12 -0400443 for (i, arg) in efn.args.iter().enumerate() {
444 if i > 0 {
445 write!(out, ", ");
446 }
447 if let Type::RustBox(_) = &arg.ty {
448 write_type(out, &arg.ty);
449 write!(out, "::from_raw({})", arg.ident);
450 } else if let Type::UniquePtr(_) = &arg.ty {
451 write_type(out, &arg.ty);
452 write!(out, "({})", arg.ident);
David Tolnaya46a2372020-03-06 10:03:48 -0800453 } else if arg.ty == RustString {
David Tolnaycc3767f2020-03-06 10:41:51 -0800454 write!(
455 out,
456 "::rust::String(::rust::unsafe_bitcopy, *{})",
457 arg.ident,
458 );
David Tolnay7db73692019-10-20 14:51:12 -0400459 } else if types.needs_indirect_abi(&arg.ty) {
David Tolnay4791f1c2020-03-17 21:53:16 -0700460 out.include.utility = true;
David Tolnay7e219b82020-03-01 13:14:51 -0800461 write!(out, "::std::move(*{})", arg.ident);
David Tolnay7db73692019-10-20 14:51:12 -0400462 } else {
463 write!(out, "{}", arg.ident);
464 }
465 }
466 write!(out, ")");
467 match &efn.ret {
468 Some(Type::RustBox(_)) => write!(out, ".into_raw()"),
469 Some(Type::UniquePtr(_)) => write!(out, ".release()"),
Adrian Taylorf5dd5522020-04-13 16:50:14 -0700470 Some(Type::Str(_)) | Some(Type::SliceRefU8(_)) if !indirect_return => write!(out, ")"),
David Tolnay7db73692019-10-20 14:51:12 -0400471 _ => {}
472 }
473 if indirect_return {
474 write!(out, ")");
475 }
476 writeln!(out, ";");
David Tolnayebef4a22020-03-17 15:33:47 -0700477 if efn.throws {
478 out.include.cstring = true;
David Tolnay5d121442020-03-17 22:14:40 -0700479 writeln!(out, " throw$.ptr = nullptr;");
480 writeln!(out, " }},");
David Tolnay82c16172020-03-17 22:54:12 -0700481 writeln!(out, " [&](const char *catch$) noexcept {{");
David Tolnay5d121442020-03-17 22:14:40 -0700482 writeln!(out, " throw$.len = ::std::strlen(catch$);");
David Tolnayebef4a22020-03-17 15:33:47 -0700483 writeln!(
484 out,
David Tolnay5d121442020-03-17 22:14:40 -0700485 " throw$.ptr = cxxbridge02$exception(catch$, throw$.len);",
David Tolnayebef4a22020-03-17 15:33:47 -0700486 );
David Tolnay5d121442020-03-17 22:14:40 -0700487 writeln!(out, " }});");
David Tolnayebef4a22020-03-17 15:33:47 -0700488 writeln!(out, " return throw$;");
489 }
David Tolnay7db73692019-10-20 14:51:12 -0400490 writeln!(out, "}}");
David Tolnay75dca2e2020-03-25 20:17:52 -0700491 for arg in &efn.args {
492 if let Type::Fn(f) = &arg.ty {
493 let var = &arg.ident;
494 write_function_pointer_trampoline(out, efn, var, f, types);
495 }
496 }
497}
498
499fn write_function_pointer_trampoline(
500 out: &mut OutFile,
501 efn: &ExternFn,
502 var: &Ident,
503 f: &Signature,
504 types: &Types,
505) {
506 out.next_section();
507 let r_trampoline = format!("{}cxxbridge02${}${}$1", out.namespace, efn.ident, var);
508 let indirect_call = true;
509 write_rust_function_decl_impl(out, &r_trampoline, f, types, indirect_call);
510
511 out.next_section();
512 let c_trampoline = format!("{}cxxbridge02${}${}$0", out.namespace, efn.ident, var);
513 write_rust_function_shim_impl(out, &c_trampoline, f, types, &r_trampoline, indirect_call);
David Tolnay7db73692019-10-20 14:51:12 -0400514}
515
516fn write_rust_function_decl(out: &mut OutFile, efn: &ExternFn, types: &Types) {
David Tolnay3caa50a2020-04-19 21:25:34 -0700517 let link_name = mangle::extern_fn(&out.namespace, efn);
David Tolnay75dca2e2020-03-25 20:17:52 -0700518 let indirect_call = false;
519 write_rust_function_decl_impl(out, &link_name, efn, types, indirect_call);
520}
521
522fn write_rust_function_decl_impl(
523 out: &mut OutFile,
524 link_name: &str,
525 sig: &Signature,
526 types: &Types,
527 indirect_call: bool,
528) {
529 if sig.throws {
David Tolnay1e548172020-03-16 13:37:09 -0700530 write!(out, "::rust::Str::Repr ");
531 } else {
David Tolnay75dca2e2020-03-25 20:17:52 -0700532 write_extern_return_type_space(out, &sig.ret, types);
David Tolnay1e548172020-03-16 13:37:09 -0700533 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700534 write!(out, "{}(", link_name);
535 let mut needs_comma = false;
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700536 if let Some(base) = &sig.receiver {
David Tolnay26804bd2020-04-19 20:06:51 -0700537 write!(out, "{} &self$", base.ident);
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700538 needs_comma = true;
539 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700540 for arg in &sig.args {
541 if needs_comma {
David Tolnay7db73692019-10-20 14:51:12 -0400542 write!(out, ", ");
543 }
544 write_extern_arg(out, arg, types);
David Tolnay75dca2e2020-03-25 20:17:52 -0700545 needs_comma = true;
David Tolnay7db73692019-10-20 14:51:12 -0400546 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700547 if indirect_return(sig, types) {
548 if needs_comma {
David Tolnay7db73692019-10-20 14:51:12 -0400549 write!(out, ", ");
550 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700551 write_return_type(out, &sig.ret);
David Tolnay7db73692019-10-20 14:51:12 -0400552 write!(out, "*return$");
David Tolnay75dca2e2020-03-25 20:17:52 -0700553 needs_comma = true;
554 }
555 if indirect_call {
556 if needs_comma {
557 write!(out, ", ");
558 }
559 write!(out, "void *");
David Tolnay7db73692019-10-20 14:51:12 -0400560 }
561 writeln!(out, ") noexcept;");
562}
563
564fn write_rust_function_shim(out: &mut OutFile, efn: &ExternFn, types: &Types) {
David Tolnay7db73692019-10-20 14:51:12 -0400565 for line in efn.doc.to_string().lines() {
566 writeln!(out, "//{}", line);
567 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700568 let local_name = efn.ident.to_string();
David Tolnay3caa50a2020-04-19 21:25:34 -0700569 let invoke = mangle::extern_fn(&out.namespace, efn);
David Tolnay75dca2e2020-03-25 20:17:52 -0700570 let indirect_call = false;
571 write_rust_function_shim_impl(out, &local_name, efn, types, &invoke, indirect_call);
572}
573
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700574fn write_rust_function_shim_decl(
David Tolnay75dca2e2020-03-25 20:17:52 -0700575 out: &mut OutFile,
576 local_name: &str,
577 sig: &Signature,
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700578 receiver: Option<&Receiver>,
David Tolnay75dca2e2020-03-25 20:17:52 -0700579 indirect_call: bool,
580) {
581 write_return_type(out, &sig.ret);
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700582 if let Some(base) = receiver {
583 write!(out, "{}::", base.ident);
584 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700585 write!(out, "{}(", local_name);
586 for (i, arg) in sig.args.iter().enumerate() {
David Tolnay7db73692019-10-20 14:51:12 -0400587 if i > 0 {
588 write!(out, ", ");
589 }
590 write_type_space(out, &arg.ty);
591 write!(out, "{}", arg.ident);
592 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700593 if indirect_call {
594 if !sig.args.is_empty() {
595 write!(out, ", ");
596 }
597 write!(out, "void *extern$");
598 }
David Tolnay1e548172020-03-16 13:37:09 -0700599 write!(out, ")");
David Tolnay75dca2e2020-03-25 20:17:52 -0700600 if !sig.throws {
David Tolnay1e548172020-03-16 13:37:09 -0700601 write!(out, " noexcept");
602 }
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700603}
604
605fn write_rust_function_shim_impl(
606 out: &mut OutFile,
607 local_name: &str,
608 sig: &Signature,
609 types: &Types,
610 invoke: &str,
611 indirect_call: bool,
612) {
613 if out.header && sig.receiver.is_some() {
614 // We've already defined this inside the struct.
615 return;
616 }
617 write_rust_function_shim_decl(out, local_name, sig, sig.receiver.as_ref(), indirect_call);
David Tolnay7db73692019-10-20 14:51:12 -0400618 if out.header {
619 writeln!(out, ";");
620 } else {
621 writeln!(out, " {{");
David Tolnay75dca2e2020-03-25 20:17:52 -0700622 for arg in &sig.args {
David Tolnayf51447e2020-03-06 14:14:27 -0800623 if arg.ty != RustString && types.needs_indirect_abi(&arg.ty) {
David Tolnay4791f1c2020-03-17 21:53:16 -0700624 out.include.utility = true;
David Tolnayf51447e2020-03-06 14:14:27 -0800625 write!(out, " ::rust::ManuallyDrop<");
626 write_type(out, &arg.ty);
627 writeln!(out, "> {}$(::std::move({0}));", arg.ident);
628 }
629 }
David Tolnay7db73692019-10-20 14:51:12 -0400630 write!(out, " ");
David Tolnay75dca2e2020-03-25 20:17:52 -0700631 let indirect_return = indirect_return(sig, types);
David Tolnay7db73692019-10-20 14:51:12 -0400632 if indirect_return {
David Tolnay09011c32020-03-06 14:40:28 -0800633 write!(out, "::rust::MaybeUninit<");
David Tolnay75dca2e2020-03-25 20:17:52 -0700634 write_type(out, sig.ret.as_ref().unwrap());
David Tolnay09011c32020-03-06 14:40:28 -0800635 writeln!(out, "> return$;");
David Tolnay7db73692019-10-20 14:51:12 -0400636 write!(out, " ");
David Tolnay75dca2e2020-03-25 20:17:52 -0700637 } else if let Some(ret) = &sig.ret {
David Tolnay7db73692019-10-20 14:51:12 -0400638 write!(out, "return ");
David Tolnay5cd8d612020-03-06 15:56:30 -0800639 match ret {
640 Type::RustBox(_) => {
641 write_type(out, ret);
642 write!(out, "::from_raw(");
643 }
David Tolnay4b3a66e2020-03-06 16:14:00 -0800644 Type::UniquePtr(_) => {
645 write_type(out, ret);
646 write!(out, "(");
647 }
David Tolnay5cd8d612020-03-06 15:56:30 -0800648 Type::Ref(_) => write!(out, "*"),
649 _ => {}
David Tolnay4a441222020-01-25 16:24:27 -0800650 }
David Tolnay7db73692019-10-20 14:51:12 -0400651 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700652 if sig.throws {
David Tolnay1e548172020-03-16 13:37:09 -0700653 write!(out, "::rust::Str::Repr error$ = ");
654 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700655 write!(out, "{}(", invoke);
David Tolnay9b5cfe12020-04-19 21:11:50 -0700656 if sig.receiver.is_some() {
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700657 write!(out, "*this");
658 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700659 for (i, arg) in sig.args.iter().enumerate() {
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700660 if i > 0 || sig.receiver.is_some() {
David Tolnay7db73692019-10-20 14:51:12 -0400661 write!(out, ", ");
662 }
David Tolnaybaae4432020-03-01 20:20:10 -0800663 match &arg.ty {
664 Type::Str(_) => write!(out, "::rust::Str::Repr("),
Adrian Taylorf5dd5522020-04-13 16:50:14 -0700665 Type::SliceRefU8(_) => write!(out, "::rust::Slice<uint8_t>::Repr("),
David Tolnaybaae4432020-03-01 20:20:10 -0800666 ty if types.needs_indirect_abi(ty) => write!(out, "&"),
667 _ => {}
David Tolnay7db73692019-10-20 14:51:12 -0400668 }
669 write!(out, "{}", arg.ident);
David Tolnayf51447e2020-03-06 14:14:27 -0800670 match &arg.ty {
David Tolnay17955e22020-01-20 17:58:24 -0800671 Type::RustBox(_) => write!(out, ".into_raw()"),
672 Type::UniquePtr(_) => write!(out, ".release()"),
Adrian Taylorf5dd5522020-04-13 16:50:14 -0700673 Type::Str(_) | Type::SliceRefU8(_) => write!(out, ")"),
David Tolnayf51447e2020-03-06 14:14:27 -0800674 ty if ty != RustString && types.needs_indirect_abi(ty) => write!(out, "$.value"),
David Tolnay17955e22020-01-20 17:58:24 -0800675 _ => {}
676 }
David Tolnay7db73692019-10-20 14:51:12 -0400677 }
678 if indirect_return {
David Tolnay75dca2e2020-03-25 20:17:52 -0700679 if !sig.args.is_empty() {
David Tolnay7db73692019-10-20 14:51:12 -0400680 write!(out, ", ");
681 }
David Tolnay09011c32020-03-06 14:40:28 -0800682 write!(out, "&return$.value");
David Tolnay7db73692019-10-20 14:51:12 -0400683 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700684 if indirect_call {
685 if !sig.args.is_empty() || indirect_return {
686 write!(out, ", ");
687 }
688 write!(out, "extern$");
689 }
David Tolnay5cd8d612020-03-06 15:56:30 -0800690 write!(out, ")");
David Tolnay75dca2e2020-03-25 20:17:52 -0700691 if let Some(ret) = &sig.ret {
David Tolnay4b3a66e2020-03-06 16:14:00 -0800692 if let Type::RustBox(_) | Type::UniquePtr(_) = ret {
David Tolnay5cd8d612020-03-06 15:56:30 -0800693 write!(out, ")");
694 }
695 }
696 writeln!(out, ";");
David Tolnay75dca2e2020-03-25 20:17:52 -0700697 if sig.throws {
David Tolnay1e548172020-03-16 13:37:09 -0700698 writeln!(out, " if (error$.ptr) {{");
699 writeln!(out, " throw ::rust::Error(error$);");
700 writeln!(out, " }}");
701 }
David Tolnay7db73692019-10-20 14:51:12 -0400702 if indirect_return {
David Tolnay4791f1c2020-03-17 21:53:16 -0700703 out.include.utility = true;
David Tolnay09011c32020-03-06 14:40:28 -0800704 writeln!(out, " return ::std::move(return$.value);");
David Tolnay7db73692019-10-20 14:51:12 -0400705 }
706 writeln!(out, "}}");
707 }
708}
709
710fn write_return_type(out: &mut OutFile, ty: &Option<Type>) {
711 match ty {
712 None => write!(out, "void "),
713 Some(ty) => write_type_space(out, ty),
714 }
715}
716
David Tolnay75dca2e2020-03-25 20:17:52 -0700717fn indirect_return(sig: &Signature, types: &Types) -> bool {
718 sig.ret
David Tolnay277e3cc2020-03-17 00:11:01 -0700719 .as_ref()
David Tolnay75dca2e2020-03-25 20:17:52 -0700720 .map_or(false, |ret| sig.throws || types.needs_indirect_abi(ret))
David Tolnay277e3cc2020-03-17 00:11:01 -0700721}
722
David Tolnay99642622020-03-25 13:07:35 -0700723fn write_indirect_return_type(out: &mut OutFile, ty: &Type) {
724 match ty {
725 Type::RustBox(ty) | Type::UniquePtr(ty) => {
726 write_type_space(out, &ty.inner);
727 write!(out, "*");
728 }
729 Type::Ref(ty) => {
730 if ty.mutability.is_none() {
731 write!(out, "const ");
732 }
733 write_type(out, &ty.inner);
734 write!(out, " *");
735 }
736 Type::Str(_) => write!(out, "::rust::Str::Repr"),
Adrian Taylorf5dd5522020-04-13 16:50:14 -0700737 Type::SliceRefU8(_) => write!(out, "::rust::Slice<uint8_t>::Repr"),
David Tolnay99642622020-03-25 13:07:35 -0700738 _ => write_type(out, ty),
739 }
740}
741
742fn write_indirect_return_type_space(out: &mut OutFile, ty: &Type) {
743 write_indirect_return_type(out, ty);
744 match ty {
745 Type::RustBox(_) | Type::UniquePtr(_) | Type::Ref(_) => {}
Adrian Taylorf5dd5522020-04-13 16:50:14 -0700746 Type::Str(_) | Type::SliceRefU8(_) => write!(out, " "),
David Tolnay99642622020-03-25 13:07:35 -0700747 _ => write_space_after_type(out, ty),
748 }
749}
750
751fn write_extern_return_type_space(out: &mut OutFile, ty: &Option<Type>, types: &Types) {
David Tolnay7db73692019-10-20 14:51:12 -0400752 match ty {
753 Some(Type::RustBox(ty)) | Some(Type::UniquePtr(ty)) => {
754 write_type_space(out, &ty.inner);
755 write!(out, "*");
756 }
David Tolnay4a441222020-01-25 16:24:27 -0800757 Some(Type::Ref(ty)) => {
758 if ty.mutability.is_none() {
759 write!(out, "const ");
760 }
761 write_type(out, &ty.inner);
762 write!(out, " *");
763 }
David Tolnay750755e2020-03-01 13:04:08 -0800764 Some(Type::Str(_)) => write!(out, "::rust::Str::Repr "),
Adrian Taylorf5dd5522020-04-13 16:50:14 -0700765 Some(Type::SliceRefU8(_)) => write!(out, "::rust::Slice<uint8_t>::Repr "),
David Tolnay7db73692019-10-20 14:51:12 -0400766 Some(ty) if types.needs_indirect_abi(ty) => write!(out, "void "),
767 _ => write_return_type(out, ty),
768 }
769}
770
771fn write_extern_arg(out: &mut OutFile, arg: &Var, types: &Types) {
772 match &arg.ty {
773 Type::RustBox(ty) | Type::UniquePtr(ty) => {
774 write_type_space(out, &ty.inner);
775 write!(out, "*");
776 }
David Tolnay750755e2020-03-01 13:04:08 -0800777 Type::Str(_) => write!(out, "::rust::Str::Repr "),
Adrian Taylorf5dd5522020-04-13 16:50:14 -0700778 Type::SliceRefU8(_) => write!(out, "::rust::Slice<uint8_t>::Repr "),
David Tolnay7db73692019-10-20 14:51:12 -0400779 _ => write_type_space(out, &arg.ty),
780 }
781 if types.needs_indirect_abi(&arg.ty) {
782 write!(out, "*");
783 }
784 write!(out, "{}", arg.ident);
785}
786
787fn write_type(out: &mut OutFile, ty: &Type) {
788 match ty {
789 Type::Ident(ident) => match Atom::from(ident) {
790 Some(Bool) => write!(out, "bool"),
791 Some(U8) => write!(out, "uint8_t"),
792 Some(U16) => write!(out, "uint16_t"),
793 Some(U32) => write!(out, "uint32_t"),
794 Some(U64) => write!(out, "uint64_t"),
795 Some(Usize) => write!(out, "size_t"),
796 Some(I8) => write!(out, "int8_t"),
797 Some(I16) => write!(out, "int16_t"),
798 Some(I32) => write!(out, "int32_t"),
799 Some(I64) => write!(out, "int64_t"),
David Tolnayb8a6fb22020-04-10 11:17:28 -0700800 Some(Isize) => write!(out, "::rust::isize"),
David Tolnay3383ae72020-03-13 01:12:26 -0700801 Some(F32) => write!(out, "float"),
802 Some(F64) => write!(out, "double"),
David Tolnay7e219b82020-03-01 13:14:51 -0800803 Some(CxxString) => write!(out, "::std::string"),
David Tolnay750755e2020-03-01 13:04:08 -0800804 Some(RustString) => write!(out, "::rust::String"),
David Tolnay7db73692019-10-20 14:51:12 -0400805 None => write!(out, "{}", ident),
806 },
807 Type::RustBox(ty) => {
David Tolnay750755e2020-03-01 13:04:08 -0800808 write!(out, "::rust::Box<");
David Tolnay7db73692019-10-20 14:51:12 -0400809 write_type(out, &ty.inner);
810 write!(out, ">");
811 }
812 Type::UniquePtr(ptr) => {
David Tolnay7e219b82020-03-01 13:14:51 -0800813 write!(out, "::std::unique_ptr<");
David Tolnay7db73692019-10-20 14:51:12 -0400814 write_type(out, &ptr.inner);
815 write!(out, ">");
816 }
817 Type::Ref(r) => {
818 if r.mutability.is_none() {
819 write!(out, "const ");
820 }
821 write_type(out, &r.inner);
822 write!(out, " &");
823 }
Adrian Taylorf5dd5522020-04-13 16:50:14 -0700824 Type::Slice(_) => {
825 // For now, only U8 slices are supported, which are covered separately below
826 unreachable!()
827 }
David Tolnay7db73692019-10-20 14:51:12 -0400828 Type::Str(_) => {
David Tolnay750755e2020-03-01 13:04:08 -0800829 write!(out, "::rust::Str");
David Tolnay7db73692019-10-20 14:51:12 -0400830 }
Adrian Taylorf5dd5522020-04-13 16:50:14 -0700831 Type::SliceRefU8(_) => {
832 write!(out, "::rust::Slice<uint8_t>");
833 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700834 Type::Fn(f) => {
835 write!(out, "::rust::{}<", if f.throws { "TryFn" } else { "Fn" });
836 match &f.ret {
837 Some(ret) => write_type(out, ret),
838 None => write!(out, "void"),
839 }
840 write!(out, "(");
841 for (i, arg) in f.args.iter().enumerate() {
842 if i > 0 {
843 write!(out, ", ");
844 }
845 write_type(out, &arg.ty);
846 }
847 write!(out, ")>");
848 }
David Tolnay2fb14e92020-03-15 23:11:38 -0700849 Type::Void(_) => unreachable!(),
David Tolnay7db73692019-10-20 14:51:12 -0400850 }
851}
852
853fn write_type_space(out: &mut OutFile, ty: &Type) {
854 write_type(out, ty);
David Tolnay99642622020-03-25 13:07:35 -0700855 write_space_after_type(out, ty);
856}
857
858fn write_space_after_type(out: &mut OutFile, ty: &Type) {
David Tolnay7db73692019-10-20 14:51:12 -0400859 match ty {
David Tolnayeb952ba2020-04-14 15:02:24 -0700860 Type::Ident(_)
861 | Type::RustBox(_)
862 | Type::UniquePtr(_)
863 | Type::Str(_)
864 | Type::SliceRefU8(_)
865 | Type::Fn(_) => write!(out, " "),
David Tolnay7db73692019-10-20 14:51:12 -0400866 Type::Ref(_) => {}
Adrian Taylorf5dd5522020-04-13 16:50:14 -0700867 Type::Void(_) | Type::Slice(_) => unreachable!(),
David Tolnay7db73692019-10-20 14:51:12 -0400868 }
869}
870
871fn write_generic_instantiations(out: &mut OutFile, types: &Types) {
872 fn allow_unique_ptr(ident: &Ident) -> bool {
873 Atom::from(ident).is_none()
874 }
875
876 out.begin_block("extern \"C\"");
877 for ty in types {
878 if let Type::RustBox(ty) = ty {
879 if let Type::Ident(inner) = &ty.inner {
880 out.next_section();
881 write_rust_box_extern(out, inner);
882 }
883 } else if let Type::UniquePtr(ptr) = ty {
884 if let Type::Ident(inner) = &ptr.inner {
885 if allow_unique_ptr(inner) {
886 out.next_section();
David Tolnay53838912020-04-09 20:56:44 -0700887 write_unique_ptr(out, inner, types);
David Tolnay7db73692019-10-20 14:51:12 -0400888 }
889 }
890 }
891 }
David Tolnay9ad1fbc2020-03-01 14:01:24 -0800892 out.end_block("extern \"C\"");
David Tolnay7db73692019-10-20 14:51:12 -0400893
David Tolnay750755e2020-03-01 13:04:08 -0800894 out.begin_block("namespace rust");
David Tolnay8c730492020-03-13 01:29:06 -0700895 out.begin_block("inline namespace cxxbridge02");
David Tolnay7db73692019-10-20 14:51:12 -0400896 for ty in types {
897 if let Type::RustBox(ty) = ty {
898 if let Type::Ident(inner) = &ty.inner {
899 write_rust_box_impl(out, inner);
900 }
901 }
902 }
David Tolnay8c730492020-03-13 01:29:06 -0700903 out.end_block("namespace cxxbridge02");
David Tolnay9ad1fbc2020-03-01 14:01:24 -0800904 out.end_block("namespace rust");
David Tolnay7db73692019-10-20 14:51:12 -0400905}
906
907fn write_rust_box_extern(out: &mut OutFile, ident: &Ident) {
908 let mut inner = String::new();
909 for name in &out.namespace {
910 inner += name;
911 inner += "::";
912 }
913 inner += &ident.to_string();
914 let instance = inner.replace("::", "$");
915
David Tolnay8c730492020-03-13 01:29:06 -0700916 writeln!(out, "#ifndef CXXBRIDGE02_RUST_BOX_{}", instance);
917 writeln!(out, "#define CXXBRIDGE02_RUST_BOX_{}", instance);
David Tolnay7db73692019-10-20 14:51:12 -0400918 writeln!(
919 out,
David Tolnay8c730492020-03-13 01:29:06 -0700920 "void cxxbridge02$box${}$uninit(::rust::Box<{}> *ptr) noexcept;",
David Tolnay7db73692019-10-20 14:51:12 -0400921 instance, inner,
922 );
923 writeln!(
924 out,
David Tolnay8c730492020-03-13 01:29:06 -0700925 "void cxxbridge02$box${}$drop(::rust::Box<{}> *ptr) noexcept;",
David Tolnay7db73692019-10-20 14:51:12 -0400926 instance, inner,
927 );
David Tolnay8c730492020-03-13 01:29:06 -0700928 writeln!(out, "#endif // CXXBRIDGE02_RUST_BOX_{}", instance);
David Tolnay7db73692019-10-20 14:51:12 -0400929}
930
931fn write_rust_box_impl(out: &mut OutFile, ident: &Ident) {
932 let mut inner = String::new();
933 for name in &out.namespace {
934 inner += name;
935 inner += "::";
936 }
937 inner += &ident.to_string();
938 let instance = inner.replace("::", "$");
939
940 writeln!(out, "template <>");
David Tolnay324437a2020-03-01 13:02:24 -0800941 writeln!(out, "void Box<{}>::uninit() noexcept {{", inner);
David Tolnay737e02e2020-04-04 21:52:46 -0700942 writeln!(out, " cxxbridge02$box${}$uninit(this);", instance);
David Tolnay7db73692019-10-20 14:51:12 -0400943 writeln!(out, "}}");
944
945 writeln!(out, "template <>");
David Tolnay324437a2020-03-01 13:02:24 -0800946 writeln!(out, "void Box<{}>::drop() noexcept {{", inner);
David Tolnay737e02e2020-04-04 21:52:46 -0700947 writeln!(out, " cxxbridge02$box${}$drop(this);", instance);
David Tolnay7db73692019-10-20 14:51:12 -0400948 writeln!(out, "}}");
David Tolnay7db73692019-10-20 14:51:12 -0400949}
950
David Tolnay53838912020-04-09 20:56:44 -0700951fn write_unique_ptr(out: &mut OutFile, ident: &Ident, types: &Types) {
David Tolnay4791f1c2020-03-17 21:53:16 -0700952 out.include.utility = true;
953
David Tolnay7db73692019-10-20 14:51:12 -0400954 let mut inner = String::new();
955 for name in &out.namespace {
956 inner += name;
957 inner += "::";
958 }
959 inner += &ident.to_string();
960 let instance = inner.replace("::", "$");
961
David Tolnay8c730492020-03-13 01:29:06 -0700962 writeln!(out, "#ifndef CXXBRIDGE02_UNIQUE_PTR_{}", instance);
963 writeln!(out, "#define CXXBRIDGE02_UNIQUE_PTR_{}", instance);
David Tolnay7db73692019-10-20 14:51:12 -0400964 writeln!(
965 out,
David Tolnay7e219b82020-03-01 13:14:51 -0800966 "static_assert(sizeof(::std::unique_ptr<{}>) == sizeof(void *), \"\");",
David Tolnay7db73692019-10-20 14:51:12 -0400967 inner,
968 );
969 writeln!(
970 out,
David Tolnay7e219b82020-03-01 13:14:51 -0800971 "static_assert(alignof(::std::unique_ptr<{}>) == alignof(void *), \"\");",
David Tolnay7db73692019-10-20 14:51:12 -0400972 inner,
973 );
974 writeln!(
975 out,
David Tolnay8c730492020-03-13 01:29:06 -0700976 "void cxxbridge02$unique_ptr${}$null(::std::unique_ptr<{}> *ptr) noexcept {{",
David Tolnay7db73692019-10-20 14:51:12 -0400977 instance, inner,
978 );
David Tolnay7e219b82020-03-01 13:14:51 -0800979 writeln!(out, " new (ptr) ::std::unique_ptr<{}>();", inner);
David Tolnay7db73692019-10-20 14:51:12 -0400980 writeln!(out, "}}");
David Tolnay53838912020-04-09 20:56:44 -0700981 if types.structs.contains_key(ident) {
982 writeln!(
983 out,
984 "void cxxbridge02$unique_ptr${}$new(::std::unique_ptr<{}> *ptr, {} *value) noexcept {{",
985 instance, inner, inner,
986 );
987 writeln!(
988 out,
989 " new (ptr) ::std::unique_ptr<{}>(new {}(::std::move(*value)));",
990 inner, inner,
991 );
992 writeln!(out, "}}");
993 }
David Tolnay7db73692019-10-20 14:51:12 -0400994 writeln!(
995 out,
David Tolnay8c730492020-03-13 01:29:06 -0700996 "void cxxbridge02$unique_ptr${}$raw(::std::unique_ptr<{}> *ptr, {} *raw) noexcept {{",
David Tolnay7db73692019-10-20 14:51:12 -0400997 instance, inner, inner,
998 );
David Tolnay7e219b82020-03-01 13:14:51 -0800999 writeln!(out, " new (ptr) ::std::unique_ptr<{}>(raw);", inner);
David Tolnay7db73692019-10-20 14:51:12 -04001000 writeln!(out, "}}");
1001 writeln!(
1002 out,
David Tolnay8c730492020-03-13 01:29:06 -07001003 "const {} *cxxbridge02$unique_ptr${}$get(const ::std::unique_ptr<{}>& ptr) noexcept {{",
David Tolnay7db73692019-10-20 14:51:12 -04001004 inner, instance, inner,
1005 );
1006 writeln!(out, " return ptr.get();");
1007 writeln!(out, "}}");
1008 writeln!(
1009 out,
David Tolnay8c730492020-03-13 01:29:06 -07001010 "{} *cxxbridge02$unique_ptr${}$release(::std::unique_ptr<{}>& ptr) noexcept {{",
David Tolnay7db73692019-10-20 14:51:12 -04001011 inner, instance, inner,
1012 );
1013 writeln!(out, " return ptr.release();");
1014 writeln!(out, "}}");
1015 writeln!(
1016 out,
David Tolnay8c730492020-03-13 01:29:06 -07001017 "void cxxbridge02$unique_ptr${}$drop(::std::unique_ptr<{}> *ptr) noexcept {{",
David Tolnay7db73692019-10-20 14:51:12 -04001018 instance, inner,
1019 );
1020 writeln!(out, " ptr->~unique_ptr();");
1021 writeln!(out, "}}");
David Tolnay8c730492020-03-13 01:29:06 -07001022 writeln!(out, "#endif // CXXBRIDGE02_UNIQUE_PTR_{}", instance);
David Tolnay7db73692019-10-20 14:51:12 -04001023}