blob: de992dbf8d49390a333efd5189c725d054ae0f07 [file] [log] [blame]
David Tolnayf7b81fb2020-11-01 22:39:04 -08001use crate::gen::nested::NamespaceEntries;
David Tolnay8810a542020-10-31 21:39:22 -07002use crate::gen::out::OutFile;
David Tolnay942cffd2020-11-03 18:27:10 -08003use crate::gen::{builtin, include, Opt};
David Tolnay7db73692019-10-20 14:51:12 -04004use crate::syntax::atom::Atom::{self, *};
David Tolnay891061b2020-04-19 22:42:33 -07005use crate::syntax::symbol::Symbol;
Adrian Taylorc8713432020-10-21 18:20:55 -07006use crate::syntax::{
David Tolnay75ea17c2020-12-06 21:08:34 -08007 derive, mangle, Api, Enum, ExternFn, ExternType, Pair, RustName, Signature, Struct, Trait,
8 Type, Types, Var,
Adrian Taylorc8713432020-10-21 18:20:55 -07009};
Adrian Taylor7b443f72020-12-07 15:47:19 -080010use crate::{gen::block::Block, syntax::types::TrivialReason};
David Tolnay7db73692019-10-20 14:51:12 -040011use proc_macro2::Ident;
David Tolnay5439fa12020-11-03 18:45:01 -080012use std::collections::{HashMap, HashSet};
David Tolnay7db73692019-10-20 14:51:12 -040013
David Tolnayac7188c2020-11-01 16:58:16 -080014pub(super) fn gen(apis: &[Api], types: &Types, opt: &Opt, header: bool) -> Vec<u8> {
David Tolnaye1476af2020-11-01 13:47:25 -080015 let mut out_file = OutFile::new(header, opt, types);
David Tolnay7db73692019-10-20 14:51:12 -040016 let out = &mut out_file;
17
David Tolnaydfb82d72020-11-02 00:10:10 -080018 pick_includes_and_builtins(out, apis);
David Tolnay4aae7c02020-10-28 12:35:42 -070019 out.include.extend(&opt.include);
David Tolnay7db73692019-10-20 14:51:12 -040020
David Tolnay7b0e5102020-11-01 23:22:12 -080021 write_forward_declarations(out, apis);
David Tolnaye1109d92020-11-01 20:51:56 -080022 write_data_structures(out, apis);
23 write_functions(out, apis);
David Tolnay169bb472020-11-01 21:04:24 -080024 write_generic_instantiations(out);
David Tolnay7db73692019-10-20 14:51:12 -040025
David Tolnay3374d8d2020-10-31 22:18:45 -070026 builtin::write(out);
David Tolnay2f3e90b2020-10-31 22:16:51 -070027 include::write(out);
Adrian Taylorc8713432020-10-21 18:20:55 -070028
David Tolnayac7188c2020-11-01 16:58:16 -080029 out_file.content()
Adrian Taylorc8713432020-10-21 18:20:55 -070030}
31
David Tolnay7b0e5102020-11-01 23:22:12 -080032fn write_forward_declarations(out: &mut OutFile, apis: &[Api]) {
33 let needs_forward_declaration = |api: &&Api| match api {
David Tolnay4bfca112020-11-01 23:59:11 -080034 Api::Struct(_) | Api::CxxType(_) | Api::RustType(_) => true,
David Tolnay17a934c2020-11-02 00:40:04 -080035 Api::Enum(enm) => !out.types.cxx.contains(&enm.name.rust),
David Tolnay7b0e5102020-11-01 23:22:12 -080036 _ => false,
37 };
Adrian Taylorc8713432020-10-21 18:20:55 -070038
David Tolnay7b0e5102020-11-01 23:22:12 -080039 let apis_by_namespace =
40 NamespaceEntries::new(apis.iter().filter(needs_forward_declaration).collect());
41
David Tolnayd920be52020-11-01 23:34:30 -080042 write(out, &apis_by_namespace, 0);
David Tolnay7b0e5102020-11-01 23:22:12 -080043
David Tolnayd920be52020-11-01 23:34:30 -080044 fn write(out: &mut OutFile, ns_entries: &NamespaceEntries, indent: usize) {
David Tolnay7b0e5102020-11-01 23:22:12 -080045 let apis = ns_entries.direct_content();
46
47 for api in apis {
David Tolnayd920be52020-11-01 23:34:30 -080048 write!(out, "{:1$}", "", indent);
David Tolnay7b0e5102020-11-01 23:22:12 -080049 match api {
David Tolnay17a934c2020-11-02 00:40:04 -080050 Api::Struct(strct) => write_struct_decl(out, &strct.name.cxx),
David Tolnay0e3ee8e2020-11-01 23:46:52 -080051 Api::Enum(enm) => write_enum_decl(out, enm),
David Tolnay17a934c2020-11-02 00:40:04 -080052 Api::CxxType(ety) => write_struct_using(out, &ety.name),
53 Api::RustType(ety) => write_struct_decl(out, &ety.name.cxx),
David Tolnay7b0e5102020-11-01 23:22:12 -080054 _ => unreachable!(),
55 }
David Tolnay7db73692019-10-20 14:51:12 -040056 }
David Tolnay7db73692019-10-20 14:51:12 -040057
David Tolnay7b0e5102020-11-01 23:22:12 -080058 for (namespace, nested_ns_entries) in ns_entries.nested_content() {
David Tolnayd920be52020-11-01 23:34:30 -080059 writeln!(out, "{:2$}namespace {} {{", "", namespace, indent);
60 write(out, nested_ns_entries, indent + 2);
61 writeln!(out, "{:1$}}}", "", indent);
David Tolnay7b0e5102020-11-01 23:22:12 -080062 }
Adrian Taylorf9213622020-10-31 22:25:42 -070063 }
64}
65
David Tolnaye1109d92020-11-01 20:51:56 -080066fn write_data_structures<'a>(out: &mut OutFile<'a>, apis: &'a [Api]) {
David Tolnayf94bef12020-04-17 14:46:42 -070067 let mut methods_for_type = HashMap::new();
David Tolnay630af882020-10-31 22:03:47 -070068 for api in apis {
David Tolnay102c7ea2020-11-08 18:58:09 -080069 if let Api::CxxFunction(efn) | Api::RustFunction(efn) = api {
David Tolnayf94bef12020-04-17 14:46:42 -070070 if let Some(receiver) = &efn.sig.receiver {
71 methods_for_type
Adrian Taylorc8713432020-10-21 18:20:55 -070072 .entry(&receiver.ty.rust)
David Tolnayf94bef12020-04-17 14:46:42 -070073 .or_insert_with(Vec::new)
74 .push(efn);
75 }
76 }
77 }
Joel Galenson968738f2020-04-15 14:19:33 -070078
David Tolnay5439fa12020-11-03 18:45:01 -080079 let mut structs_written = HashSet::new();
80 let mut toposorted_structs = out.types.toposorted_structs.iter();
David Tolnay9622b462020-11-02 21:34:42 -080081 for api in apis {
Joel Galensonc1c4e7a2020-04-15 10:21:00 -070082 match api {
David Tolnay5439fa12020-11-03 18:45:01 -080083 Api::Struct(strct) if !structs_written.contains(&strct.name.rust) => {
84 for next in &mut toposorted_structs {
85 if !out.types.cxx.contains(&strct.name.rust) {
86 out.next_section();
David Tolnay102c7ea2020-11-08 18:58:09 -080087 let methods = methods_for_type
88 .get(&strct.name.rust)
89 .map(Vec::as_slice)
90 .unwrap_or_default();
91 write_struct(out, next, methods);
David Tolnay5439fa12020-11-03 18:45:01 -080092 }
93 structs_written.insert(&next.name.rust);
94 if next.name.rust == strct.name.rust {
95 break;
96 }
97 }
98 }
Joel Galensonc03402a2020-04-23 17:31:09 -070099 Api::Enum(enm) => {
100 out.next_section();
David Tolnay17a934c2020-11-02 00:40:04 -0800101 if out.types.cxx.contains(&enm.name.rust) {
Joel Galenson905eb2e2020-05-04 14:58:14 -0700102 check_enum(out, enm);
103 } else {
104 write_enum(out, enm);
105 }
Joel Galensonc03402a2020-04-23 17:31:09 -0700106 }
David Tolnayc1fe0052020-04-17 15:15:06 -0700107 Api::RustType(ety) => {
David Tolnay17a934c2020-11-02 00:40:04 -0800108 if let Some(methods) = methods_for_type.get(&ety.name.rust) {
David Tolnay46a54e72020-04-17 14:48:21 -0700109 out.next_section();
David Tolnaya7c2ea12020-10-30 21:32:53 -0700110 write_struct_with_methods(out, ety, methods);
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700111 }
David Tolnayc1fe0052020-04-17 15:15:06 -0700112 }
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700113 _ => {}
David Tolnay7db73692019-10-20 14:51:12 -0400114 }
115 }
116
David Tolnayfabca772020-10-03 21:25:41 -0700117 out.next_section();
118 for api in apis {
119 if let Api::TypeAlias(ety) = api {
Adrian Taylor7b443f72020-12-07 15:47:19 -0800120 if let Some(reason) = out.types.required_trivial.get(&ety.name.rust) {
121 check_trivial_extern_type(out, &ety.name, reason)
David Tolnayfabca772020-10-03 21:25:41 -0700122 }
123 }
124 }
David Tolnay1b0339c2020-11-01 20:37:50 -0800125}
126
David Tolnaye1109d92020-11-01 20:51:56 -0800127fn write_functions<'a>(out: &mut OutFile<'a>, apis: &'a [Api]) {
David Tolnayce5a91f2020-10-31 22:42:08 -0700128 if !out.header {
David Tolnay7db73692019-10-20 14:51:12 -0400129 for api in apis {
David Tolnay04770742020-11-01 13:50:50 -0800130 match api {
David Tolnayb960ed22020-11-27 14:34:30 -0800131 Api::Struct(strct) => write_struct_operator_decls(out, strct),
David Tolnay04770742020-11-01 13:50:50 -0800132 Api::CxxFunction(efn) => write_cxx_function_shim(out, efn),
133 Api::RustFunction(efn) => write_rust_function_decl(out, efn),
134 _ => {}
135 }
David Tolnay7db73692019-10-20 14:51:12 -0400136 }
David Tolnay7da38202020-11-27 17:36:16 -0800137
138 write_std_specializations(out, apis);
David Tolnay7db73692019-10-20 14:51:12 -0400139 }
140
141 for api in apis {
David Tolnayb960ed22020-11-27 14:34:30 -0800142 match api {
143 Api::Struct(strct) => write_struct_operators(out, strct),
144 Api::RustFunction(efn) => {
145 out.next_section();
146 write_rust_function_shim(out, efn);
147 }
148 _ => {}
David Tolnay7db73692019-10-20 14:51:12 -0400149 }
150 }
David Tolnay7db73692019-10-20 14:51:12 -0400151}
152
David Tolnay7da38202020-11-27 17:36:16 -0800153fn write_std_specializations(out: &mut OutFile, apis: &[Api]) {
154 out.set_namespace(Default::default());
155 out.begin_block(Block::Namespace("std"));
156
157 for api in apis {
158 if let Api::Struct(strct) = api {
159 if derive::contains(&strct.derives, Trait::Hash) {
160 out.next_section();
161 let qualified = strct.name.to_fully_qualified();
162 writeln!(out, "template <> struct hash<{}> {{", qualified);
163 writeln!(
164 out,
165 " size_t operator()(const {} &self) const noexcept {{",
166 qualified,
167 );
168 let link_name = mangle::operator(&strct.name, "hash");
169 write!(out, " return ::");
170 for name in &strct.name.namespace {
171 write!(out, "{}::", name);
172 }
173 writeln!(out, "{}(self);", link_name);
174 writeln!(out, " }}");
175 writeln!(out, "}};");
176 }
177 }
178 }
179
180 out.end_block(Block::Namespace("std"));
181}
182
David Tolnaydfb82d72020-11-02 00:10:10 -0800183fn pick_includes_and_builtins(out: &mut OutFile, apis: &[Api]) {
184 for api in apis {
185 if let Api::Include(include) = api {
186 out.include.insert(include);
187 }
188 }
189
David Tolnaya7c2ea12020-10-30 21:32:53 -0700190 for ty in out.types {
David Tolnay7db73692019-10-20 14:51:12 -0400191 match ty {
Adrian Taylorc8713432020-10-21 18:20:55 -0700192 Type::Ident(ident) => match Atom::from(&ident.rust) {
David Tolnay89e386d2020-10-03 19:02:19 -0700193 Some(U8) | Some(U16) | Some(U32) | Some(U64) | Some(I8) | Some(I16) | Some(I32)
194 | Some(I64) => out.include.cstdint = true,
195 Some(Usize) => out.include.cstddef = true,
David Tolnaydcfa8e92020-11-02 09:50:06 -0800196 Some(Isize) => out.builtin.rust_isize = true,
David Tolnay89e386d2020-10-03 19:02:19 -0700197 Some(CxxString) => out.include.string = true,
David Tolnaydcfa8e92020-11-02 09:50:06 -0800198 Some(RustString) => out.builtin.rust_string = true,
David Tolnayb3873dc2020-11-25 19:47:49 -0800199 Some(Bool) | Some(Char) | Some(F32) | Some(F64) | None => {}
David Tolnay89e386d2020-10-03 19:02:19 -0700200 },
David Tolnaydcfa8e92020-11-02 09:50:06 -0800201 Type::RustBox(_) => out.builtin.rust_box = true,
202 Type::RustVec(_) => out.builtin.rust_vec = true,
David Tolnayb9da1462020-10-31 21:03:41 -0700203 Type::UniquePtr(_) => out.include.memory = true,
David Tolnayb3b24a12020-12-01 15:27:43 -0800204 Type::SharedPtr(_) => out.include.memory = true,
David Tolnaydcfa8e92020-11-02 09:50:06 -0800205 Type::Str(_) => out.builtin.rust_str = true,
David Tolnayb9da1462020-10-31 21:03:41 -0700206 Type::CxxVector(_) => out.include.vector = true,
David Tolnaydcfa8e92020-11-02 09:50:06 -0800207 Type::Fn(_) => out.builtin.rust_fn = true,
David Tolnay5515a9e2020-11-25 19:07:54 -0800208 Type::SliceRef(_) => out.builtin.rust_slice = true,
David Tolnaye8b1bb42020-11-24 20:37:37 -0800209 Type::Array(_) => out.include.array = true,
David Tolnay11bd7ff2020-11-01 19:44:58 -0800210 Type::Ref(_) | Type::Void(_) => {}
David Tolnay7db73692019-10-20 14:51:12 -0400211 }
212 }
David Tolnayec66d112020-10-31 21:00:26 -0700213}
David Tolnayf51447e2020-03-06 14:14:27 -0800214
David Tolnay102c7ea2020-11-08 18:58:09 -0800215fn write_struct<'a>(out: &mut OutFile<'a>, strct: &'a Struct, methods: &[&ExternFn]) {
David Tolnayb960ed22020-11-27 14:34:30 -0800216 let operator_eq = derive::contains(&strct.derives, Trait::PartialEq);
David Tolnay84389352020-11-27 17:12:10 -0800217 let operator_ord = derive::contains(&strct.derives, Trait::PartialOrd);
David Tolnayb960ed22020-11-27 14:34:30 -0800218
David Tolnay17a934c2020-11-02 00:40:04 -0800219 out.set_namespace(&strct.name.namespace);
David Tolnay0f0162f2020-11-16 23:43:37 -0800220 let guard = format!("CXXBRIDGE1_STRUCT_{}", strct.name.to_symbol());
David Tolnaya25ea9c2020-08-27 22:59:38 -0700221 writeln!(out, "#ifndef {}", guard);
222 writeln!(out, "#define {}", guard);
David Tolnay7db73692019-10-20 14:51:12 -0400223 for line in strct.doc.to_string().lines() {
224 writeln!(out, "//{}", line);
225 }
David Tolnay17a934c2020-11-02 00:40:04 -0800226 writeln!(out, "struct {} final {{", strct.name.cxx);
David Tolnay84389352020-11-27 17:12:10 -0800227
David Tolnay7db73692019-10-20 14:51:12 -0400228 for field in &strct.fields {
229 write!(out, " ");
David Tolnaya7c2ea12020-10-30 21:32:53 -0700230 write_type_space(out, &field.ty);
David Tolnay7db73692019-10-20 14:51:12 -0400231 writeln!(out, "{};", field.ident);
232 }
David Tolnay84389352020-11-27 17:12:10 -0800233
234 if !methods.is_empty() || operator_eq || operator_ord {
David Tolnay102c7ea2020-11-08 18:58:09 -0800235 writeln!(out);
236 }
David Tolnay84389352020-11-27 17:12:10 -0800237
David Tolnay102c7ea2020-11-08 18:58:09 -0800238 for method in methods {
239 write!(out, " ");
240 let sig = &method.sig;
241 let local_name = method.name.cxx.to_string();
242 write_rust_function_shim_decl(out, &local_name, sig, false);
243 writeln!(out, ";");
244 }
David Tolnay84389352020-11-27 17:12:10 -0800245
David Tolnayb960ed22020-11-27 14:34:30 -0800246 if operator_eq {
247 writeln!(
248 out,
249 " bool operator==(const {} &) const noexcept;",
250 strct.name.cxx,
251 );
252 writeln!(
253 out,
254 " bool operator!=(const {} &) const noexcept;",
255 strct.name.cxx,
256 );
257 }
David Tolnay84389352020-11-27 17:12:10 -0800258
259 if operator_ord {
260 writeln!(
261 out,
262 " bool operator<(const {} &) const noexcept;",
263 strct.name.cxx,
264 );
265 writeln!(
266 out,
267 " bool operator<=(const {} &) const noexcept;",
268 strct.name.cxx,
269 );
270 writeln!(
271 out,
272 " bool operator>(const {} &) const noexcept;",
273 strct.name.cxx,
274 );
275 writeln!(
276 out,
277 " bool operator>=(const {} &) const noexcept;",
278 strct.name.cxx,
279 );
280 }
281
David Tolnay7db73692019-10-20 14:51:12 -0400282 writeln!(out, "}};");
David Tolnaya25ea9c2020-08-27 22:59:38 -0700283 writeln!(out, "#endif // {}", guard);
David Tolnay7db73692019-10-20 14:51:12 -0400284}
285
286fn write_struct_decl(out: &mut OutFile, ident: &Ident) {
287 writeln!(out, "struct {};", ident);
288}
289
David Tolnay0e3ee8e2020-11-01 23:46:52 -0800290fn write_enum_decl(out: &mut OutFile, enm: &Enum) {
David Tolnay17a934c2020-11-02 00:40:04 -0800291 write!(out, "enum class {} : ", enm.name.cxx);
David Tolnay0e3ee8e2020-11-01 23:46:52 -0800292 write_atom(out, enm.repr);
293 writeln!(out, ";");
294}
295
David Tolnay8faec772020-11-02 00:18:19 -0800296fn write_struct_using(out: &mut OutFile, ident: &Pair) {
297 writeln!(out, "using {} = {};", ident.cxx, ident.to_fully_qualified());
David Tolnay8861bee2020-01-20 18:39:24 -0800298}
299
David Tolnay0b9b9f82020-11-01 20:41:00 -0800300fn write_struct_with_methods<'a>(
301 out: &mut OutFile<'a>,
302 ety: &'a ExternType,
303 methods: &[&ExternFn],
304) {
David Tolnay17a934c2020-11-02 00:40:04 -0800305 out.set_namespace(&ety.name.namespace);
David Tolnay0f0162f2020-11-16 23:43:37 -0800306 let guard = format!("CXXBRIDGE1_STRUCT_{}", ety.name.to_symbol());
David Tolnaya25ea9c2020-08-27 22:59:38 -0700307 writeln!(out, "#ifndef {}", guard);
308 writeln!(out, "#define {}", guard);
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700309 for line in ety.doc.to_string().lines() {
310 writeln!(out, "//{}", line);
311 }
David Tolnay365fc7c2020-11-25 16:08:13 -0800312 out.builtin.opaque = true;
David Tolnay7c06b862020-11-25 16:59:09 -0800313 writeln!(
314 out,
315 "struct {} final : public ::rust::Opaque {{",
316 ety.name.cxx,
317 );
Joel Galenson968738f2020-04-15 14:19:33 -0700318 for method in methods {
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700319 write!(out, " ");
320 let sig = &method.sig;
David Tolnay17a934c2020-11-02 00:40:04 -0800321 let local_name = method.name.cxx.to_string();
David Tolnaya7c2ea12020-10-30 21:32:53 -0700322 write_rust_function_shim_decl(out, &local_name, sig, false);
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700323 writeln!(out, ";");
324 }
325 writeln!(out, "}};");
David Tolnaya25ea9c2020-08-27 22:59:38 -0700326 writeln!(out, "#endif // {}", guard);
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700327}
328
David Tolnay0b9b9f82020-11-01 20:41:00 -0800329fn write_enum<'a>(out: &mut OutFile<'a>, enm: &'a Enum) {
David Tolnay17a934c2020-11-02 00:40:04 -0800330 out.set_namespace(&enm.name.namespace);
David Tolnay0f0162f2020-11-16 23:43:37 -0800331 let guard = format!("CXXBRIDGE1_ENUM_{}", enm.name.to_symbol());
David Tolnaya25ea9c2020-08-27 22:59:38 -0700332 writeln!(out, "#ifndef {}", guard);
333 writeln!(out, "#define {}", guard);
Joel Galensonc03402a2020-04-23 17:31:09 -0700334 for line in enm.doc.to_string().lines() {
335 writeln!(out, "//{}", line);
336 }
David Tolnay17a934c2020-11-02 00:40:04 -0800337 write!(out, "enum class {} : ", enm.name.cxx);
David Tolnayf6a89f22020-05-10 23:39:27 -0700338 write_atom(out, enm.repr);
339 writeln!(out, " {{");
Joel Galensonc03402a2020-04-23 17:31:09 -0700340 for variant in &enm.variants {
Joel Galenson88547732020-05-05 08:23:42 -0700341 writeln!(out, " {} = {},", variant.ident, variant.discriminant);
Joel Galensonc03402a2020-04-23 17:31:09 -0700342 }
343 writeln!(out, "}};");
David Tolnaya25ea9c2020-08-27 22:59:38 -0700344 writeln!(out, "#endif // {}", guard);
Joel Galensonc03402a2020-04-23 17:31:09 -0700345}
346
David Tolnay0b9b9f82020-11-01 20:41:00 -0800347fn check_enum<'a>(out: &mut OutFile<'a>, enm: &'a Enum) {
David Tolnay17a934c2020-11-02 00:40:04 -0800348 out.set_namespace(&enm.name.namespace);
David Tolnay06711bc2020-11-19 19:25:14 -0800349 out.include.type_traits = true;
350 writeln!(
351 out,
352 "static_assert(::std::is_enum<{}>::value, \"expected enum\");",
353 enm.name.cxx,
354 );
David Tolnay17a934c2020-11-02 00:40:04 -0800355 write!(out, "static_assert(sizeof({}) == sizeof(", enm.name.cxx);
David Tolnayf6a89f22020-05-10 23:39:27 -0700356 write_atom(out, enm.repr);
357 writeln!(out, "), \"incorrect size\");");
Joel Galenson0f654ff2020-05-04 20:04:21 -0700358 for variant in &enm.variants {
David Tolnayf6a89f22020-05-10 23:39:27 -0700359 write!(out, "static_assert(static_cast<");
360 write_atom(out, enm.repr);
Joel Galenson0f654ff2020-05-04 20:04:21 -0700361 writeln!(
362 out,
David Tolnayf6a89f22020-05-10 23:39:27 -0700363 ">({}::{}) == {}, \"disagrees with the value in #[cxx::bridge]\");",
David Tolnay17a934c2020-11-02 00:40:04 -0800364 enm.name.cxx, variant.ident, variant.discriminant,
Joel Galenson0f654ff2020-05-04 20:04:21 -0700365 );
Joel Galenson0f654ff2020-05-04 20:04:21 -0700366 }
Joel Galenson905eb2e2020-05-04 14:58:14 -0700367}
368
Adrian Taylor7b443f72020-12-07 15:47:19 -0800369fn check_trivial_extern_type(out: &mut OutFile, id: &Pair, reason: &TrivialReason) {
David Tolnay174bd952020-11-02 09:23:12 -0800370 // NOTE: The following static assertion is just nice-to-have and not
David Tolnayfd0034e2020-10-04 13:15:34 -0700371 // necessary for soundness. That's because triviality is always declared by
372 // the user in the form of an unsafe impl of cxx::ExternType:
373 //
374 // unsafe impl ExternType for MyType {
375 // type Id = cxx::type_id!("...");
376 // type Kind = cxx::kind::Trivial;
377 // }
378 //
379 // Since the user went on the record with their unsafe impl to unsafely
380 // claim they KNOW that the type is trivial, it's fine for that to be on
David Tolnay174bd952020-11-02 09:23:12 -0800381 // them if that were wrong. However, in practice correctly reasoning about
382 // the relocatability of C++ types is challenging, particularly if the type
383 // definition were to change over time, so for now we add this check.
David Tolnayfd0034e2020-10-04 13:15:34 -0700384 //
David Tolnay174bd952020-11-02 09:23:12 -0800385 // There may be legitimate reasons to opt out of this assertion for support
386 // of types that the programmer knows are soundly Rust-movable despite not
387 // being recognized as such by the C++ type system due to a move constructor
388 // or destructor. To opt out of the relocatability check, they need to do
389 // one of the following things in any header used by `include!` in their
390 // bridge.
391 //
392 // --- if they define the type:
393 // struct MyType {
394 // ...
395 // + using IsRelocatable = std::true_type;
396 // };
397 //
398 // --- otherwise:
399 // + template <>
400 // + struct rust::IsRelocatable<MyType> : std::true_type {};
401 //
David Tolnayfd0034e2020-10-04 13:15:34 -0700402
David Tolnay174bd952020-11-02 09:23:12 -0800403 let id = id.to_fully_qualified();
404 out.builtin.relocatable = true;
David Tolnay7426cc12020-10-03 19:04:04 -0700405 writeln!(out, "static_assert(");
David Tolnay174bd952020-11-02 09:23:12 -0800406 writeln!(out, " ::rust::IsRelocatable<{}>::value,", id);
David Tolnay7426cc12020-10-03 19:04:04 -0700407 writeln!(
408 out,
Adrian Taylor7b443f72020-12-07 15:47:19 -0800409 " \"type {} is not move constructible and trivially destructible in C++ yet is used as a trivial type in Rust ({})\");",
David Tolnay7426cc12020-10-03 19:04:04 -0700410 id,
Adrian Taylor7b443f72020-12-07 15:47:19 -0800411 reason
David Tolnay7426cc12020-10-03 19:04:04 -0700412 );
Adrian Taylor405e8742020-09-25 14:01:25 -0700413}
414
David Tolnayb960ed22020-11-27 14:34:30 -0800415fn write_struct_operator_decls<'a>(out: &mut OutFile<'a>, strct: &'a Struct) {
416 out.set_namespace(&strct.name.namespace);
417 out.begin_block(Block::ExternC);
418
419 if derive::contains(&strct.derives, Trait::PartialEq) {
David Tolnaya05f9402020-11-27 17:44:05 -0800420 let link_name = mangle::operator(&strct.name, "eq");
David Tolnayb960ed22020-11-27 14:34:30 -0800421 writeln!(
422 out,
423 "bool {}(const {1} &, const {1} &) noexcept;",
424 link_name, strct.name.cxx,
425 );
David Tolnaya6f3b6f2020-11-27 16:47:30 -0800426
427 if !derive::contains(&strct.derives, Trait::Eq) {
David Tolnaya05f9402020-11-27 17:44:05 -0800428 let link_name = mangle::operator(&strct.name, "ne");
David Tolnaya6f3b6f2020-11-27 16:47:30 -0800429 writeln!(
430 out,
431 "bool {}(const {1} &, const {1} &) noexcept;",
432 link_name, strct.name.cxx,
433 );
434 }
David Tolnayb960ed22020-11-27 14:34:30 -0800435 }
436
David Tolnay84389352020-11-27 17:12:10 -0800437 if derive::contains(&strct.derives, Trait::PartialOrd) {
David Tolnaya05f9402020-11-27 17:44:05 -0800438 let link_name = mangle::operator(&strct.name, "lt");
David Tolnay84389352020-11-27 17:12:10 -0800439 writeln!(
440 out,
441 "bool {}(const {1} &, const {1} &) noexcept;",
442 link_name, strct.name.cxx,
443 );
444
David Tolnaya05f9402020-11-27 17:44:05 -0800445 let link_name = mangle::operator(&strct.name, "le");
David Tolnay84389352020-11-27 17:12:10 -0800446 writeln!(
447 out,
448 "bool {}(const {1} &, const {1} &) noexcept;",
449 link_name, strct.name.cxx,
450 );
451
452 if !derive::contains(&strct.derives, Trait::Ord) {
David Tolnaya05f9402020-11-27 17:44:05 -0800453 let link_name = mangle::operator(&strct.name, "gt");
David Tolnay84389352020-11-27 17:12:10 -0800454 writeln!(
455 out,
456 "bool {}(const {1} &, const {1} &) noexcept;",
457 link_name, strct.name.cxx,
458 );
459
David Tolnaya05f9402020-11-27 17:44:05 -0800460 let link_name = mangle::operator(&strct.name, "ge");
David Tolnay84389352020-11-27 17:12:10 -0800461 writeln!(
462 out,
463 "bool {}(const {1} &, const {1} &) noexcept;",
464 link_name, strct.name.cxx,
465 );
466 }
467 }
468
David Tolnay7da38202020-11-27 17:36:16 -0800469 if derive::contains(&strct.derives, Trait::Hash) {
470 let link_name = mangle::operator(&strct.name, "hash");
471 writeln!(
472 out,
473 "size_t {}(const {} &) noexcept;",
474 link_name, strct.name.cxx,
475 );
476 }
477
David Tolnayb960ed22020-11-27 14:34:30 -0800478 out.end_block(Block::ExternC);
479}
480
481fn write_struct_operators<'a>(out: &mut OutFile<'a>, strct: &'a Struct) {
482 if out.header {
483 return;
484 }
485
486 out.set_namespace(&strct.name.namespace);
487
488 if derive::contains(&strct.derives, Trait::PartialEq) {
David Tolnayb960ed22020-11-27 14:34:30 -0800489 out.next_section();
490 writeln!(
491 out,
492 "bool {0}::operator==(const {0} &rhs) const noexcept {{",
493 strct.name.cxx,
494 );
David Tolnaya05f9402020-11-27 17:44:05 -0800495 let link_name = mangle::operator(&strct.name, "eq");
David Tolnayb960ed22020-11-27 14:34:30 -0800496 writeln!(out, " return {}(*this, rhs);", link_name);
497 writeln!(out, "}}");
David Tolnaya6f3b6f2020-11-27 16:47:30 -0800498
David Tolnayb960ed22020-11-27 14:34:30 -0800499 out.next_section();
500 writeln!(
501 out,
502 "bool {0}::operator!=(const {0} &rhs) const noexcept {{",
503 strct.name.cxx,
504 );
David Tolnaya6f3b6f2020-11-27 16:47:30 -0800505 if derive::contains(&strct.derives, Trait::Eq) {
506 writeln!(out, " return !(*this == rhs);");
507 } else {
David Tolnaya05f9402020-11-27 17:44:05 -0800508 let link_name = mangle::operator(&strct.name, "ne");
David Tolnaya6f3b6f2020-11-27 16:47:30 -0800509 writeln!(out, " return {}(*this, rhs);", link_name);
510 }
David Tolnayb960ed22020-11-27 14:34:30 -0800511 writeln!(out, "}}");
512 }
David Tolnay84389352020-11-27 17:12:10 -0800513
514 if derive::contains(&strct.derives, Trait::PartialOrd) {
515 out.next_section();
516 writeln!(
517 out,
518 "bool {0}::operator<(const {0} &rhs) const noexcept {{",
519 strct.name.cxx,
520 );
David Tolnaya05f9402020-11-27 17:44:05 -0800521 let link_name = mangle::operator(&strct.name, "lt");
David Tolnay84389352020-11-27 17:12:10 -0800522 writeln!(out, " return {}(*this, rhs);", link_name);
523 writeln!(out, "}}");
524
525 out.next_section();
526 writeln!(
527 out,
528 "bool {0}::operator<=(const {0} &rhs) const noexcept {{",
529 strct.name.cxx,
530 );
David Tolnaya05f9402020-11-27 17:44:05 -0800531 let link_name = mangle::operator(&strct.name, "le");
David Tolnay84389352020-11-27 17:12:10 -0800532 writeln!(out, " return {}(*this, rhs);", link_name);
533 writeln!(out, "}}");
534
535 out.next_section();
536 writeln!(
537 out,
538 "bool {0}::operator>(const {0} &rhs) const noexcept {{",
539 strct.name.cxx,
540 );
541 if derive::contains(&strct.derives, Trait::Ord) {
542 writeln!(out, " return !(*this <= rhs);");
543 } else {
David Tolnaya05f9402020-11-27 17:44:05 -0800544 let link_name = mangle::operator(&strct.name, "gt");
David Tolnay84389352020-11-27 17:12:10 -0800545 writeln!(out, " return {}(*this, rhs);", link_name);
546 }
547 writeln!(out, "}}");
548
549 out.next_section();
550 writeln!(
551 out,
552 "bool {0}::operator>=(const {0} &rhs) const noexcept {{",
553 strct.name.cxx,
554 );
555 if derive::contains(&strct.derives, Trait::Ord) {
556 writeln!(out, " return !(*this < rhs);");
557 } else {
David Tolnaya05f9402020-11-27 17:44:05 -0800558 let link_name = mangle::operator(&strct.name, "ge");
David Tolnay84389352020-11-27 17:12:10 -0800559 writeln!(out, " return {}(*this, rhs);", link_name);
560 }
561 writeln!(out, "}}");
562 }
David Tolnayb960ed22020-11-27 14:34:30 -0800563}
564
David Tolnay0b9b9f82020-11-01 20:41:00 -0800565fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
David Tolnay04770742020-11-01 13:50:50 -0800566 out.next_section();
David Tolnay17a934c2020-11-02 00:40:04 -0800567 out.set_namespace(&efn.name.namespace);
David Tolnayca563ee2020-11-01 20:12:27 -0800568 out.begin_block(Block::ExternC);
David Tolnaye1476af2020-11-01 13:47:25 -0800569 if let Some(annotation) = &out.opt.cxx_impl_annotations {
David Tolnaycc1ae762020-10-31 15:53:50 -0700570 write!(out, "{} ", annotation);
Adrian Taylor21f0ff02020-07-21 16:21:48 -0700571 }
David Tolnayebef4a22020-03-17 15:33:47 -0700572 if efn.throws {
David Tolnay919085c2020-10-31 22:32:22 -0700573 out.builtin.ptr_len = true;
David Tolnayd68dfa82020-10-31 16:01:24 -0700574 write!(out, "::rust::repr::PtrLen ");
David Tolnayebef4a22020-03-17 15:33:47 -0700575 } else {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700576 write_extern_return_type_space(out, &efn.ret);
David Tolnayebef4a22020-03-17 15:33:47 -0700577 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700578 let mangled = mangle::extern_fn(efn, out.types);
David Tolnay3caa50a2020-04-19 21:25:34 -0700579 write!(out, "{}(", mangled);
David Tolnaye439c772020-04-20 00:23:55 -0700580 if let Some(receiver) = &efn.receiver {
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800581 if !receiver.mutable {
David Tolnay86710612020-04-20 00:30:32 -0700582 write!(out, "const ");
583 }
Adrian Taylorc8713432020-10-21 18:20:55 -0700584 write!(
585 out,
586 "{} &self",
David Tolnay8faec772020-11-02 00:18:19 -0800587 out.types.resolve(&receiver.ty).to_fully_qualified(),
Adrian Taylorc8713432020-10-21 18:20:55 -0700588 );
Joel Galenson3d4f6122020-04-07 15:54:05 -0700589 }
David Tolnay7db73692019-10-20 14:51:12 -0400590 for (i, arg) in efn.args.iter().enumerate() {
Joel Galenson3d4f6122020-04-07 15:54:05 -0700591 if i > 0 || efn.receiver.is_some() {
David Tolnay7db73692019-10-20 14:51:12 -0400592 write!(out, ", ");
593 }
David Tolnaya46a2372020-03-06 10:03:48 -0800594 if arg.ty == RustString {
595 write!(out, "const ");
David Tolnay313b10e2020-04-25 16:30:51 -0700596 } else if let Type::RustVec(_) = arg.ty {
597 write!(out, "const ");
David Tolnaya46a2372020-03-06 10:03:48 -0800598 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700599 write_extern_arg(out, arg);
David Tolnay7db73692019-10-20 14:51:12 -0400600 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700601 let indirect_return = indirect_return(efn, out.types);
David Tolnay7db73692019-10-20 14:51:12 -0400602 if indirect_return {
myronahne3b78ea2020-05-23 01:08:13 +0700603 if !efn.args.is_empty() || efn.receiver.is_some() {
David Tolnay7db73692019-10-20 14:51:12 -0400604 write!(out, ", ");
605 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700606 write_indirect_return_type_space(out, efn.ret.as_ref().unwrap());
David Tolnay7db73692019-10-20 14:51:12 -0400607 write!(out, "*return$");
608 }
609 writeln!(out, ") noexcept {{");
610 write!(out, " ");
David Tolnaya7c2ea12020-10-30 21:32:53 -0700611 write_return_type(out, &efn.ret);
Joel Galenson3d4f6122020-04-07 15:54:05 -0700612 match &efn.receiver {
David Tolnay17a934c2020-11-02 00:40:04 -0800613 None => write!(out, "(*{}$)(", efn.name.rust),
Adrian Taylorc8713432020-10-21 18:20:55 -0700614 Some(receiver) => write!(
615 out,
616 "({}::*{}$)(",
David Tolnaya7c2ea12020-10-30 21:32:53 -0700617 out.types.resolve(&receiver.ty).to_fully_qualified(),
David Tolnay17a934c2020-11-02 00:40:04 -0800618 efn.name.rust,
Adrian Taylorc8713432020-10-21 18:20:55 -0700619 ),
Joel Galenson3d4f6122020-04-07 15:54:05 -0700620 }
David Tolnay7db73692019-10-20 14:51:12 -0400621 for (i, arg) in efn.args.iter().enumerate() {
622 if i > 0 {
623 write!(out, ", ");
624 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700625 write_type(out, &arg.ty);
David Tolnay7db73692019-10-20 14:51:12 -0400626 }
Joel Galenson3d4f6122020-04-07 15:54:05 -0700627 write!(out, ")");
David Tolnay4e7123f2020-04-19 21:11:37 -0700628 if let Some(receiver) = &efn.receiver {
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800629 if !receiver.mutable {
David Tolnay4e7123f2020-04-19 21:11:37 -0700630 write!(out, " const");
631 }
Joel Galenson3d4f6122020-04-07 15:54:05 -0700632 }
633 write!(out, " = ");
634 match &efn.receiver {
David Tolnay17a934c2020-11-02 00:40:04 -0800635 None => write!(out, "{}", efn.name.to_fully_qualified()),
Adrian Taylorc8713432020-10-21 18:20:55 -0700636 Some(receiver) => write!(
637 out,
638 "&{}::{}",
David Tolnaya7c2ea12020-10-30 21:32:53 -0700639 out.types.resolve(&receiver.ty).to_fully_qualified(),
David Tolnay17a934c2020-11-02 00:40:04 -0800640 efn.name.cxx,
Adrian Taylorc8713432020-10-21 18:20:55 -0700641 ),
Joel Galenson3d4f6122020-04-07 15:54:05 -0700642 }
643 writeln!(out, ";");
David Tolnay7db73692019-10-20 14:51:12 -0400644 write!(out, " ");
David Tolnayebef4a22020-03-17 15:33:47 -0700645 if efn.throws {
David Tolnay919085c2020-10-31 22:32:22 -0700646 out.builtin.ptr_len = true;
David Tolnay74d6d512020-10-31 22:22:03 -0700647 out.builtin.trycatch = true;
David Tolnayd68dfa82020-10-31 16:01:24 -0700648 writeln!(out, "::rust::repr::PtrLen throw$;");
David Tolnay3e3e0af2020-03-17 22:42:49 -0700649 writeln!(out, " ::rust::behavior::trycatch(");
David Tolnay5d121442020-03-17 22:14:40 -0700650 writeln!(out, " [&] {{");
651 write!(out, " ");
David Tolnayebef4a22020-03-17 15:33:47 -0700652 }
David Tolnay7db73692019-10-20 14:51:12 -0400653 if indirect_return {
David Tolnay0ecd05a2020-07-29 16:32:03 -0700654 out.include.new = true;
David Tolnay7db73692019-10-20 14:51:12 -0400655 write!(out, "new (return$) ");
David Tolnaya7c2ea12020-10-30 21:32:53 -0700656 write_indirect_return_type(out, efn.ret.as_ref().unwrap());
David Tolnay7db73692019-10-20 14:51:12 -0400657 write!(out, "(");
David Tolnay99642622020-03-25 13:07:35 -0700658 } else if efn.ret.is_some() {
David Tolnay7db73692019-10-20 14:51:12 -0400659 write!(out, "return ");
David Tolnay99642622020-03-25 13:07:35 -0700660 }
661 match &efn.ret {
662 Some(Type::Ref(_)) => write!(out, "&"),
David Tolnay74d6d512020-10-31 22:22:03 -0700663 Some(Type::Str(_)) if !indirect_return => {
664 out.builtin.rust_str_repr = true;
665 write!(out, "::rust::impl<::rust::Str>::repr(");
666 }
David Tolnay73b72642020-11-25 17:44:05 -0800667 Some(ty @ Type::SliceRef(_)) if !indirect_return => {
David Tolnay36aa9e02020-10-31 23:08:21 -0700668 out.builtin.rust_slice_repr = true;
David Tolnayc5629f02020-11-23 18:32:46 -0800669 write!(out, "::rust::impl<");
670 write_type(out, ty);
671 write!(out, ">::repr(");
David Tolnayeb952ba2020-04-14 15:02:24 -0700672 }
David Tolnay99642622020-03-25 13:07:35 -0700673 _ => {}
David Tolnay7db73692019-10-20 14:51:12 -0400674 }
Joel Galenson3d4f6122020-04-07 15:54:05 -0700675 match &efn.receiver {
David Tolnay17a934c2020-11-02 00:40:04 -0800676 None => write!(out, "{}$(", efn.name.rust),
677 Some(_) => write!(out, "(self.*{}$)(", efn.name.rust),
Joel Galenson3d4f6122020-04-07 15:54:05 -0700678 }
David Tolnay7db73692019-10-20 14:51:12 -0400679 for (i, arg) in efn.args.iter().enumerate() {
680 if i > 0 {
681 write!(out, ", ");
682 }
683 if let Type::RustBox(_) = &arg.ty {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700684 write_type(out, &arg.ty);
David Tolnay7db73692019-10-20 14:51:12 -0400685 write!(out, "::from_raw({})", arg.ident);
686 } else if let Type::UniquePtr(_) = &arg.ty {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700687 write_type(out, &arg.ty);
David Tolnay7db73692019-10-20 14:51:12 -0400688 write!(out, "({})", arg.ident);
David Tolnay0356d332020-10-31 19:46:41 -0700689 } else if let Type::Str(_) = arg.ty {
David Tolnay74d6d512020-10-31 22:22:03 -0700690 out.builtin.rust_str_new_unchecked = true;
David Tolnay0356d332020-10-31 19:46:41 -0700691 write!(
692 out,
693 "::rust::impl<::rust::Str>::new_unchecked({})",
694 arg.ident,
695 );
David Tolnaya46a2372020-03-06 10:03:48 -0800696 } else if arg.ty == RustString {
David Tolnay74d6d512020-10-31 22:22:03 -0700697 out.builtin.unsafe_bitcopy = true;
David Tolnaycc3767f2020-03-06 10:41:51 -0800698 write!(
699 out,
700 "::rust::String(::rust::unsafe_bitcopy, *{})",
701 arg.ident,
702 );
David Tolnay313b10e2020-04-25 16:30:51 -0700703 } else if let Type::RustVec(_) = arg.ty {
David Tolnay74d6d512020-10-31 22:22:03 -0700704 out.builtin.unsafe_bitcopy = true;
David Tolnaya7c2ea12020-10-30 21:32:53 -0700705 write_type(out, &arg.ty);
David Tolnay313b10e2020-04-25 16:30:51 -0700706 write!(out, "(::rust::unsafe_bitcopy, *{})", arg.ident);
David Tolnay73b72642020-11-25 17:44:05 -0800707 } else if let Type::SliceRef(slice) = &arg.ty {
David Tolnayc5629f02020-11-23 18:32:46 -0800708 write_type(out, &arg.ty);
709 write!(out, "(static_cast<");
710 if slice.mutability.is_none() {
711 write!(out, "const ");
712 }
David Tolnay5515a9e2020-11-25 19:07:54 -0800713 write_type_space(out, &slice.inner);
714 write!(out, "*>({0}.ptr), {0}.len)", arg.ident);
David Tolnaya7c2ea12020-10-30 21:32:53 -0700715 } else if out.types.needs_indirect_abi(&arg.ty) {
David Tolnay4791f1c2020-03-17 21:53:16 -0700716 out.include.utility = true;
David Tolnay7e219b82020-03-01 13:14:51 -0800717 write!(out, "::std::move(*{})", arg.ident);
David Tolnay7db73692019-10-20 14:51:12 -0400718 } else {
719 write!(out, "{}", arg.ident);
720 }
721 }
722 write!(out, ")");
723 match &efn.ret {
724 Some(Type::RustBox(_)) => write!(out, ".into_raw()"),
725 Some(Type::UniquePtr(_)) => write!(out, ".release()"),
David Tolnay73b72642020-11-25 17:44:05 -0800726 Some(Type::Str(_)) | Some(Type::SliceRef(_)) if !indirect_return => write!(out, ")"),
David Tolnay7db73692019-10-20 14:51:12 -0400727 _ => {}
728 }
729 if indirect_return {
730 write!(out, ")");
731 }
732 writeln!(out, ";");
David Tolnayebef4a22020-03-17 15:33:47 -0700733 if efn.throws {
734 out.include.cstring = true;
David Tolnay1f010c62020-11-01 20:27:46 -0800735 out.builtin.exception = true;
David Tolnay5d121442020-03-17 22:14:40 -0700736 writeln!(out, " throw$.ptr = nullptr;");
737 writeln!(out, " }},");
David Tolnay82c16172020-03-17 22:54:12 -0700738 writeln!(out, " [&](const char *catch$) noexcept {{");
David Tolnay5d121442020-03-17 22:14:40 -0700739 writeln!(out, " throw$.len = ::std::strlen(catch$);");
David Tolnayebef4a22020-03-17 15:33:47 -0700740 writeln!(
741 out,
David Tolnayc5629f02020-11-23 18:32:46 -0800742 " throw$.ptr = const_cast<char *>(::cxxbridge1$exception(catch$, throw$.len));",
David Tolnayebef4a22020-03-17 15:33:47 -0700743 );
David Tolnay5d121442020-03-17 22:14:40 -0700744 writeln!(out, " }});");
David Tolnayebef4a22020-03-17 15:33:47 -0700745 writeln!(out, " return throw$;");
746 }
David Tolnay7db73692019-10-20 14:51:12 -0400747 writeln!(out, "}}");
David Tolnay75dca2e2020-03-25 20:17:52 -0700748 for arg in &efn.args {
749 if let Type::Fn(f) = &arg.ty {
750 let var = &arg.ident;
David Tolnaya7c2ea12020-10-30 21:32:53 -0700751 write_function_pointer_trampoline(out, efn, var, f);
David Tolnay75dca2e2020-03-25 20:17:52 -0700752 }
753 }
David Tolnayca563ee2020-11-01 20:12:27 -0800754 out.end_block(Block::ExternC);
David Tolnay75dca2e2020-03-25 20:17:52 -0700755}
756
757fn write_function_pointer_trampoline(
758 out: &mut OutFile,
759 efn: &ExternFn,
760 var: &Ident,
761 f: &Signature,
David Tolnay75dca2e2020-03-25 20:17:52 -0700762) {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700763 let r_trampoline = mangle::r_trampoline(efn, var, out.types);
David Tolnay75dca2e2020-03-25 20:17:52 -0700764 let indirect_call = true;
David Tolnaya7c2ea12020-10-30 21:32:53 -0700765 write_rust_function_decl_impl(out, &r_trampoline, f, indirect_call);
David Tolnay75dca2e2020-03-25 20:17:52 -0700766
767 out.next_section();
David Tolnaya7c2ea12020-10-30 21:32:53 -0700768 let c_trampoline = mangle::c_trampoline(efn, var, out.types).to_string();
769 write_rust_function_shim_impl(out, &c_trampoline, f, &r_trampoline, indirect_call);
David Tolnay7db73692019-10-20 14:51:12 -0400770}
771
David Tolnay0b9b9f82020-11-01 20:41:00 -0800772fn write_rust_function_decl<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
David Tolnay17a934c2020-11-02 00:40:04 -0800773 out.set_namespace(&efn.name.namespace);
David Tolnayca563ee2020-11-01 20:12:27 -0800774 out.begin_block(Block::ExternC);
David Tolnaya7c2ea12020-10-30 21:32:53 -0700775 let link_name = mangle::extern_fn(efn, out.types);
David Tolnay75dca2e2020-03-25 20:17:52 -0700776 let indirect_call = false;
David Tolnaya7c2ea12020-10-30 21:32:53 -0700777 write_rust_function_decl_impl(out, &link_name, efn, indirect_call);
David Tolnayca563ee2020-11-01 20:12:27 -0800778 out.end_block(Block::ExternC);
David Tolnay75dca2e2020-03-25 20:17:52 -0700779}
780
781fn write_rust_function_decl_impl(
782 out: &mut OutFile,
David Tolnay891061b2020-04-19 22:42:33 -0700783 link_name: &Symbol,
David Tolnay75dca2e2020-03-25 20:17:52 -0700784 sig: &Signature,
David Tolnay75dca2e2020-03-25 20:17:52 -0700785 indirect_call: bool,
786) {
David Tolnay04770742020-11-01 13:50:50 -0800787 out.next_section();
David Tolnay75dca2e2020-03-25 20:17:52 -0700788 if sig.throws {
David Tolnay919085c2020-10-31 22:32:22 -0700789 out.builtin.ptr_len = true;
David Tolnayd68dfa82020-10-31 16:01:24 -0700790 write!(out, "::rust::repr::PtrLen ");
David Tolnay1e548172020-03-16 13:37:09 -0700791 } else {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700792 write_extern_return_type_space(out, &sig.ret);
David Tolnay1e548172020-03-16 13:37:09 -0700793 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700794 write!(out, "{}(", link_name);
795 let mut needs_comma = false;
David Tolnaye439c772020-04-20 00:23:55 -0700796 if let Some(receiver) = &sig.receiver {
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800797 if !receiver.mutable {
David Tolnay86710612020-04-20 00:30:32 -0700798 write!(out, "const ");
799 }
Adrian Taylorc8713432020-10-21 18:20:55 -0700800 write!(
801 out,
802 "{} &self",
David Tolnay8faec772020-11-02 00:18:19 -0800803 out.types.resolve(&receiver.ty).to_fully_qualified(),
Adrian Taylorc8713432020-10-21 18:20:55 -0700804 );
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700805 needs_comma = true;
806 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700807 for arg in &sig.args {
808 if needs_comma {
David Tolnay7db73692019-10-20 14:51:12 -0400809 write!(out, ", ");
810 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700811 write_extern_arg(out, arg);
David Tolnay75dca2e2020-03-25 20:17:52 -0700812 needs_comma = true;
David Tolnay7db73692019-10-20 14:51:12 -0400813 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700814 if indirect_return(sig, out.types) {
David Tolnay75dca2e2020-03-25 20:17:52 -0700815 if needs_comma {
David Tolnay7db73692019-10-20 14:51:12 -0400816 write!(out, ", ");
817 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700818 write_return_type(out, &sig.ret);
David Tolnay7db73692019-10-20 14:51:12 -0400819 write!(out, "*return$");
David Tolnay75dca2e2020-03-25 20:17:52 -0700820 needs_comma = true;
821 }
822 if indirect_call {
823 if needs_comma {
824 write!(out, ", ");
825 }
826 write!(out, "void *");
David Tolnay7db73692019-10-20 14:51:12 -0400827 }
828 writeln!(out, ") noexcept;");
829}
830
David Tolnay0b9b9f82020-11-01 20:41:00 -0800831fn write_rust_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
David Tolnay17a934c2020-11-02 00:40:04 -0800832 out.set_namespace(&efn.name.namespace);
David Tolnay7db73692019-10-20 14:51:12 -0400833 for line in efn.doc.to_string().lines() {
834 writeln!(out, "//{}", line);
835 }
David Tolnaya73853b2020-04-20 01:19:56 -0700836 let local_name = match &efn.sig.receiver {
David Tolnay17a934c2020-11-02 00:40:04 -0800837 None => efn.name.cxx.to_string(),
838 Some(receiver) => format!("{}::{}", out.types.resolve(&receiver.ty).cxx, efn.name.cxx),
David Tolnaya73853b2020-04-20 01:19:56 -0700839 };
David Tolnaya7c2ea12020-10-30 21:32:53 -0700840 let invoke = mangle::extern_fn(efn, out.types);
David Tolnay75dca2e2020-03-25 20:17:52 -0700841 let indirect_call = false;
David Tolnaya7c2ea12020-10-30 21:32:53 -0700842 write_rust_function_shim_impl(out, &local_name, efn, &invoke, indirect_call);
David Tolnay75dca2e2020-03-25 20:17:52 -0700843}
844
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700845fn write_rust_function_shim_decl(
David Tolnay75dca2e2020-03-25 20:17:52 -0700846 out: &mut OutFile,
David Tolnaya73853b2020-04-20 01:19:56 -0700847 local_name: &str,
David Tolnay75dca2e2020-03-25 20:17:52 -0700848 sig: &Signature,
David Tolnay75dca2e2020-03-25 20:17:52 -0700849 indirect_call: bool,
850) {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700851 write_return_type(out, &sig.ret);
David Tolnay75dca2e2020-03-25 20:17:52 -0700852 write!(out, "{}(", local_name);
853 for (i, arg) in sig.args.iter().enumerate() {
David Tolnay7db73692019-10-20 14:51:12 -0400854 if i > 0 {
855 write!(out, ", ");
856 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700857 write_type_space(out, &arg.ty);
David Tolnay7db73692019-10-20 14:51:12 -0400858 write!(out, "{}", arg.ident);
859 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700860 if indirect_call {
861 if !sig.args.is_empty() {
862 write!(out, ", ");
863 }
864 write!(out, "void *extern$");
865 }
David Tolnay1e548172020-03-16 13:37:09 -0700866 write!(out, ")");
David Tolnay86710612020-04-20 00:30:32 -0700867 if let Some(receiver) = &sig.receiver {
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800868 if !receiver.mutable {
David Tolnay86710612020-04-20 00:30:32 -0700869 write!(out, " const");
870 }
871 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700872 if !sig.throws {
David Tolnay1e548172020-03-16 13:37:09 -0700873 write!(out, " noexcept");
874 }
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700875}
876
877fn write_rust_function_shim_impl(
878 out: &mut OutFile,
David Tolnaya73853b2020-04-20 01:19:56 -0700879 local_name: &str,
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700880 sig: &Signature,
David Tolnay891061b2020-04-19 22:42:33 -0700881 invoke: &Symbol,
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700882 indirect_call: bool,
883) {
884 if out.header && sig.receiver.is_some() {
885 // We've already defined this inside the struct.
886 return;
887 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700888 write_rust_function_shim_decl(out, local_name, sig, indirect_call);
David Tolnay7db73692019-10-20 14:51:12 -0400889 if out.header {
890 writeln!(out, ";");
David Tolnay439cde22020-04-20 00:46:25 -0700891 return;
David Tolnay7db73692019-10-20 14:51:12 -0400892 }
David Tolnay439cde22020-04-20 00:46:25 -0700893 writeln!(out, " {{");
894 for arg in &sig.args {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700895 if arg.ty != RustString && out.types.needs_indirect_abi(&arg.ty) {
David Tolnay439cde22020-04-20 00:46:25 -0700896 out.include.utility = true;
David Tolnay74d6d512020-10-31 22:22:03 -0700897 out.builtin.manually_drop = true;
David Tolnay439cde22020-04-20 00:46:25 -0700898 write!(out, " ::rust::ManuallyDrop<");
David Tolnaya7c2ea12020-10-30 21:32:53 -0700899 write_type(out, &arg.ty);
David Tolnay439cde22020-04-20 00:46:25 -0700900 writeln!(out, "> {}$(::std::move({0}));", arg.ident);
901 }
902 }
903 write!(out, " ");
David Tolnaya7c2ea12020-10-30 21:32:53 -0700904 let indirect_return = indirect_return(sig, out.types);
David Tolnay439cde22020-04-20 00:46:25 -0700905 if indirect_return {
David Tolnay74d6d512020-10-31 22:22:03 -0700906 out.builtin.maybe_uninit = true;
David Tolnay439cde22020-04-20 00:46:25 -0700907 write!(out, "::rust::MaybeUninit<");
David Tolnaya7c2ea12020-10-30 21:32:53 -0700908 write_type(out, sig.ret.as_ref().unwrap());
David Tolnay439cde22020-04-20 00:46:25 -0700909 writeln!(out, "> return$;");
910 write!(out, " ");
911 } else if let Some(ret) = &sig.ret {
912 write!(out, "return ");
913 match ret {
914 Type::RustBox(_) => {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700915 write_type(out, ret);
David Tolnay439cde22020-04-20 00:46:25 -0700916 write!(out, "::from_raw(");
917 }
918 Type::UniquePtr(_) => {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700919 write_type(out, ret);
David Tolnay439cde22020-04-20 00:46:25 -0700920 write!(out, "(");
921 }
922 Type::Ref(_) => write!(out, "*"),
David Tolnay74d6d512020-10-31 22:22:03 -0700923 Type::Str(_) => {
924 out.builtin.rust_str_new_unchecked = true;
925 write!(out, "::rust::impl<::rust::Str>::new_unchecked(");
926 }
David Tolnay73b72642020-11-25 17:44:05 -0800927 Type::SliceRef(_) => {
David Tolnay36aa9e02020-10-31 23:08:21 -0700928 out.builtin.rust_slice_new = true;
David Tolnayc5629f02020-11-23 18:32:46 -0800929 write!(out, "::rust::impl<");
930 write_type(out, ret);
931 write!(out, ">::slice(");
David Tolnay36aa9e02020-10-31 23:08:21 -0700932 }
David Tolnay439cde22020-04-20 00:46:25 -0700933 _ => {}
934 }
935 }
936 if sig.throws {
David Tolnay919085c2020-10-31 22:32:22 -0700937 out.builtin.ptr_len = true;
David Tolnayd68dfa82020-10-31 16:01:24 -0700938 write!(out, "::rust::repr::PtrLen error$ = ");
David Tolnay439cde22020-04-20 00:46:25 -0700939 }
940 write!(out, "{}(", invoke);
David Tolnay9d840362020-11-10 08:50:40 -0800941 let mut needs_comma = false;
David Tolnay439cde22020-04-20 00:46:25 -0700942 if sig.receiver.is_some() {
943 write!(out, "*this");
David Tolnay9d840362020-11-10 08:50:40 -0800944 needs_comma = true;
David Tolnay439cde22020-04-20 00:46:25 -0700945 }
David Tolnay9d840362020-11-10 08:50:40 -0800946 for arg in &sig.args {
947 if needs_comma {
David Tolnay439cde22020-04-20 00:46:25 -0700948 write!(out, ", ");
949 }
950 match &arg.ty {
David Tolnay74d6d512020-10-31 22:22:03 -0700951 Type::Str(_) => {
952 out.builtin.rust_str_repr = true;
953 write!(out, "::rust::impl<::rust::Str>::repr(");
954 }
David Tolnay73b72642020-11-25 17:44:05 -0800955 Type::SliceRef(_) => {
David Tolnay36aa9e02020-10-31 23:08:21 -0700956 out.builtin.rust_slice_repr = true;
David Tolnayc5629f02020-11-23 18:32:46 -0800957 write!(out, "::rust::impl<");
958 write_type(out, &arg.ty);
959 write!(out, ">::repr(");
David Tolnay36aa9e02020-10-31 23:08:21 -0700960 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700961 ty if out.types.needs_indirect_abi(ty) => write!(out, "&"),
David Tolnay439cde22020-04-20 00:46:25 -0700962 _ => {}
963 }
964 write!(out, "{}", arg.ident);
965 match &arg.ty {
966 Type::RustBox(_) => write!(out, ".into_raw()"),
967 Type::UniquePtr(_) => write!(out, ".release()"),
David Tolnay73b72642020-11-25 17:44:05 -0800968 Type::Str(_) | Type::SliceRef(_) => write!(out, ")"),
David Tolnaya7c2ea12020-10-30 21:32:53 -0700969 ty if ty != RustString && out.types.needs_indirect_abi(ty) => write!(out, "$.value"),
David Tolnay439cde22020-04-20 00:46:25 -0700970 _ => {}
971 }
David Tolnay9d840362020-11-10 08:50:40 -0800972 needs_comma = true;
David Tolnay439cde22020-04-20 00:46:25 -0700973 }
974 if indirect_return {
David Tolnay9d840362020-11-10 08:50:40 -0800975 if needs_comma {
David Tolnay439cde22020-04-20 00:46:25 -0700976 write!(out, ", ");
977 }
978 write!(out, "&return$.value");
David Tolnay9d840362020-11-10 08:50:40 -0800979 needs_comma = true;
David Tolnay439cde22020-04-20 00:46:25 -0700980 }
981 if indirect_call {
David Tolnay9d840362020-11-10 08:50:40 -0800982 if needs_comma {
David Tolnay439cde22020-04-20 00:46:25 -0700983 write!(out, ", ");
984 }
985 write!(out, "extern$");
986 }
987 write!(out, ")");
David Tolnay22602b42020-09-21 18:04:05 -0400988 if !indirect_return {
989 if let Some(ret) = &sig.ret {
David Tolnay73b72642020-11-25 17:44:05 -0800990 if let Type::RustBox(_) | Type::UniquePtr(_) | Type::Str(_) | Type::SliceRef(_) = ret {
David Tolnay22602b42020-09-21 18:04:05 -0400991 write!(out, ")");
992 }
David Tolnay439cde22020-04-20 00:46:25 -0700993 }
994 }
995 writeln!(out, ";");
996 if sig.throws {
David Tolnay74d6d512020-10-31 22:22:03 -0700997 out.builtin.rust_error = true;
David Tolnayd68dfa82020-10-31 16:01:24 -0700998 writeln!(out, " if (error$.ptr) {{");
David Tolnay84ddf9e2020-10-31 15:36:48 -0700999 writeln!(out, " throw ::rust::impl<::rust::Error>::error(error$);");
David Tolnay439cde22020-04-20 00:46:25 -07001000 writeln!(out, " }}");
1001 }
1002 if indirect_return {
1003 out.include.utility = true;
1004 writeln!(out, " return ::std::move(return$.value);");
1005 }
1006 writeln!(out, "}}");
David Tolnay7db73692019-10-20 14:51:12 -04001007}
1008
David Tolnaya7c2ea12020-10-30 21:32:53 -07001009fn write_return_type(out: &mut OutFile, ty: &Option<Type>) {
David Tolnay7db73692019-10-20 14:51:12 -04001010 match ty {
1011 None => write!(out, "void "),
David Tolnaya7c2ea12020-10-30 21:32:53 -07001012 Some(ty) => write_type_space(out, ty),
David Tolnay7db73692019-10-20 14:51:12 -04001013 }
1014}
1015
David Tolnay75dca2e2020-03-25 20:17:52 -07001016fn indirect_return(sig: &Signature, types: &Types) -> bool {
1017 sig.ret
David Tolnay277e3cc2020-03-17 00:11:01 -07001018 .as_ref()
David Tolnay75dca2e2020-03-25 20:17:52 -07001019 .map_or(false, |ret| sig.throws || types.needs_indirect_abi(ret))
David Tolnay277e3cc2020-03-17 00:11:01 -07001020}
1021
David Tolnaya7c2ea12020-10-30 21:32:53 -07001022fn write_indirect_return_type(out: &mut OutFile, ty: &Type) {
David Tolnay99642622020-03-25 13:07:35 -07001023 match ty {
1024 Type::RustBox(ty) | Type::UniquePtr(ty) => {
David Tolnaya7c2ea12020-10-30 21:32:53 -07001025 write_type_space(out, &ty.inner);
David Tolnay99642622020-03-25 13:07:35 -07001026 write!(out, "*");
1027 }
1028 Type::Ref(ty) => {
David Tolnay9c4ac2e2020-11-15 21:14:03 -08001029 if !ty.mutable {
David Tolnay99642622020-03-25 13:07:35 -07001030 write!(out, "const ");
1031 }
David Tolnaya7c2ea12020-10-30 21:32:53 -07001032 write_type(out, &ty.inner);
David Tolnay99642622020-03-25 13:07:35 -07001033 write!(out, " *");
1034 }
David Tolnaya7c2ea12020-10-30 21:32:53 -07001035 _ => write_type(out, ty),
David Tolnay99642622020-03-25 13:07:35 -07001036 }
1037}
1038
David Tolnaya7c2ea12020-10-30 21:32:53 -07001039fn write_indirect_return_type_space(out: &mut OutFile, ty: &Type) {
1040 write_indirect_return_type(out, ty);
David Tolnay99642622020-03-25 13:07:35 -07001041 match ty {
1042 Type::RustBox(_) | Type::UniquePtr(_) | Type::Ref(_) => {}
David Tolnay73b72642020-11-25 17:44:05 -08001043 Type::Str(_) | Type::SliceRef(_) => write!(out, " "),
David Tolnay99642622020-03-25 13:07:35 -07001044 _ => write_space_after_type(out, ty),
1045 }
1046}
1047
David Tolnaya7c2ea12020-10-30 21:32:53 -07001048fn write_extern_return_type_space(out: &mut OutFile, ty: &Option<Type>) {
David Tolnay7db73692019-10-20 14:51:12 -04001049 match ty {
1050 Some(Type::RustBox(ty)) | Some(Type::UniquePtr(ty)) => {
David Tolnaya7c2ea12020-10-30 21:32:53 -07001051 write_type_space(out, &ty.inner);
David Tolnay7db73692019-10-20 14:51:12 -04001052 write!(out, "*");
1053 }
David Tolnay4a441222020-01-25 16:24:27 -08001054 Some(Type::Ref(ty)) => {
David Tolnay9c4ac2e2020-11-15 21:14:03 -08001055 if !ty.mutable {
David Tolnay4a441222020-01-25 16:24:27 -08001056 write!(out, "const ");
1057 }
David Tolnaya7c2ea12020-10-30 21:32:53 -07001058 write_type(out, &ty.inner);
David Tolnay4a441222020-01-25 16:24:27 -08001059 write!(out, " *");
1060 }
David Tolnay73b72642020-11-25 17:44:05 -08001061 Some(Type::Str(_)) | Some(Type::SliceRef(_)) => {
David Tolnay919085c2020-10-31 22:32:22 -07001062 out.builtin.ptr_len = true;
1063 write!(out, "::rust::repr::PtrLen ");
1064 }
David Tolnaya7c2ea12020-10-30 21:32:53 -07001065 Some(ty) if out.types.needs_indirect_abi(ty) => write!(out, "void "),
1066 _ => write_return_type(out, ty),
David Tolnay7db73692019-10-20 14:51:12 -04001067 }
1068}
1069
David Tolnaya7c2ea12020-10-30 21:32:53 -07001070fn write_extern_arg(out: &mut OutFile, arg: &Var) {
David Tolnay7db73692019-10-20 14:51:12 -04001071 match &arg.ty {
David Tolnay4377a9e2020-04-24 15:20:26 -07001072 Type::RustBox(ty) | Type::UniquePtr(ty) | Type::CxxVector(ty) => {
David Tolnaya7c2ea12020-10-30 21:32:53 -07001073 write_type_space(out, &ty.inner);
David Tolnay7db73692019-10-20 14:51:12 -04001074 write!(out, "*");
1075 }
David Tolnay73b72642020-11-25 17:44:05 -08001076 Type::Str(_) | Type::SliceRef(_) => {
David Tolnay919085c2020-10-31 22:32:22 -07001077 out.builtin.ptr_len = true;
1078 write!(out, "::rust::repr::PtrLen ");
1079 }
David Tolnaya7c2ea12020-10-30 21:32:53 -07001080 _ => write_type_space(out, &arg.ty),
David Tolnay7db73692019-10-20 14:51:12 -04001081 }
David Tolnaya7c2ea12020-10-30 21:32:53 -07001082 if out.types.needs_indirect_abi(&arg.ty) {
David Tolnay7db73692019-10-20 14:51:12 -04001083 write!(out, "*");
1084 }
1085 write!(out, "{}", arg.ident);
1086}
1087
David Tolnaya7c2ea12020-10-30 21:32:53 -07001088fn write_type(out: &mut OutFile, ty: &Type) {
David Tolnay7db73692019-10-20 14:51:12 -04001089 match ty {
Adrian Taylorc8713432020-10-21 18:20:55 -07001090 Type::Ident(ident) => match Atom::from(&ident.rust) {
David Tolnayf6a89f22020-05-10 23:39:27 -07001091 Some(atom) => write_atom(out, atom),
David Tolnaya7c2ea12020-10-30 21:32:53 -07001092 None => write!(out, "{}", out.types.resolve(ident).to_fully_qualified()),
David Tolnay7db73692019-10-20 14:51:12 -04001093 },
1094 Type::RustBox(ty) => {
David Tolnay750755e2020-03-01 13:04:08 -08001095 write!(out, "::rust::Box<");
David Tolnaya7c2ea12020-10-30 21:32:53 -07001096 write_type(out, &ty.inner);
David Tolnay7db73692019-10-20 14:51:12 -04001097 write!(out, ">");
1098 }
Myron Ahneba35cf2020-02-05 19:41:51 +07001099 Type::RustVec(ty) => {
1100 write!(out, "::rust::Vec<");
David Tolnaya7c2ea12020-10-30 21:32:53 -07001101 write_type(out, &ty.inner);
Myron Ahneba35cf2020-02-05 19:41:51 +07001102 write!(out, ">");
1103 }
David Tolnay7db73692019-10-20 14:51:12 -04001104 Type::UniquePtr(ptr) => {
David Tolnay7e219b82020-03-01 13:14:51 -08001105 write!(out, "::std::unique_ptr<");
David Tolnaya7c2ea12020-10-30 21:32:53 -07001106 write_type(out, &ptr.inner);
David Tolnay7db73692019-10-20 14:51:12 -04001107 write!(out, ">");
1108 }
David Tolnayb3b24a12020-12-01 15:27:43 -08001109 Type::SharedPtr(ptr) => {
1110 write!(out, "::std::shared_ptr<");
1111 write_type(out, &ptr.inner);
1112 write!(out, ">");
1113 }
David Tolnay4377a9e2020-04-24 15:20:26 -07001114 Type::CxxVector(ty) => {
Myron Ahneba35cf2020-02-05 19:41:51 +07001115 write!(out, "::std::vector<");
David Tolnaya7c2ea12020-10-30 21:32:53 -07001116 write_type(out, &ty.inner);
Myron Ahneba35cf2020-02-05 19:41:51 +07001117 write!(out, ">");
1118 }
David Tolnay7db73692019-10-20 14:51:12 -04001119 Type::Ref(r) => {
David Tolnay9c4ac2e2020-11-15 21:14:03 -08001120 if !r.mutable {
David Tolnay7db73692019-10-20 14:51:12 -04001121 write!(out, "const ");
1122 }
David Tolnaya7c2ea12020-10-30 21:32:53 -07001123 write_type(out, &r.inner);
David Tolnay7db73692019-10-20 14:51:12 -04001124 write!(out, " &");
1125 }
1126 Type::Str(_) => {
David Tolnay750755e2020-03-01 13:04:08 -08001127 write!(out, "::rust::Str");
David Tolnay7db73692019-10-20 14:51:12 -04001128 }
David Tolnay5515a9e2020-11-25 19:07:54 -08001129 Type::SliceRef(slice) => {
David Tolnayc5629f02020-11-23 18:32:46 -08001130 write!(out, "::rust::Slice<");
David Tolnay5515a9e2020-11-25 19:07:54 -08001131 if slice.mutability.is_none() {
David Tolnayc5629f02020-11-23 18:32:46 -08001132 write!(out, "const ");
1133 }
David Tolnay5515a9e2020-11-25 19:07:54 -08001134 write_type(out, &slice.inner);
1135 write!(out, ">");
Adrian Taylorf5dd5522020-04-13 16:50:14 -07001136 }
David Tolnay75dca2e2020-03-25 20:17:52 -07001137 Type::Fn(f) => {
David Tolnayf031c322020-11-29 19:41:33 -08001138 write!(out, "::rust::Fn<");
David Tolnay75dca2e2020-03-25 20:17:52 -07001139 match &f.ret {
David Tolnaya7c2ea12020-10-30 21:32:53 -07001140 Some(ret) => write_type(out, ret),
David Tolnay75dca2e2020-03-25 20:17:52 -07001141 None => write!(out, "void"),
1142 }
1143 write!(out, "(");
1144 for (i, arg) in f.args.iter().enumerate() {
1145 if i > 0 {
1146 write!(out, ", ");
1147 }
David Tolnaya7c2ea12020-10-30 21:32:53 -07001148 write_type(out, &arg.ty);
David Tolnay75dca2e2020-03-25 20:17:52 -07001149 }
1150 write!(out, ")>");
1151 }
Xiangpeng Hao78762352020-11-12 10:24:18 +08001152 Type::Array(a) => {
1153 write!(out, "::std::array<");
1154 write_type(out, &a.inner);
1155 write!(out, ", {}>", &a.len);
1156 }
David Tolnay2fb14e92020-03-15 23:11:38 -07001157 Type::Void(_) => unreachable!(),
David Tolnay7db73692019-10-20 14:51:12 -04001158 }
1159}
1160
David Tolnayf6a89f22020-05-10 23:39:27 -07001161fn write_atom(out: &mut OutFile, atom: Atom) {
1162 match atom {
1163 Bool => write!(out, "bool"),
David Tolnayb3873dc2020-11-25 19:47:49 -08001164 Char => write!(out, "char"),
David Tolnayf6a89f22020-05-10 23:39:27 -07001165 U8 => write!(out, "uint8_t"),
1166 U16 => write!(out, "uint16_t"),
1167 U32 => write!(out, "uint32_t"),
1168 U64 => write!(out, "uint64_t"),
1169 Usize => write!(out, "size_t"),
1170 I8 => write!(out, "int8_t"),
1171 I16 => write!(out, "int16_t"),
1172 I32 => write!(out, "int32_t"),
1173 I64 => write!(out, "int64_t"),
1174 Isize => write!(out, "::rust::isize"),
1175 F32 => write!(out, "float"),
1176 F64 => write!(out, "double"),
1177 CxxString => write!(out, "::std::string"),
1178 RustString => write!(out, "::rust::String"),
1179 }
1180}
1181
David Tolnaya7c2ea12020-10-30 21:32:53 -07001182fn write_type_space(out: &mut OutFile, ty: &Type) {
1183 write_type(out, ty);
David Tolnay99642622020-03-25 13:07:35 -07001184 write_space_after_type(out, ty);
1185}
1186
1187fn write_space_after_type(out: &mut OutFile, ty: &Type) {
David Tolnay7db73692019-10-20 14:51:12 -04001188 match ty {
David Tolnayeb952ba2020-04-14 15:02:24 -07001189 Type::Ident(_)
1190 | Type::RustBox(_)
1191 | Type::UniquePtr(_)
David Tolnayb3b24a12020-12-01 15:27:43 -08001192 | Type::SharedPtr(_)
David Tolnayeb952ba2020-04-14 15:02:24 -07001193 | Type::Str(_)
David Tolnay4377a9e2020-04-24 15:20:26 -07001194 | Type::CxxVector(_)
Myron Ahneba35cf2020-02-05 19:41:51 +07001195 | Type::RustVec(_)
David Tolnay73b72642020-11-25 17:44:05 -08001196 | Type::SliceRef(_)
Xiangpeng Hao78762352020-11-12 10:24:18 +08001197 | Type::Fn(_)
1198 | Type::Array(_) => write!(out, " "),
David Tolnay7db73692019-10-20 14:51:12 -04001199 Type::Ref(_) => {}
David Tolnaye0dca7b2020-11-25 17:18:57 -08001200 Type::Void(_) => unreachable!(),
David Tolnay7db73692019-10-20 14:51:12 -04001201 }
1202}
1203
David Tolnay1bdb4712020-11-25 07:27:54 -08001204#[derive(Copy, Clone)]
1205enum UniquePtr<'a> {
David Tolnay75ea17c2020-12-06 21:08:34 -08001206 Ident(&'a RustName),
1207 CxxVector(&'a RustName),
David Tolnay1bdb4712020-11-25 07:27:54 -08001208}
1209
1210trait ToTypename {
1211 fn to_typename(&self, types: &Types) -> String;
1212}
1213
David Tolnay75ea17c2020-12-06 21:08:34 -08001214impl ToTypename for RustName {
David Tolnay1bdb4712020-11-25 07:27:54 -08001215 fn to_typename(&self, types: &Types) -> String {
1216 types.resolve(self).to_fully_qualified()
David Tolnay2eca4a02020-04-24 19:50:51 -07001217 }
1218}
1219
David Tolnay1bdb4712020-11-25 07:27:54 -08001220impl<'a> ToTypename for UniquePtr<'a> {
1221 fn to_typename(&self, types: &Types) -> String {
1222 match self {
1223 UniquePtr::Ident(ident) => ident.to_typename(types),
1224 UniquePtr::CxxVector(element) => {
1225 format!("::std::vector<{}>", element.to_typename(types))
1226 }
1227 }
1228 }
1229}
1230
1231trait ToMangled {
1232 fn to_mangled(&self, types: &Types) -> Symbol;
1233}
1234
David Tolnay75ea17c2020-12-06 21:08:34 -08001235impl ToMangled for RustName {
David Tolnay1bdb4712020-11-25 07:27:54 -08001236 fn to_mangled(&self, types: &Types) -> Symbol {
1237 self.to_symbol(types)
1238 }
1239}
1240
1241impl<'a> ToMangled for UniquePtr<'a> {
1242 fn to_mangled(&self, types: &Types) -> Symbol {
1243 match self {
1244 UniquePtr::Ident(ident) => ident.to_mangled(types),
1245 UniquePtr::CxxVector(element) => element.to_mangled(types).prefix_with("std$vector$"),
1246 }
David Tolnaybae50ef2020-04-25 12:38:41 -07001247 }
1248}
1249
David Tolnaya7c2ea12020-10-30 21:32:53 -07001250fn write_generic_instantiations(out: &mut OutFile) {
David Tolnay169bb472020-11-01 21:04:24 -08001251 if out.header {
1252 return;
1253 }
1254
1255 out.next_section();
David Tolnay078c90f2020-11-01 13:31:08 -08001256 out.set_namespace(Default::default());
David Tolnay0c033e32020-11-01 15:15:48 -08001257 out.begin_block(Block::ExternC);
David Tolnaya7c2ea12020-10-30 21:32:53 -07001258 for ty in out.types {
David Tolnayf33bc242020-12-04 18:27:02 -08001259 if let Type::RustBox(ptr) = ty {
1260 if let Type::Ident(inner) = &ptr.inner {
1261 if Atom::from(&inner.rust).is_none()
1262 && (!out.types.aliases.contains_key(&inner.rust)
1263 || out.types.explicit_impls.contains(ty))
1264 {
1265 out.next_section();
1266 write_rust_box_extern(out, &out.types.resolve(&inner));
1267 }
David Tolnay7db73692019-10-20 14:51:12 -04001268 }
David Tolnayf33bc242020-12-04 18:27:02 -08001269 } else if let Type::RustVec(vec) = ty {
1270 if let Type::Ident(inner) = &vec.inner {
1271 if Atom::from(&inner.rust).is_none()
1272 && (!out.types.aliases.contains_key(&inner.rust)
1273 || out.types.explicit_impls.contains(ty))
1274 {
David Tolnay6787be62020-04-25 11:01:02 -07001275 out.next_section();
David Tolnaya7c2ea12020-10-30 21:32:53 -07001276 write_rust_vec_extern(out, inner);
David Tolnay6787be62020-04-25 11:01:02 -07001277 }
Myron Ahneba35cf2020-02-05 19:41:51 +07001278 }
David Tolnay7db73692019-10-20 14:51:12 -04001279 } else if let Type::UniquePtr(ptr) = ty {
1280 if let Type::Ident(inner) = &ptr.inner {
Adrian Taylorc8713432020-10-21 18:20:55 -07001281 if Atom::from(&inner.rust).is_none()
David Tolnaya7c2ea12020-10-30 21:32:53 -07001282 && (!out.types.aliases.contains_key(&inner.rust)
1283 || out.types.explicit_impls.contains(ty))
David Tolnay7e69f892020-10-03 22:20:22 -07001284 {
David Tolnay7db73692019-10-20 14:51:12 -04001285 out.next_section();
David Tolnaya7c2ea12020-10-30 21:32:53 -07001286 write_unique_ptr(out, inner);
Myron Ahneba35cf2020-02-05 19:41:51 +07001287 }
1288 }
David Tolnayb3b24a12020-12-01 15:27:43 -08001289 } else if let Type::SharedPtr(ptr) = ty {
1290 if let Type::Ident(inner) = &ptr.inner {
1291 if Atom::from(&inner.rust).is_none()
David Tolnayb7453812020-12-01 21:46:55 -08001292 && (!out.types.aliases.contains_key(&inner.rust)
David Tolnayb3b24a12020-12-01 15:27:43 -08001293 || out.types.explicit_impls.contains(ty))
1294 {
1295 out.next_section();
1296 write_shared_ptr(out, inner);
1297 }
1298 }
David Tolnayf33bc242020-12-04 18:27:02 -08001299 } else if let Type::CxxVector(vector) = ty {
1300 if let Type::Ident(inner) = &vector.inner {
Adrian Taylorc8713432020-10-21 18:20:55 -07001301 if Atom::from(&inner.rust).is_none()
David Tolnaya7c2ea12020-10-30 21:32:53 -07001302 && (!out.types.aliases.contains_key(&inner.rust)
1303 || out.types.explicit_impls.contains(ty))
David Tolnay7e69f892020-10-03 22:20:22 -07001304 {
Myron Ahneba35cf2020-02-05 19:41:51 +07001305 out.next_section();
David Tolnay1bdb4712020-11-25 07:27:54 -08001306 write_cxx_vector(out, inner);
David Tolnay7db73692019-10-20 14:51:12 -04001307 }
1308 }
1309 }
1310 }
David Tolnay0c033e32020-11-01 15:15:48 -08001311 out.end_block(Block::ExternC);
David Tolnay7db73692019-10-20 14:51:12 -04001312
David Tolnay0c033e32020-11-01 15:15:48 -08001313 out.begin_block(Block::Namespace("rust"));
David Tolnay0f0162f2020-11-16 23:43:37 -08001314 out.begin_block(Block::InlineNamespace("cxxbridge1"));
David Tolnaya7c2ea12020-10-30 21:32:53 -07001315 for ty in out.types {
David Tolnayf33bc242020-12-04 18:27:02 -08001316 if let Type::RustBox(ptr) = ty {
1317 if let Type::Ident(inner) = &ptr.inner {
1318 if Atom::from(&inner.rust).is_none()
1319 && (!out.types.aliases.contains_key(&inner.rust)
1320 || out.types.explicit_impls.contains(ty))
1321 {
1322 write_rust_box_impl(out, &out.types.resolve(&inner));
1323 }
David Tolnay7db73692019-10-20 14:51:12 -04001324 }
David Tolnayf33bc242020-12-04 18:27:02 -08001325 } else if let Type::RustVec(vec) = ty {
1326 if let Type::Ident(inner) = &vec.inner {
1327 if Atom::from(&inner.rust).is_none()
1328 && (!out.types.aliases.contains_key(&inner.rust)
1329 || out.types.explicit_impls.contains(ty))
1330 {
David Tolnaya7c2ea12020-10-30 21:32:53 -07001331 write_rust_vec_impl(out, inner);
David Tolnay6787be62020-04-25 11:01:02 -07001332 }
Myron Ahneba35cf2020-02-05 19:41:51 +07001333 }
David Tolnay7db73692019-10-20 14:51:12 -04001334 }
1335 }
David Tolnay0f0162f2020-11-16 23:43:37 -08001336 out.end_block(Block::InlineNamespace("cxxbridge1"));
David Tolnay0c033e32020-11-01 15:15:48 -08001337 out.end_block(Block::Namespace("rust"));
David Tolnay7db73692019-10-20 14:51:12 -04001338}
1339
David Tolnay8faec772020-11-02 00:18:19 -08001340fn write_rust_box_extern(out: &mut OutFile, ident: &Pair) {
Adrian Taylorc8713432020-10-21 18:20:55 -07001341 let inner = ident.to_fully_qualified();
1342 let instance = ident.to_symbol();
David Tolnay7db73692019-10-20 14:51:12 -04001343
David Tolnay0f0162f2020-11-16 23:43:37 -08001344 writeln!(out, "#ifndef CXXBRIDGE1_RUST_BOX_{}", instance);
1345 writeln!(out, "#define CXXBRIDGE1_RUST_BOX_{}", instance);
David Tolnay7db73692019-10-20 14:51:12 -04001346 writeln!(
1347 out,
David Tolnay0f0162f2020-11-16 23:43:37 -08001348 "void cxxbridge1$box${}$uninit(::rust::Box<{}> *ptr) noexcept;",
David Tolnay7db73692019-10-20 14:51:12 -04001349 instance, inner,
1350 );
1351 writeln!(
1352 out,
David Tolnay0f0162f2020-11-16 23:43:37 -08001353 "void cxxbridge1$box${}$drop(::rust::Box<{}> *ptr) noexcept;",
David Tolnay7db73692019-10-20 14:51:12 -04001354 instance, inner,
1355 );
David Tolnay0f0162f2020-11-16 23:43:37 -08001356 writeln!(out, "#endif // CXXBRIDGE1_RUST_BOX_{}", instance);
David Tolnay7db73692019-10-20 14:51:12 -04001357}
1358
David Tolnay75ea17c2020-12-06 21:08:34 -08001359fn write_rust_vec_extern(out: &mut OutFile, element: &RustName) {
David Tolnay1bdb4712020-11-25 07:27:54 -08001360 let inner = element.to_typename(out.types);
1361 let instance = element.to_mangled(out.types);
Myron Ahneba35cf2020-02-05 19:41:51 +07001362
David Tolnay0f0162f2020-11-16 23:43:37 -08001363 writeln!(out, "#ifndef CXXBRIDGE1_RUST_VEC_{}", instance);
1364 writeln!(out, "#define CXXBRIDGE1_RUST_VEC_{}", instance);
Myron Ahneba35cf2020-02-05 19:41:51 +07001365 writeln!(
1366 out,
David Tolnay0f0162f2020-11-16 23:43:37 -08001367 "void cxxbridge1$rust_vec${}$new(const ::rust::Vec<{}> *ptr) noexcept;",
David Tolnayf97c2d52020-04-25 16:37:48 -07001368 instance, inner,
1369 );
1370 writeln!(
1371 out,
David Tolnay0f0162f2020-11-16 23:43:37 -08001372 "void cxxbridge1$rust_vec${}$drop(::rust::Vec<{}> *ptr) noexcept;",
Myron Ahneba35cf2020-02-05 19:41:51 +07001373 instance, inner,
1374 );
1375 writeln!(
1376 out,
David Tolnay0f0162f2020-11-16 23:43:37 -08001377 "size_t cxxbridge1$rust_vec${}$len(const ::rust::Vec<{}> *ptr) noexcept;",
Myron Ahneba35cf2020-02-05 19:41:51 +07001378 instance, inner,
1379 );
David Tolnay219c0792020-04-24 20:31:37 -07001380 writeln!(
1381 out,
David Tolnay0f0162f2020-11-16 23:43:37 -08001382 "const {} *cxxbridge1$rust_vec${}$data(const ::rust::Vec<{0}> *ptr) noexcept;",
David Tolnay219c0792020-04-24 20:31:37 -07001383 inner, instance,
1384 );
David Tolnay503d0192020-04-24 22:18:56 -07001385 writeln!(
1386 out,
David Tolnay0f0162f2020-11-16 23:43:37 -08001387 "void cxxbridge1$rust_vec${}$reserve_total(::rust::Vec<{}> *ptr, size_t cap) noexcept;",
David Tolnayfb6b73c2020-11-10 14:32:16 -08001388 instance, inner,
1389 );
1390 writeln!(
1391 out,
David Tolnay0f0162f2020-11-16 23:43:37 -08001392 "void cxxbridge1$rust_vec${}$set_len(::rust::Vec<{}> *ptr, size_t len) noexcept;",
David Tolnayfb6b73c2020-11-10 14:32:16 -08001393 instance, inner,
1394 );
1395 writeln!(
1396 out,
David Tolnay0f0162f2020-11-16 23:43:37 -08001397 "size_t cxxbridge1$rust_vec${}$stride() noexcept;",
David Tolnay503d0192020-04-24 22:18:56 -07001398 instance,
1399 );
David Tolnay0f0162f2020-11-16 23:43:37 -08001400 writeln!(out, "#endif // CXXBRIDGE1_RUST_VEC_{}", instance);
Myron Ahneba35cf2020-02-05 19:41:51 +07001401}
1402
David Tolnay8faec772020-11-02 00:18:19 -08001403fn write_rust_box_impl(out: &mut OutFile, ident: &Pair) {
Adrian Taylorc8713432020-10-21 18:20:55 -07001404 let inner = ident.to_fully_qualified();
1405 let instance = ident.to_symbol();
David Tolnay7db73692019-10-20 14:51:12 -04001406
1407 writeln!(out, "template <>");
David Tolnay324437a2020-03-01 13:02:24 -08001408 writeln!(out, "void Box<{}>::uninit() noexcept {{", inner);
David Tolnay0f0162f2020-11-16 23:43:37 -08001409 writeln!(out, " cxxbridge1$box${}$uninit(this);", instance);
David Tolnay7db73692019-10-20 14:51:12 -04001410 writeln!(out, "}}");
1411
1412 writeln!(out, "template <>");
David Tolnay324437a2020-03-01 13:02:24 -08001413 writeln!(out, "void Box<{}>::drop() noexcept {{", inner);
David Tolnay0f0162f2020-11-16 23:43:37 -08001414 writeln!(out, " cxxbridge1$box${}$drop(this);", instance);
David Tolnay7db73692019-10-20 14:51:12 -04001415 writeln!(out, "}}");
David Tolnay7db73692019-10-20 14:51:12 -04001416}
1417
David Tolnay75ea17c2020-12-06 21:08:34 -08001418fn write_rust_vec_impl(out: &mut OutFile, element: &RustName) {
David Tolnay1bdb4712020-11-25 07:27:54 -08001419 let inner = element.to_typename(out.types);
1420 let instance = element.to_mangled(out.types);
David Tolnay4791f1c2020-03-17 21:53:16 -07001421
Myron Ahneba35cf2020-02-05 19:41:51 +07001422 writeln!(out, "template <>");
David Tolnayf97c2d52020-04-25 16:37:48 -07001423 writeln!(out, "Vec<{}>::Vec() noexcept {{", inner);
David Tolnay0f0162f2020-11-16 23:43:37 -08001424 writeln!(out, " cxxbridge1$rust_vec${}$new(this);", instance);
David Tolnayf97c2d52020-04-25 16:37:48 -07001425 writeln!(out, "}}");
1426
1427 writeln!(out, "template <>");
Myron Ahneba35cf2020-02-05 19:41:51 +07001428 writeln!(out, "void Vec<{}>::drop() noexcept {{", inner);
David Tolnay0f0162f2020-11-16 23:43:37 -08001429 writeln!(out, " return cxxbridge1$rust_vec${}$drop(this);", instance);
Myron Ahneba35cf2020-02-05 19:41:51 +07001430 writeln!(out, "}}");
1431
1432 writeln!(out, "template <>");
1433 writeln!(out, "size_t Vec<{}>::size() const noexcept {{", inner);
David Tolnay0f0162f2020-11-16 23:43:37 -08001434 writeln!(out, " return cxxbridge1$rust_vec${}$len(this);", instance);
Myron Ahneba35cf2020-02-05 19:41:51 +07001435 writeln!(out, "}}");
David Tolnay219c0792020-04-24 20:31:37 -07001436
1437 writeln!(out, "template <>");
1438 writeln!(out, "const {} *Vec<{0}>::data() const noexcept {{", inner);
David Tolnay0f0162f2020-11-16 23:43:37 -08001439 writeln!(out, " return cxxbridge1$rust_vec${}$data(this);", instance);
David Tolnay219c0792020-04-24 20:31:37 -07001440 writeln!(out, "}}");
David Tolnay503d0192020-04-24 22:18:56 -07001441
1442 writeln!(out, "template <>");
David Tolnayfb6b73c2020-11-10 14:32:16 -08001443 writeln!(
1444 out,
1445 "void Vec<{}>::reserve_total(size_t cap) noexcept {{",
1446 inner,
1447 );
1448 writeln!(
1449 out,
David Tolnay0f0162f2020-11-16 23:43:37 -08001450 " return cxxbridge1$rust_vec${}$reserve_total(this, cap);",
David Tolnayfb6b73c2020-11-10 14:32:16 -08001451 instance,
1452 );
1453 writeln!(out, "}}");
1454
1455 writeln!(out, "template <>");
1456 writeln!(out, "void Vec<{}>::set_len(size_t len) noexcept {{", inner);
1457 writeln!(
1458 out,
David Tolnay0f0162f2020-11-16 23:43:37 -08001459 " return cxxbridge1$rust_vec${}$set_len(this, len);",
David Tolnayfb6b73c2020-11-10 14:32:16 -08001460 instance,
1461 );
1462 writeln!(out, "}}");
1463
1464 writeln!(out, "template <>");
David Tolnay503d0192020-04-24 22:18:56 -07001465 writeln!(out, "size_t Vec<{}>::stride() noexcept {{", inner);
David Tolnay0f0162f2020-11-16 23:43:37 -08001466 writeln!(out, " return cxxbridge1$rust_vec${}$stride();", instance);
David Tolnay503d0192020-04-24 22:18:56 -07001467 writeln!(out, "}}");
Myron Ahneba35cf2020-02-05 19:41:51 +07001468}
1469
David Tolnay75ea17c2020-12-06 21:08:34 -08001470fn write_unique_ptr(out: &mut OutFile, ident: &RustName) {
David Tolnay1bdb4712020-11-25 07:27:54 -08001471 let ty = UniquePtr::Ident(ident);
1472 let instance = ty.to_mangled(out.types);
David Tolnay63da4d32020-04-25 09:41:12 -07001473
David Tolnay0f0162f2020-11-16 23:43:37 -08001474 writeln!(out, "#ifndef CXXBRIDGE1_UNIQUE_PTR_{}", instance);
1475 writeln!(out, "#define CXXBRIDGE1_UNIQUE_PTR_{}", instance);
David Tolnay63da4d32020-04-25 09:41:12 -07001476
David Tolnay1bdb4712020-11-25 07:27:54 -08001477 write_unique_ptr_common(out, ty);
David Tolnay63da4d32020-04-25 09:41:12 -07001478
David Tolnay0f0162f2020-11-16 23:43:37 -08001479 writeln!(out, "#endif // CXXBRIDGE1_UNIQUE_PTR_{}", instance);
David Tolnay63da4d32020-04-25 09:41:12 -07001480}
1481
1482// Shared by UniquePtr<T> and UniquePtr<CxxVector<T>>.
David Tolnay1bdb4712020-11-25 07:27:54 -08001483fn write_unique_ptr_common(out: &mut OutFile, ty: UniquePtr) {
David Tolnay0ecd05a2020-07-29 16:32:03 -07001484 out.include.new = true;
Myron Ahneba35cf2020-02-05 19:41:51 +07001485 out.include.utility = true;
David Tolnay1bdb4712020-11-25 07:27:54 -08001486 let inner = ty.to_typename(out.types);
1487 let instance = ty.to_mangled(out.types);
David Tolnay7db73692019-10-20 14:51:12 -04001488
David Tolnay63da4d32020-04-25 09:41:12 -07001489 let can_construct_from_value = match ty {
David Tolnayca0f9da2020-10-16 13:16:17 -07001490 // Some aliases are to opaque types; some are to trivial types. We can't
1491 // know at code generation time, so we generate both C++ and Rust side
1492 // bindings for a "new" method anyway. But the Rust code can't be called
1493 // for Opaque types because the 'new' method is not implemented.
David Tolnay1bdb4712020-11-25 07:27:54 -08001494 UniquePtr::Ident(ident) => {
David Tolnaya7c2ea12020-10-30 21:32:53 -07001495 out.types.structs.contains_key(&ident.rust)
David Tolnay15609ab2020-11-25 07:14:12 -08001496 || out.types.enums.contains_key(&ident.rust)
David Tolnaya7c2ea12020-10-30 21:32:53 -07001497 || out.types.aliases.contains_key(&ident.rust)
David Tolnayca0f9da2020-10-16 13:16:17 -07001498 }
David Tolnay1bdb4712020-11-25 07:27:54 -08001499 UniquePtr::CxxVector(_) => false,
David Tolnay63da4d32020-04-25 09:41:12 -07001500 };
1501
David Tolnay53462762020-11-25 07:08:10 -08001502 let conditional_delete = match ty {
1503 UniquePtr::Ident(ident) => {
1504 !out.types.structs.contains_key(&ident.rust)
1505 && !out.types.enums.contains_key(&ident.rust)
1506 }
1507 UniquePtr::CxxVector(_) => false,
1508 };
1509
1510 if conditional_delete {
1511 out.builtin.is_complete = true;
1512 let definition = match ty {
1513 UniquePtr::Ident(ty) => &out.types.resolve(ty).cxx,
1514 UniquePtr::CxxVector(_) => unreachable!(),
1515 };
1516 writeln!(
1517 out,
1518 "static_assert(::rust::is_complete<{}>::value, \"definition of {} is required\");",
1519 inner, definition,
1520 );
1521 }
David Tolnay7db73692019-10-20 14:51:12 -04001522 writeln!(
1523 out,
David Tolnay7e219b82020-03-01 13:14:51 -08001524 "static_assert(sizeof(::std::unique_ptr<{}>) == sizeof(void *), \"\");",
David Tolnay7db73692019-10-20 14:51:12 -04001525 inner,
1526 );
1527 writeln!(
1528 out,
David Tolnay7e219b82020-03-01 13:14:51 -08001529 "static_assert(alignof(::std::unique_ptr<{}>) == alignof(void *), \"\");",
David Tolnay7db73692019-10-20 14:51:12 -04001530 inner,
1531 );
1532 writeln!(
1533 out,
David Tolnay0f0162f2020-11-16 23:43:37 -08001534 "void cxxbridge1$unique_ptr${}$null(::std::unique_ptr<{}> *ptr) noexcept {{",
David Tolnay7db73692019-10-20 14:51:12 -04001535 instance, inner,
1536 );
David Tolnay7e219b82020-03-01 13:14:51 -08001537 writeln!(out, " new (ptr) ::std::unique_ptr<{}>();", inner);
David Tolnay7db73692019-10-20 14:51:12 -04001538 writeln!(out, "}}");
David Tolnay63da4d32020-04-25 09:41:12 -07001539 if can_construct_from_value {
David Tolnay0b881402020-12-01 21:05:08 -08001540 out.builtin.maybe_uninit = true;
David Tolnay63da4d32020-04-25 09:41:12 -07001541 writeln!(
David Tolnay53838912020-04-09 20:56:44 -07001542 out,
David Tolnay0b881402020-12-01 21:05:08 -08001543 "{} *cxxbridge1$unique_ptr${}$uninit(::std::unique_ptr<{}> *ptr) noexcept {{",
1544 inner, instance, inner,
David Tolnay53838912020-04-09 20:56:44 -07001545 );
David Tolnay63da4d32020-04-25 09:41:12 -07001546 writeln!(
1547 out,
David Tolnay0b881402020-12-01 21:05:08 -08001548 " {} *uninit = reinterpret_cast<{} *>(new ::rust::MaybeUninit<{}>);",
1549 inner, inner, inner,
David Tolnay63da4d32020-04-25 09:41:12 -07001550 );
David Tolnay0b881402020-12-01 21:05:08 -08001551 writeln!(out, " new (ptr) ::std::unique_ptr<{}>(uninit);", inner);
1552 writeln!(out, " return uninit;");
David Tolnay63da4d32020-04-25 09:41:12 -07001553 writeln!(out, "}}");
David Tolnay53838912020-04-09 20:56:44 -07001554 }
David Tolnay7db73692019-10-20 14:51:12 -04001555 writeln!(
1556 out,
David Tolnay0f0162f2020-11-16 23:43:37 -08001557 "void cxxbridge1$unique_ptr${}$raw(::std::unique_ptr<{}> *ptr, {} *raw) noexcept {{",
David Tolnay7db73692019-10-20 14:51:12 -04001558 instance, inner, inner,
1559 );
David Tolnay7e219b82020-03-01 13:14:51 -08001560 writeln!(out, " new (ptr) ::std::unique_ptr<{}>(raw);", inner);
David Tolnay7db73692019-10-20 14:51:12 -04001561 writeln!(out, "}}");
1562 writeln!(
1563 out,
David Tolnay0f0162f2020-11-16 23:43:37 -08001564 "const {} *cxxbridge1$unique_ptr${}$get(const ::std::unique_ptr<{}>& ptr) noexcept {{",
David Tolnay7db73692019-10-20 14:51:12 -04001565 inner, instance, inner,
1566 );
1567 writeln!(out, " return ptr.get();");
1568 writeln!(out, "}}");
1569 writeln!(
1570 out,
David Tolnay0f0162f2020-11-16 23:43:37 -08001571 "{} *cxxbridge1$unique_ptr${}$release(::std::unique_ptr<{}>& ptr) noexcept {{",
David Tolnay7db73692019-10-20 14:51:12 -04001572 inner, instance, inner,
1573 );
1574 writeln!(out, " return ptr.release();");
1575 writeln!(out, "}}");
1576 writeln!(
1577 out,
David Tolnay0f0162f2020-11-16 23:43:37 -08001578 "void cxxbridge1$unique_ptr${}$drop(::std::unique_ptr<{}> *ptr) noexcept {{",
David Tolnay7db73692019-10-20 14:51:12 -04001579 instance, inner,
1580 );
David Tolnay53462762020-11-25 07:08:10 -08001581 if conditional_delete {
1582 out.builtin.deleter_if = true;
1583 writeln!(
1584 out,
1585 " ::rust::deleter_if<::rust::is_complete<{}>::value>{{}}(ptr);",
1586 inner,
1587 );
1588 } else {
1589 writeln!(out, " ptr->~unique_ptr();");
1590 }
David Tolnay7db73692019-10-20 14:51:12 -04001591 writeln!(out, "}}");
David Tolnay7db73692019-10-20 14:51:12 -04001592}
Myron Ahneba35cf2020-02-05 19:41:51 +07001593
David Tolnay75ea17c2020-12-06 21:08:34 -08001594fn write_shared_ptr(out: &mut OutFile, ident: &RustName) {
David Tolnayb3b24a12020-12-01 15:27:43 -08001595 let resolved = out.types.resolve(ident);
1596 let inner = resolved.to_fully_qualified();
1597 let instance = ident.to_symbol(out.types);
1598
1599 writeln!(out, "#ifndef CXXBRIDGE1_SHARED_PTR_{}", instance);
1600 writeln!(out, "#define CXXBRIDGE1_SHARED_PTR_{}", instance);
1601 out.include.new = true;
1602 out.include.utility = true;
1603
1604 // Some aliases are to opaque types; some are to trivial types. We can't
1605 // know at code generation time, so we generate both C++ and Rust side
1606 // bindings for a "new" method anyway. But the Rust code can't be called for
1607 // Opaque types because the 'new' method is not implemented.
1608 let can_construct_from_value = out.types.structs.contains_key(&ident.rust)
1609 || out.types.enums.contains_key(&ident.rust)
1610 || out.types.aliases.contains_key(&ident.rust);
1611
David Tolnayb3b24a12020-12-01 15:27:43 -08001612 writeln!(
1613 out,
1614 "static_assert(sizeof(::std::shared_ptr<{}>) == 2 * sizeof(void *), \"\");",
1615 inner,
1616 );
1617 writeln!(
1618 out,
1619 "static_assert(alignof(::std::shared_ptr<{}>) == alignof(void *), \"\");",
1620 inner,
1621 );
1622 writeln!(
1623 out,
1624 "void cxxbridge1$shared_ptr${}$null(::std::shared_ptr<{}> *ptr) noexcept {{",
1625 instance, inner,
1626 );
1627 writeln!(out, " new (ptr) ::std::shared_ptr<{}>();", inner);
1628 writeln!(out, "}}");
1629 if can_construct_from_value {
David Tolnay0b881402020-12-01 21:05:08 -08001630 out.builtin.maybe_uninit = true;
David Tolnayb3b24a12020-12-01 15:27:43 -08001631 writeln!(
1632 out,
David Tolnay0b881402020-12-01 21:05:08 -08001633 "{} *cxxbridge1$shared_ptr${}$uninit(::std::shared_ptr<{}> *ptr) noexcept {{",
1634 inner, instance, inner,
David Tolnayb3b24a12020-12-01 15:27:43 -08001635 );
1636 writeln!(
1637 out,
David Tolnay0b881402020-12-01 21:05:08 -08001638 " {} *uninit = reinterpret_cast<{} *>(new ::rust::MaybeUninit<{}>);",
1639 inner, inner, inner,
David Tolnayb3b24a12020-12-01 15:27:43 -08001640 );
David Tolnay0b881402020-12-01 21:05:08 -08001641 writeln!(out, " new (ptr) ::std::shared_ptr<{}>(uninit);", inner);
1642 writeln!(out, " return uninit;");
David Tolnayb3b24a12020-12-01 15:27:43 -08001643 writeln!(out, "}}");
1644 }
1645 writeln!(
1646 out,
1647 "void cxxbridge1$shared_ptr${}$clone(const ::std::shared_ptr<{}>& self, ::std::shared_ptr<{}> *ptr) noexcept {{",
1648 instance, inner, inner,
1649 );
1650 writeln!(out, " new (ptr) ::std::shared_ptr<{}>(self);", inner);
1651 writeln!(out, "}}");
1652 writeln!(
1653 out,
1654 "const {} *cxxbridge1$shared_ptr${}$get(const ::std::shared_ptr<{}>& self) noexcept {{",
1655 inner, instance, inner,
1656 );
1657 writeln!(out, " return self.get();");
1658 writeln!(out, "}}");
1659 writeln!(
1660 out,
1661 "void cxxbridge1$shared_ptr${}$drop(::std::shared_ptr<{}> *self) noexcept {{",
1662 instance, inner,
1663 );
1664 writeln!(out, " self->~shared_ptr();");
1665 writeln!(out, "}}");
1666
1667 writeln!(out, "#endif // CXXBRIDGE1_SHARED_PTR_{}", instance);
1668}
1669
David Tolnay75ea17c2020-12-06 21:08:34 -08001670fn write_cxx_vector(out: &mut OutFile, element: &RustName) {
David Tolnay1bdb4712020-11-25 07:27:54 -08001671 let inner = element.to_typename(out.types);
1672 let instance = element.to_mangled(out.types);
Myron Ahneba35cf2020-02-05 19:41:51 +07001673
David Tolnay0f0162f2020-11-16 23:43:37 -08001674 writeln!(out, "#ifndef CXXBRIDGE1_VECTOR_{}", instance);
1675 writeln!(out, "#define CXXBRIDGE1_VECTOR_{}", instance);
Myron Ahneba35cf2020-02-05 19:41:51 +07001676 writeln!(
1677 out,
David Tolnay0f0162f2020-11-16 23:43:37 -08001678 "size_t cxxbridge1$std$vector${}$size(const ::std::vector<{}> &s) noexcept {{",
Myron Ahneba35cf2020-02-05 19:41:51 +07001679 instance, inner,
1680 );
1681 writeln!(out, " return s.size();");
1682 writeln!(out, "}}");
Myron Ahneba35cf2020-02-05 19:41:51 +07001683 writeln!(
1684 out,
David Tolnay0f0162f2020-11-16 23:43:37 -08001685 "const {} *cxxbridge1$std$vector${}$get_unchecked(const ::std::vector<{}> &s, size_t pos) noexcept {{",
Myron Ahneba35cf2020-02-05 19:41:51 +07001686 inner, instance, inner,
1687 );
David Tolnayb3fcf7b2020-04-30 22:58:28 -07001688 writeln!(out, " return &s[pos];");
Myron Ahneba35cf2020-02-05 19:41:51 +07001689 writeln!(out, "}}");
David Tolnay63da4d32020-04-25 09:41:12 -07001690
David Tolnay1bdb4712020-11-25 07:27:54 -08001691 write_unique_ptr_common(out, UniquePtr::CxxVector(element));
David Tolnay63da4d32020-04-25 09:41:12 -07001692
David Tolnay0f0162f2020-11-16 23:43:37 -08001693 writeln!(out, "#endif // CXXBRIDGE1_VECTOR_{}", instance);
Myron Ahneba35cf2020-02-05 19:41:51 +07001694}