blob: 7e1caac4737fd5f040b6b8d081b4699d843d7f77 [file] [log] [blame]
David Tolnay754e21c2020-03-29 20:58:46 -07001use crate::gen::namespace::Namespace;
David Tolnay7db73692019-10-20 14:51:12 -04002use crate::gen::out::OutFile;
David Tolnay33d30292020-03-18 18:02:02 -07003use crate::gen::{include, Opt};
David Tolnay7db73692019-10-20 14:51:12 -04004use crate::syntax::atom::Atom::{self, *};
Joel Galensonc1c4e7a2020-04-15 10:21:00 -07005use crate::syntax::{Api, ExternFn, ExternType, Receiver, Signature, Struct, Type, Types, Var};
David Tolnay7db73692019-10-20 14:51:12 -04006use proc_macro2::Ident;
7
David Tolnay33d30292020-03-18 18:02:02 -07008pub(super) fn gen(
David Tolnay754e21c2020-03-29 20:58:46 -07009 namespace: Namespace,
David Tolnay33d30292020-03-18 18:02:02 -070010 apis: &[Api],
11 types: &Types,
12 opt: Opt,
13 header: bool,
14) -> OutFile {
David Tolnay7db73692019-10-20 14:51:12 -040015 let mut out_file = OutFile::new(namespace.clone(), header);
16 let out = &mut out_file;
17
18 if header {
19 writeln!(out, "#pragma once");
20 }
21
David Tolnay33d30292020-03-18 18:02:02 -070022 out.include.extend(opt.include);
David Tolnay7db73692019-10-20 14:51:12 -040023 for api in apis {
24 if let Api::Include(include) = api {
David Tolnay9c68b1a2020-03-06 11:12:55 -080025 out.include.insert(include.value());
David Tolnay7db73692019-10-20 14:51:12 -040026 }
27 }
28
29 write_includes(out, types);
David Tolnayf51447e2020-03-06 14:14:27 -080030 write_include_cxxbridge(out, apis, types);
David Tolnay7db73692019-10-20 14:51:12 -040031
David Tolnay7db73692019-10-20 14:51:12 -040032 out.next_section();
33 for name in &namespace {
34 writeln!(out, "namespace {} {{", name);
35 }
36
David Tolnay7db73692019-10-20 14:51:12 -040037 out.next_section();
38 for api in apis {
39 match api {
40 Api::Struct(strct) => write_struct_decl(out, &strct.ident),
David Tolnay8861bee2020-01-20 18:39:24 -080041 Api::CxxType(ety) => write_struct_using(out, &ety.ident),
42 Api::RustType(ety) => write_struct_decl(out, &ety.ident),
David Tolnay7db73692019-10-20 14:51:12 -040043 _ => {}
44 }
45 }
46
47 for api in apis {
Joel Galensonc1c4e7a2020-04-15 10:21:00 -070048 match api {
49 Api::Struct(strct) => {
50 out.next_section();
51 write_struct(out, strct);
52 }
53 Api::RustType(ety) => {
54 let methods = apis.iter().filter_map(|api| match api {
55 Api::RustFunction(efn) => match &efn.sig.receiver {
56 Some(rcvr) if rcvr.ident == ety.ident => Some(efn),
57 _ => None,
58 },
59 _ => None,
60 }).collect::<Vec<_>>();
61 if !methods.is_empty() {
62 out.next_section();
63 write_struct_with_methods(out, ety, methods);
64 }
65 }
66 _ => {}
David Tolnay7db73692019-10-20 14:51:12 -040067 }
68 }
69
70 if !header {
71 out.begin_block("extern \"C\"");
David Tolnayebef4a22020-03-17 15:33:47 -070072 write_exception_glue(out, apis);
David Tolnay7db73692019-10-20 14:51:12 -040073 for api in apis {
74 let (efn, write): (_, fn(_, _, _)) = match api {
75 Api::CxxFunction(efn) => (efn, write_cxx_function_shim),
76 Api::RustFunction(efn) => (efn, write_rust_function_decl),
77 _ => continue,
78 };
79 out.next_section();
80 write(out, efn, types);
81 }
David Tolnay9ad1fbc2020-03-01 14:01:24 -080082 out.end_block("extern \"C\"");
David Tolnay7db73692019-10-20 14:51:12 -040083 }
84
85 for api in apis {
86 if let Api::RustFunction(efn) = api {
87 out.next_section();
88 write_rust_function_shim(out, efn, types);
89 }
90 }
91
92 out.next_section();
93 for name in namespace.iter().rev() {
94 writeln!(out, "}} // namespace {}", name);
95 }
96
97 if !header {
98 out.next_section();
99 write_generic_instantiations(out, types);
100 }
101
David Tolnay9c68b1a2020-03-06 11:12:55 -0800102 out.prepend(out.include.to_string());
103
David Tolnay7db73692019-10-20 14:51:12 -0400104 out_file
105}
106
107fn write_includes(out: &mut OutFile, types: &Types) {
David Tolnay7db73692019-10-20 14:51:12 -0400108 for ty in types {
109 match ty {
110 Type::Ident(ident) => match Atom::from(ident) {
David Tolnay30430f12020-03-19 20:49:00 -0700111 Some(U8) | Some(U16) | Some(U32) | Some(U64) | Some(I8) | Some(I16) | Some(I32)
112 | Some(I64) => out.include.cstdint = true,
113 Some(Usize) => out.include.cstddef = true,
David Tolnay9c68b1a2020-03-06 11:12:55 -0800114 Some(CxxString) => out.include.string = true,
David Tolnay30430f12020-03-19 20:49:00 -0700115 Some(Bool) | Some(Isize) | Some(F32) | Some(F64) | Some(RustString) | None => {}
David Tolnay7db73692019-10-20 14:51:12 -0400116 },
David Tolnay9c68b1a2020-03-06 11:12:55 -0800117 Type::RustBox(_) => out.include.type_traits = true,
118 Type::UniquePtr(_) => out.include.memory = true,
David Tolnay4770b472020-04-14 16:32:59 -0700119 Type::SliceRefU8(_) => out.include.cstdint = true,
David Tolnay7db73692019-10-20 14:51:12 -0400120 _ => {}
121 }
122 }
David Tolnay7db73692019-10-20 14:51:12 -0400123}
124
David Tolnayf51447e2020-03-06 14:14:27 -0800125fn write_include_cxxbridge(out: &mut OutFile, apis: &[Api], types: &Types) {
David Tolnayb7a7cb62020-03-17 21:18:40 -0700126 let mut needs_rust_string = false;
127 let mut needs_rust_str = false;
David Tolnay4770b472020-04-14 16:32:59 -0700128 let mut needs_rust_slice = false;
David Tolnay7db73692019-10-20 14:51:12 -0400129 let mut needs_rust_box = false;
David Tolnay75dca2e2020-03-25 20:17:52 -0700130 let mut needs_rust_fn = false;
David Tolnayb8a6fb22020-04-10 11:17:28 -0700131 let mut needs_rust_isize = false;
David Tolnay7db73692019-10-20 14:51:12 -0400132 for ty in types {
David Tolnayb7a7cb62020-03-17 21:18:40 -0700133 match ty {
134 Type::RustBox(_) => {
135 out.include.type_traits = true;
136 needs_rust_box = true;
137 }
138 Type::Str(_) => {
139 out.include.cstdint = true;
140 out.include.string = true;
141 needs_rust_str = true;
142 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700143 Type::Fn(_) => {
144 needs_rust_fn = true;
145 }
David Tolnay4770b472020-04-14 16:32:59 -0700146 Type::Slice(_) | Type::SliceRefU8(_) => {
147 needs_rust_slice = true;
148 }
David Tolnayb8a6fb22020-04-10 11:17:28 -0700149 ty if ty == Isize => {
David Tolnay59b5ba12020-04-10 11:32:19 -0700150 out.include.base_tsd = true;
David Tolnayb8a6fb22020-04-10 11:17:28 -0700151 needs_rust_isize = true;
152 }
David Tolnayb7a7cb62020-03-17 21:18:40 -0700153 ty if ty == RustString => {
154 out.include.array = true;
155 out.include.cstdint = true;
156 out.include.string = true;
157 needs_rust_string = true;
158 }
159 _ => {}
David Tolnay7db73692019-10-20 14:51:12 -0400160 }
161 }
162
David Tolnayb7a7cb62020-03-17 21:18:40 -0700163 let mut needs_rust_error = false;
164 let mut needs_unsafe_bitcopy = false;
David Tolnayf51447e2020-03-06 14:14:27 -0800165 let mut needs_manually_drop = false;
David Tolnay09011c32020-03-06 14:40:28 -0800166 let mut needs_maybe_uninit = false;
David Tolnay5d121442020-03-17 22:14:40 -0700167 let mut needs_trycatch = false;
David Tolnay09011c32020-03-06 14:40:28 -0800168 for api in apis {
David Tolnayb7a7cb62020-03-17 21:18:40 -0700169 match api {
170 Api::CxxFunction(efn) if !out.header => {
David Tolnay5d121442020-03-17 22:14:40 -0700171 if efn.throws {
172 needs_trycatch = true;
173 }
David Tolnayb7a7cb62020-03-17 21:18:40 -0700174 for arg in &efn.args {
175 if arg.ty == RustString {
176 needs_unsafe_bitcopy = true;
177 break;
178 }
David Tolnay09011c32020-03-06 14:40:28 -0800179 }
180 }
David Tolnayb7a7cb62020-03-17 21:18:40 -0700181 Api::RustFunction(efn) if !out.header => {
182 if efn.throws {
183 out.include.exception = true;
184 needs_rust_error = true;
185 }
186 for arg in &efn.args {
187 if arg.ty != RustString && types.needs_indirect_abi(&arg.ty) {
188 needs_manually_drop = true;
189 break;
190 }
191 }
192 if let Some(ret) = &efn.ret {
193 if types.needs_indirect_abi(ret) {
194 needs_maybe_uninit = true;
195 }
David Tolnayf51447e2020-03-06 14:14:27 -0800196 }
197 }
David Tolnayb7a7cb62020-03-17 21:18:40 -0700198 _ => {}
David Tolnayf51447e2020-03-06 14:14:27 -0800199 }
200 }
201
David Tolnay750755e2020-03-01 13:04:08 -0800202 out.begin_block("namespace rust");
David Tolnay8c730492020-03-13 01:29:06 -0700203 out.begin_block("inline namespace cxxbridge02");
David Tolnayf51447e2020-03-06 14:14:27 -0800204
David Tolnayb7a7cb62020-03-17 21:18:40 -0700205 if needs_rust_string
206 || needs_rust_str
David Tolnay4770b472020-04-14 16:32:59 -0700207 || needs_rust_slice
David Tolnayb7a7cb62020-03-17 21:18:40 -0700208 || needs_rust_box
David Tolnay75dca2e2020-03-25 20:17:52 -0700209 || needs_rust_fn
David Tolnayb7a7cb62020-03-17 21:18:40 -0700210 || needs_rust_error
David Tolnayb8a6fb22020-04-10 11:17:28 -0700211 || needs_rust_isize
David Tolnayb7a7cb62020-03-17 21:18:40 -0700212 || needs_unsafe_bitcopy
213 || needs_manually_drop
214 || needs_maybe_uninit
David Tolnay5d121442020-03-17 22:14:40 -0700215 || needs_trycatch
David Tolnayb7a7cb62020-03-17 21:18:40 -0700216 {
David Tolnay736cbca2020-03-11 16:49:18 -0700217 writeln!(out, "// #include \"rust/cxx.h\"");
David Tolnayf51447e2020-03-06 14:14:27 -0800218 }
219
David Tolnayd1402742020-03-25 22:21:42 -0700220 if needs_rust_string {
221 out.next_section();
222 writeln!(out, "struct unsafe_bitcopy_t;");
223 }
224
David Tolnayb7a7cb62020-03-17 21:18:40 -0700225 write_header_section(out, needs_rust_string, "CXXBRIDGE02_RUST_STRING");
226 write_header_section(out, needs_rust_str, "CXXBRIDGE02_RUST_STR");
David Tolnay4770b472020-04-14 16:32:59 -0700227 write_header_section(out, needs_rust_slice, "CXXBRIDGE02_RUST_SLICE");
David Tolnayb7a7cb62020-03-17 21:18:40 -0700228 write_header_section(out, needs_rust_box, "CXXBRIDGE02_RUST_BOX");
David Tolnay75dca2e2020-03-25 20:17:52 -0700229 write_header_section(out, needs_rust_fn, "CXXBRIDGE02_RUST_FN");
David Tolnayb7a7cb62020-03-17 21:18:40 -0700230 write_header_section(out, needs_rust_error, "CXXBRIDGE02_RUST_ERROR");
David Tolnayb8a6fb22020-04-10 11:17:28 -0700231 write_header_section(out, needs_rust_isize, "CXXBRIDGE02_RUST_ISIZE");
David Tolnayb7a7cb62020-03-17 21:18:40 -0700232 write_header_section(out, needs_unsafe_bitcopy, "CXXBRIDGE02_RUST_BITCOPY");
David Tolnayf51447e2020-03-06 14:14:27 -0800233
234 if needs_manually_drop {
235 out.next_section();
David Tolnay4791f1c2020-03-17 21:53:16 -0700236 out.include.utility = true;
David Tolnayf51447e2020-03-06 14:14:27 -0800237 writeln!(out, "template <typename T>");
238 writeln!(out, "union ManuallyDrop {{");
239 writeln!(out, " T value;");
240 writeln!(
241 out,
242 " ManuallyDrop(T &&value) : value(::std::move(value)) {{}}",
243 );
244 writeln!(out, " ~ManuallyDrop() {{}}");
245 writeln!(out, "}};");
246 }
247
David Tolnay09011c32020-03-06 14:40:28 -0800248 if needs_maybe_uninit {
249 out.next_section();
250 writeln!(out, "template <typename T>");
251 writeln!(out, "union MaybeUninit {{");
252 writeln!(out, " T value;");
253 writeln!(out, " MaybeUninit() {{}}");
254 writeln!(out, " ~MaybeUninit() {{}}");
255 writeln!(out, "}};");
256 }
257
David Tolnay3e3e0af2020-03-17 22:42:49 -0700258 out.end_block("namespace cxxbridge02");
259
David Tolnay5d121442020-03-17 22:14:40 -0700260 if needs_trycatch {
David Tolnay3e3e0af2020-03-17 22:42:49 -0700261 out.begin_block("namespace behavior");
David Tolnay5d121442020-03-17 22:14:40 -0700262 out.include.exception = true;
David Tolnay04722332020-03-18 11:31:54 -0700263 out.include.type_traits = true;
264 out.include.utility = true;
265 writeln!(out, "class missing {{}};");
266 writeln!(out, "missing trycatch(...);");
David Tolnay3e3e0af2020-03-17 22:42:49 -0700267 writeln!(out);
David Tolnay04722332020-03-18 11:31:54 -0700268 writeln!(out, "template <typename Try, typename Fail>");
269 writeln!(out, "static typename std::enable_if<");
David Tolnay3e3e0af2020-03-17 22:42:49 -0700270 writeln!(
271 out,
David Tolnay04722332020-03-18 11:31:54 -0700272 " std::is_same<decltype(trycatch(std::declval<Try>(), std::declval<Fail>())),",
David Tolnay3e3e0af2020-03-17 22:42:49 -0700273 );
David Tolnay04722332020-03-18 11:31:54 -0700274 writeln!(out, " missing>::value>::type");
275 writeln!(out, "trycatch(Try &&func, Fail &&fail) noexcept try {{");
David Tolnay5d121442020-03-17 22:14:40 -0700276 writeln!(out, " func();");
277 writeln!(out, "}} catch (const ::std::exception &e) {{");
278 writeln!(out, " fail(e.what());");
279 writeln!(out, "}}");
David Tolnay3e3e0af2020-03-17 22:42:49 -0700280 out.end_block("namespace behavior");
David Tolnay5d121442020-03-17 22:14:40 -0700281 }
282
David Tolnay9ad1fbc2020-03-01 14:01:24 -0800283 out.end_block("namespace rust");
David Tolnay7db73692019-10-20 14:51:12 -0400284}
285
David Tolnayb7a7cb62020-03-17 21:18:40 -0700286fn write_header_section(out: &mut OutFile, needed: bool, section: &str) {
David Tolnay8e086612020-04-10 12:20:46 -0700287 let section = include::get(section);
David Tolnayb7a7cb62020-03-17 21:18:40 -0700288 if needed {
289 out.next_section();
David Tolnay8e086612020-04-10 12:20:46 -0700290 for line in section.lines() {
David Tolnayb7a7cb62020-03-17 21:18:40 -0700291 if !line.trim_start().starts_with("//") {
292 writeln!(out, "{}", line);
293 }
294 }
295 }
296}
297
David Tolnay7db73692019-10-20 14:51:12 -0400298fn write_struct(out: &mut OutFile, strct: &Struct) {
299 for line in strct.doc.to_string().lines() {
300 writeln!(out, "//{}", line);
301 }
302 writeln!(out, "struct {} final {{", strct.ident);
303 for field in &strct.fields {
304 write!(out, " ");
305 write_type_space(out, &field.ty);
306 writeln!(out, "{};", field.ident);
307 }
308 writeln!(out, "}};");
309}
310
311fn write_struct_decl(out: &mut OutFile, ident: &Ident) {
312 writeln!(out, "struct {};", ident);
313}
314
David Tolnay8861bee2020-01-20 18:39:24 -0800315fn write_struct_using(out: &mut OutFile, ident: &Ident) {
316 writeln!(out, "using {} = {};", ident, ident);
317}
318
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700319fn write_struct_with_methods(out: &mut OutFile, ety: &ExternType, methods: Vec<&ExternFn>) {
320 for line in ety.doc.to_string().lines() {
321 writeln!(out, "//{}", line);
322 }
323 writeln!(out, "struct {} final {{", ety.ident);
324 for method in &methods {
325 write!(out, " ");
326 let sig = &method.sig;
327 let local_name = method.ident.to_string();
328 write_rust_function_shim_decl(out, &local_name, sig, None, false);
329 writeln!(out, ";");
330 }
331 writeln!(out, "}};");
332}
333
David Tolnayebef4a22020-03-17 15:33:47 -0700334fn write_exception_glue(out: &mut OutFile, apis: &[Api]) {
335 let mut has_cxx_throws = false;
336 for api in apis {
337 if let Api::CxxFunction(efn) = api {
338 if efn.throws {
339 has_cxx_throws = true;
340 break;
341 }
342 }
343 }
344
345 if has_cxx_throws {
346 out.next_section();
David Tolnaye68634c2020-03-18 12:03:40 -0700347 writeln!(
David Tolnayebef4a22020-03-17 15:33:47 -0700348 out,
349 "const char *cxxbridge02$exception(const char *, size_t);",
350 );
351 }
352}
353
David Tolnay7db73692019-10-20 14:51:12 -0400354fn write_cxx_function_shim(out: &mut OutFile, efn: &ExternFn, types: &Types) {
David Tolnayebef4a22020-03-17 15:33:47 -0700355 if efn.throws {
356 write!(out, "::rust::Str::Repr ");
357 } else {
David Tolnay99642622020-03-25 13:07:35 -0700358 write_extern_return_type_space(out, &efn.ret, types);
David Tolnayebef4a22020-03-17 15:33:47 -0700359 }
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700360 let receiver_type = match &efn.receiver {
361 Some(base) => base.ident.to_string(),
362 None => "_".to_string(),
363 };
364 write!(out, "{}cxxbridge02${}${}(", out.namespace, receiver_type, efn.ident);
Joel Galenson3d4f6122020-04-07 15:54:05 -0700365 if let Some(base) = &efn.receiver {
366 write!(out, "{} *__receiver$", base.ident);
367 }
David Tolnay7db73692019-10-20 14:51:12 -0400368 for (i, arg) in efn.args.iter().enumerate() {
Joel Galenson3d4f6122020-04-07 15:54:05 -0700369 if i > 0 || efn.receiver.is_some() {
David Tolnay7db73692019-10-20 14:51:12 -0400370 write!(out, ", ");
371 }
David Tolnaya46a2372020-03-06 10:03:48 -0800372 if arg.ty == RustString {
373 write!(out, "const ");
374 }
David Tolnay7db73692019-10-20 14:51:12 -0400375 write_extern_arg(out, arg, types);
376 }
David Tolnay277e3cc2020-03-17 00:11:01 -0700377 let indirect_return = indirect_return(efn, types);
David Tolnay7db73692019-10-20 14:51:12 -0400378 if indirect_return {
379 if !efn.args.is_empty() {
380 write!(out, ", ");
381 }
David Tolnay99642622020-03-25 13:07:35 -0700382 write_indirect_return_type_space(out, efn.ret.as_ref().unwrap());
David Tolnay7db73692019-10-20 14:51:12 -0400383 write!(out, "*return$");
384 }
385 writeln!(out, ") noexcept {{");
386 write!(out, " ");
387 write_return_type(out, &efn.ret);
Joel Galenson3d4f6122020-04-07 15:54:05 -0700388 match &efn.receiver {
389 None => write!(out, "(*{}$)(", efn.ident),
390 Some(base) => write!(out, "({}::*{}$)(", base.ident, efn.ident),
391 }
David Tolnay7db73692019-10-20 14:51:12 -0400392 for (i, arg) in efn.args.iter().enumerate() {
393 if i > 0 {
394 write!(out, ", ");
395 }
396 write_type(out, &arg.ty);
397 }
Joel Galenson3d4f6122020-04-07 15:54:05 -0700398 write!(out, ")");
399 match &efn.receiver {
400 Some(Receiver { mutability: None, ident: _ }) => write!(out, " const"),
401 _ => {},
402 }
403 write!(out, " = ");
404 match &efn.receiver {
405 None => write!(out, "{}", efn.ident),
406 Some(base) => write!(out, "&{}::{}", base.ident, efn.ident),
407 }
408 writeln!(out, ";");
David Tolnay7db73692019-10-20 14:51:12 -0400409 write!(out, " ");
David Tolnayebef4a22020-03-17 15:33:47 -0700410 if efn.throws {
411 writeln!(out, "::rust::Str::Repr throw$;");
David Tolnay3e3e0af2020-03-17 22:42:49 -0700412 writeln!(out, " ::rust::behavior::trycatch(");
David Tolnay5d121442020-03-17 22:14:40 -0700413 writeln!(out, " [&] {{");
414 write!(out, " ");
David Tolnayebef4a22020-03-17 15:33:47 -0700415 }
David Tolnay7db73692019-10-20 14:51:12 -0400416 if indirect_return {
417 write!(out, "new (return$) ");
David Tolnay99642622020-03-25 13:07:35 -0700418 write_indirect_return_type(out, efn.ret.as_ref().unwrap());
David Tolnay7db73692019-10-20 14:51:12 -0400419 write!(out, "(");
David Tolnay99642622020-03-25 13:07:35 -0700420 } else if efn.ret.is_some() {
David Tolnay7db73692019-10-20 14:51:12 -0400421 write!(out, "return ");
David Tolnay99642622020-03-25 13:07:35 -0700422 }
423 match &efn.ret {
424 Some(Type::Ref(_)) => write!(out, "&"),
425 Some(Type::Str(_)) if !indirect_return => write!(out, "::rust::Str::Repr("),
David Tolnayeb952ba2020-04-14 15:02:24 -0700426 Some(Type::SliceRefU8(_)) if !indirect_return => {
427 write!(out, "::rust::Slice<uint8_t>::Repr(")
428 }
David Tolnay99642622020-03-25 13:07:35 -0700429 _ => {}
David Tolnay7db73692019-10-20 14:51:12 -0400430 }
Joel Galenson3d4f6122020-04-07 15:54:05 -0700431 match &efn.receiver {
432 None => write!(out, "{}$(", efn.ident),
433 Some(_) => write!(out, "(__receiver$->*{}$)(", efn.ident),
434 }
David Tolnay7db73692019-10-20 14:51:12 -0400435 for (i, arg) in efn.args.iter().enumerate() {
436 if i > 0 {
437 write!(out, ", ");
438 }
439 if let Type::RustBox(_) = &arg.ty {
440 write_type(out, &arg.ty);
441 write!(out, "::from_raw({})", arg.ident);
442 } else if let Type::UniquePtr(_) = &arg.ty {
443 write_type(out, &arg.ty);
444 write!(out, "({})", arg.ident);
David Tolnaya46a2372020-03-06 10:03:48 -0800445 } else if arg.ty == RustString {
David Tolnaycc3767f2020-03-06 10:41:51 -0800446 write!(
447 out,
448 "::rust::String(::rust::unsafe_bitcopy, *{})",
449 arg.ident,
450 );
David Tolnay7db73692019-10-20 14:51:12 -0400451 } else if types.needs_indirect_abi(&arg.ty) {
David Tolnay4791f1c2020-03-17 21:53:16 -0700452 out.include.utility = true;
David Tolnay7e219b82020-03-01 13:14:51 -0800453 write!(out, "::std::move(*{})", arg.ident);
David Tolnay7db73692019-10-20 14:51:12 -0400454 } else {
455 write!(out, "{}", arg.ident);
456 }
457 }
458 write!(out, ")");
459 match &efn.ret {
460 Some(Type::RustBox(_)) => write!(out, ".into_raw()"),
461 Some(Type::UniquePtr(_)) => write!(out, ".release()"),
Adrian Taylorf5dd5522020-04-13 16:50:14 -0700462 Some(Type::Str(_)) | Some(Type::SliceRefU8(_)) if !indirect_return => write!(out, ")"),
David Tolnay7db73692019-10-20 14:51:12 -0400463 _ => {}
464 }
465 if indirect_return {
466 write!(out, ")");
467 }
468 writeln!(out, ";");
David Tolnayebef4a22020-03-17 15:33:47 -0700469 if efn.throws {
470 out.include.cstring = true;
David Tolnay5d121442020-03-17 22:14:40 -0700471 writeln!(out, " throw$.ptr = nullptr;");
472 writeln!(out, " }},");
David Tolnay82c16172020-03-17 22:54:12 -0700473 writeln!(out, " [&](const char *catch$) noexcept {{");
David Tolnay5d121442020-03-17 22:14:40 -0700474 writeln!(out, " throw$.len = ::std::strlen(catch$);");
David Tolnayebef4a22020-03-17 15:33:47 -0700475 writeln!(
476 out,
David Tolnay5d121442020-03-17 22:14:40 -0700477 " throw$.ptr = cxxbridge02$exception(catch$, throw$.len);",
David Tolnayebef4a22020-03-17 15:33:47 -0700478 );
David Tolnay5d121442020-03-17 22:14:40 -0700479 writeln!(out, " }});");
David Tolnayebef4a22020-03-17 15:33:47 -0700480 writeln!(out, " return throw$;");
481 }
David Tolnay7db73692019-10-20 14:51:12 -0400482 writeln!(out, "}}");
David Tolnay75dca2e2020-03-25 20:17:52 -0700483 for arg in &efn.args {
484 if let Type::Fn(f) = &arg.ty {
485 let var = &arg.ident;
486 write_function_pointer_trampoline(out, efn, var, f, types);
487 }
488 }
489}
490
491fn write_function_pointer_trampoline(
492 out: &mut OutFile,
493 efn: &ExternFn,
494 var: &Ident,
495 f: &Signature,
496 types: &Types,
497) {
498 out.next_section();
499 let r_trampoline = format!("{}cxxbridge02${}${}$1", out.namespace, efn.ident, var);
500 let indirect_call = true;
501 write_rust_function_decl_impl(out, &r_trampoline, f, types, indirect_call);
502
503 out.next_section();
504 let c_trampoline = format!("{}cxxbridge02${}${}$0", out.namespace, efn.ident, var);
505 write_rust_function_shim_impl(out, &c_trampoline, f, types, &r_trampoline, indirect_call);
David Tolnay7db73692019-10-20 14:51:12 -0400506}
507
508fn write_rust_function_decl(out: &mut OutFile, efn: &ExternFn, types: &Types) {
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700509 let receiver_type = match &efn.receiver {
510 Some(base) => base.ident.to_string(),
511 None => "_".to_string(),
512 };
513 let link_name = format!("{}cxxbridge02${}${}", out.namespace, receiver_type, efn.ident);
David Tolnay75dca2e2020-03-25 20:17:52 -0700514 let indirect_call = false;
515 write_rust_function_decl_impl(out, &link_name, efn, types, indirect_call);
516}
517
518fn write_rust_function_decl_impl(
519 out: &mut OutFile,
520 link_name: &str,
521 sig: &Signature,
522 types: &Types,
523 indirect_call: bool,
524) {
525 if sig.throws {
David Tolnay1e548172020-03-16 13:37:09 -0700526 write!(out, "::rust::Str::Repr ");
527 } else {
David Tolnay75dca2e2020-03-25 20:17:52 -0700528 write_extern_return_type_space(out, &sig.ret, types);
David Tolnay1e548172020-03-16 13:37:09 -0700529 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700530 write!(out, "{}(", link_name);
531 let mut needs_comma = false;
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700532 if let Some(base) = &sig.receiver {
533 write!(out, "{} &__receiver$", base.ident);
534 needs_comma = true;
535 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700536 for arg in &sig.args {
537 if needs_comma {
David Tolnay7db73692019-10-20 14:51:12 -0400538 write!(out, ", ");
539 }
540 write_extern_arg(out, arg, types);
David Tolnay75dca2e2020-03-25 20:17:52 -0700541 needs_comma = true;
David Tolnay7db73692019-10-20 14:51:12 -0400542 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700543 if indirect_return(sig, types) {
544 if needs_comma {
David Tolnay7db73692019-10-20 14:51:12 -0400545 write!(out, ", ");
546 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700547 write_return_type(out, &sig.ret);
David Tolnay7db73692019-10-20 14:51:12 -0400548 write!(out, "*return$");
David Tolnay75dca2e2020-03-25 20:17:52 -0700549 needs_comma = true;
550 }
551 if indirect_call {
552 if needs_comma {
553 write!(out, ", ");
554 }
555 write!(out, "void *");
David Tolnay7db73692019-10-20 14:51:12 -0400556 }
557 writeln!(out, ") noexcept;");
558}
559
560fn write_rust_function_shim(out: &mut OutFile, efn: &ExternFn, types: &Types) {
David Tolnay7db73692019-10-20 14:51:12 -0400561 for line in efn.doc.to_string().lines() {
562 writeln!(out, "//{}", line);
563 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700564 let local_name = efn.ident.to_string();
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700565 let receiver_type = match &efn.receiver {
566 Some(base) => base.ident.to_string(),
567 None => "_".to_string(),
568 };
569 let invoke = format!("{}cxxbridge02${}${}", out.namespace, receiver_type, efn.ident);
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);
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700656 if let Some(_) = &sig.receiver {
657 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}