blob: dfa0502de5ec2b7da5edd35ce9a2fef29666e4ce [file] [log] [blame]
David Tolnaybd9608f2020-11-01 13:24:16 -08001use crate::gen::alphasort::NamespaceEntries;
David Tolnay0c033e32020-11-01 15:15:48 -08002use crate::gen::block::Block;
David Tolnay8810a542020-10-31 21:39:22 -07003use crate::gen::out::OutFile;
David Tolnay3374d8d2020-10-31 22:18:45 -07004use crate::gen::{builtin, include, Opt};
David Tolnay7db73692019-10-20 14:51:12 -04005use crate::syntax::atom::Atom::{self, *};
David Tolnay891061b2020-04-19 22:42:33 -07006use crate::syntax::symbol::Symbol;
Adrian Taylorc8713432020-10-21 18:20:55 -07007use crate::syntax::{
David Tolnay2f3e90b2020-10-31 22:16:51 -07008 mangle, Api, CppName, Enum, ExternFn, ExternType, ResolvableName, Signature, Struct, Type,
9 Types, Var,
Adrian Taylorc8713432020-10-21 18:20:55 -070010};
David Tolnay7db73692019-10-20 14:51:12 -040011use proc_macro2::Ident;
Joel Galenson0f654ff2020-05-04 20:04:21 -070012use std::collections::HashMap;
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 Tolnay74d6d512020-10-31 22:22:03 -070018 pick_includes_and_builtins(out);
David Tolnay4aae7c02020-10-28 12:35:42 -070019 out.include.extend(&opt.include);
David Tolnay7db73692019-10-20 14:51:12 -040020
Adrian Taylor565ddf02020-10-29 21:12:36 -070021 let apis_by_namespace = NamespaceEntries::new(apis);
David Tolnaye2797352020-11-01 19:08:37 -080022 write_namespace_forward_declarations(out, &apis_by_namespace);
23 write_namespace_contents(out, &apis_by_namespace);
Adrian Taylorc8713432020-10-21 18:20:55 -070024
25 if !header {
26 out.next_section();
David Tolnaya7c2ea12020-10-30 21:32:53 -070027 write_generic_instantiations(out);
David Tolnay7db73692019-10-20 14:51:12 -040028 }
29
David Tolnay3374d8d2020-10-31 22:18:45 -070030 builtin::write(out);
David Tolnay2f3e90b2020-10-31 22:16:51 -070031 include::write(out);
Adrian Taylorc8713432020-10-21 18:20:55 -070032
David Tolnayac7188c2020-11-01 16:58:16 -080033 out_file.content()
Adrian Taylorc8713432020-10-21 18:20:55 -070034}
35
David Tolnaye2797352020-11-01 19:08:37 -080036fn write_namespace_forward_declarations(out: &mut OutFile, ns_entries: &NamespaceEntries) {
David Tolnay9e4e7502020-11-01 12:47:36 -080037 let apis = ns_entries.direct_content();
Adrian Taylorc8713432020-10-21 18:20:55 -070038
David Tolnay630af882020-10-31 22:03:47 -070039 for api in apis {
David Tolnay7db73692019-10-20 14:51:12 -040040 match api {
David Tolnay880d1f82020-10-31 22:05:24 -070041 Api::Include(include) => out.include.insert(include),
Adrian Taylorc8713432020-10-21 18:20:55 -070042 Api::Struct(strct) => write_struct_decl(out, &strct.ident.cxx.ident),
43 Api::CxxType(ety) => write_struct_using(out, &ety.ident.cxx),
44 Api::RustType(ety) => write_struct_decl(out, &ety.ident.cxx.ident),
David Tolnay7c295462020-04-25 12:45:07 -070045 _ => {}
David Tolnay7db73692019-10-20 14:51:12 -040046 }
47 }
48
David Tolnay7943e502020-11-01 12:51:31 -080049 for (namespace, nested_ns_entries) in ns_entries.nested_content() {
50 writeln!(out, "namespace {} {{", namespace);
David Tolnaye2797352020-11-01 19:08:37 -080051 write_namespace_forward_declarations(out, nested_ns_entries);
David Tolnay7943e502020-11-01 12:51:31 -080052 writeln!(out, "}} // namespace {}", namespace);
Adrian Taylorf9213622020-10-31 22:25:42 -070053 }
54}
55
David Tolnaye2797352020-11-01 19:08:37 -080056fn write_namespace_contents<'a>(out: &mut OutFile<'a>, ns_entries: &'a NamespaceEntries<'a>) {
David Tolnay078c90f2020-11-01 13:31:08 -080057 out.set_namespace(&ns_entries.namespace);
David Tolnay9e4e7502020-11-01 12:47:36 -080058 let apis = ns_entries.direct_content();
Adrian Taylorf9213622020-10-31 22:25:42 -070059
David Tolnayf94bef12020-04-17 14:46:42 -070060 let mut methods_for_type = HashMap::new();
David Tolnay630af882020-10-31 22:03:47 -070061 for api in apis {
David Tolnayf94bef12020-04-17 14:46:42 -070062 if let Api::RustFunction(efn) = api {
63 if let Some(receiver) = &efn.sig.receiver {
64 methods_for_type
Adrian Taylorc8713432020-10-21 18:20:55 -070065 .entry(&receiver.ty.rust)
David Tolnayf94bef12020-04-17 14:46:42 -070066 .or_insert_with(Vec::new)
67 .push(efn);
68 }
69 }
70 }
Joel Galenson968738f2020-04-15 14:19:33 -070071
David Tolnay7db73692019-10-20 14:51:12 -040072 for api in apis {
Joel Galensonc1c4e7a2020-04-15 10:21:00 -070073 match api {
74 Api::Struct(strct) => {
75 out.next_section();
David Tolnay4d148422020-10-31 22:41:37 -070076 if !out.types.cxx.contains(&strct.ident.rust) {
David Tolnaya7c2ea12020-10-30 21:32:53 -070077 write_struct(out, strct);
David Tolnaya593d6e2020-08-29 19:48:08 -070078 }
Joel Galensonc1c4e7a2020-04-15 10:21:00 -070079 }
Joel Galensonc03402a2020-04-23 17:31:09 -070080 Api::Enum(enm) => {
81 out.next_section();
David Tolnay4d148422020-10-31 22:41:37 -070082 if out.types.cxx.contains(&enm.ident.rust) {
Joel Galenson905eb2e2020-05-04 14:58:14 -070083 check_enum(out, enm);
84 } else {
85 write_enum(out, enm);
86 }
Joel Galensonc03402a2020-04-23 17:31:09 -070087 }
David Tolnayc1fe0052020-04-17 15:15:06 -070088 Api::RustType(ety) => {
Adrian Taylorc8713432020-10-21 18:20:55 -070089 if let Some(methods) = methods_for_type.get(&ety.ident.rust) {
David Tolnay46a54e72020-04-17 14:48:21 -070090 out.next_section();
David Tolnaya7c2ea12020-10-30 21:32:53 -070091 write_struct_with_methods(out, ety, methods);
Joel Galensonc1c4e7a2020-04-15 10:21:00 -070092 }
David Tolnayc1fe0052020-04-17 15:15:06 -070093 }
Joel Galensonc1c4e7a2020-04-15 10:21:00 -070094 _ => {}
David Tolnay7db73692019-10-20 14:51:12 -040095 }
96 }
97
David Tolnayfabca772020-10-03 21:25:41 -070098 out.next_section();
99 for api in apis {
100 if let Api::TypeAlias(ety) = api {
David Tolnay4d148422020-10-31 22:41:37 -0700101 if out.types.required_trivial.contains_key(&ety.ident.rust) {
Adrian Taylorc8713432020-10-21 18:20:55 -0700102 check_trivial_extern_type(out, &ety.ident.cxx)
David Tolnayfabca772020-10-03 21:25:41 -0700103 }
104 }
105 }
106
David Tolnayce5a91f2020-10-31 22:42:08 -0700107 if !out.header {
David Tolnay7db73692019-10-20 14:51:12 -0400108 for api in apis {
David Tolnay04770742020-11-01 13:50:50 -0800109 match api {
110 Api::CxxFunction(efn) => write_cxx_function_shim(out, efn),
111 Api::RustFunction(efn) => write_rust_function_decl(out, efn),
112 _ => {}
113 }
David Tolnay7db73692019-10-20 14:51:12 -0400114 }
David Tolnay7db73692019-10-20 14:51:12 -0400115 }
116
117 for api in apis {
118 if let Api::RustFunction(efn) = api {
119 out.next_section();
David Tolnaya7c2ea12020-10-30 21:32:53 -0700120 write_rust_function_shim(out, efn);
David Tolnay7db73692019-10-20 14:51:12 -0400121 }
122 }
123
David Tolnay078c90f2020-11-01 13:31:08 -0800124 for (_, nested_ns_entries) in ns_entries.nested_content() {
David Tolnaye2797352020-11-01 19:08:37 -0800125 write_namespace_contents(out, nested_ns_entries);
David Tolnay7db73692019-10-20 14:51:12 -0400126 }
David Tolnay7db73692019-10-20 14:51:12 -0400127}
128
David Tolnay74d6d512020-10-31 22:22:03 -0700129fn pick_includes_and_builtins(out: &mut OutFile) {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700130 for ty in out.types {
David Tolnay7db73692019-10-20 14:51:12 -0400131 match ty {
Adrian Taylorc8713432020-10-21 18:20:55 -0700132 Type::Ident(ident) => match Atom::from(&ident.rust) {
David Tolnay89e386d2020-10-03 19:02:19 -0700133 Some(U8) | Some(U16) | Some(U32) | Some(U64) | Some(I8) | Some(I16) | Some(I32)
134 | Some(I64) => out.include.cstdint = true,
135 Some(Usize) => out.include.cstddef = true,
David Tolnayb9da1462020-10-31 21:03:41 -0700136 Some(Isize) => {
137 out.include.basetsd = true;
138 out.builtin.rust_isize = true;
139 }
David Tolnay89e386d2020-10-03 19:02:19 -0700140 Some(CxxString) => out.include.string = true,
David Tolnayb9da1462020-10-31 21:03:41 -0700141 Some(RustString) => {
142 out.include.array = true;
143 out.include.cstdint = true;
144 out.include.string = true;
145 out.builtin.rust_string = true;
146 }
147 Some(Bool) | Some(F32) | Some(F64) | None => {}
David Tolnay89e386d2020-10-03 19:02:19 -0700148 },
David Tolnayb7a7cb62020-03-17 21:18:40 -0700149 Type::RustBox(_) => {
David Tolnay0ecd05a2020-07-29 16:32:03 -0700150 out.include.new = true;
David Tolnayb7a7cb62020-03-17 21:18:40 -0700151 out.include.type_traits = true;
David Tolnay3be0e1f2020-10-31 20:53:00 -0700152 out.builtin.rust_box = true;
David Tolnayb7a7cb62020-03-17 21:18:40 -0700153 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700154 Type::RustVec(_) => {
David Tolnay9c6bf2d2020-04-24 15:27:07 -0700155 out.include.array = true;
David Tolnay0ecd05a2020-07-29 16:32:03 -0700156 out.include.new = true;
David Tolnayc87c2152020-04-24 17:07:41 -0700157 out.include.type_traits = true;
David Tolnay3be0e1f2020-10-31 20:53:00 -0700158 out.builtin.panic = true;
159 out.builtin.rust_vec = true;
160 out.builtin.unsafe_bitcopy = true;
Myron Ahneba35cf2020-02-05 19:41:51 +0700161 }
David Tolnayb9da1462020-10-31 21:03:41 -0700162 Type::UniquePtr(_) => out.include.memory = true,
David Tolnayb7a7cb62020-03-17 21:18:40 -0700163 Type::Str(_) => {
164 out.include.cstdint = true;
165 out.include.string = true;
David Tolnay3be0e1f2020-10-31 20:53:00 -0700166 out.builtin.rust_str = true;
David Tolnayb7a7cb62020-03-17 21:18:40 -0700167 }
David Tolnayb9da1462020-10-31 21:03:41 -0700168 Type::CxxVector(_) => out.include.vector = true,
David Tolnay75dca2e2020-03-25 20:17:52 -0700169 Type::Fn(_) => {
David Tolnay3be0e1f2020-10-31 20:53:00 -0700170 out.builtin.rust_fn = true;
David Tolnay75dca2e2020-03-25 20:17:52 -0700171 }
David Tolnayb9da1462020-10-31 21:03:41 -0700172 Type::Slice(_) => {
David Tolnay3be0e1f2020-10-31 20:53:00 -0700173 out.builtin.rust_slice = true;
David Tolnay4770b472020-04-14 16:32:59 -0700174 }
David Tolnayb9da1462020-10-31 21:03:41 -0700175 Type::SliceRefU8(_) => {
David Tolnayb7a7cb62020-03-17 21:18:40 -0700176 out.include.cstdint = true;
David Tolnayb9da1462020-10-31 21:03:41 -0700177 out.builtin.rust_slice = true;
David Tolnayb7a7cb62020-03-17 21:18:40 -0700178 }
David Tolnay11bd7ff2020-11-01 19:44:58 -0800179 Type::Ref(_) | Type::Void(_) => {}
David Tolnay7db73692019-10-20 14:51:12 -0400180 }
181 }
David Tolnayec66d112020-10-31 21:00:26 -0700182}
David Tolnayf51447e2020-03-06 14:14:27 -0800183
David Tolnaya7c2ea12020-10-30 21:32:53 -0700184fn write_struct(out: &mut OutFile, strct: &Struct) {
Adrian Taylorc8713432020-10-21 18:20:55 -0700185 let guard = format!("CXXBRIDGE05_STRUCT_{}", strct.ident.cxx.to_symbol());
David Tolnaya25ea9c2020-08-27 22:59:38 -0700186 writeln!(out, "#ifndef {}", guard);
187 writeln!(out, "#define {}", guard);
David Tolnay7db73692019-10-20 14:51:12 -0400188 for line in strct.doc.to_string().lines() {
189 writeln!(out, "//{}", line);
190 }
Adrian Taylorc8713432020-10-21 18:20:55 -0700191 writeln!(out, "struct {} final {{", strct.ident.cxx.ident);
David Tolnay7db73692019-10-20 14:51:12 -0400192 for field in &strct.fields {
193 write!(out, " ");
David Tolnaya7c2ea12020-10-30 21:32:53 -0700194 write_type_space(out, &field.ty);
David Tolnay7db73692019-10-20 14:51:12 -0400195 writeln!(out, "{};", field.ident);
196 }
197 writeln!(out, "}};");
David Tolnaya25ea9c2020-08-27 22:59:38 -0700198 writeln!(out, "#endif // {}", guard);
David Tolnay7db73692019-10-20 14:51:12 -0400199}
200
201fn write_struct_decl(out: &mut OutFile, ident: &Ident) {
202 writeln!(out, "struct {};", ident);
203}
204
Adrian Taylorc8713432020-10-21 18:20:55 -0700205fn write_struct_using(out: &mut OutFile, ident: &CppName) {
206 writeln!(
207 out,
208 "using {} = {};",
209 ident.ident,
210 ident.to_fully_qualified()
211 );
David Tolnay8861bee2020-01-20 18:39:24 -0800212}
213
David Tolnaya7c2ea12020-10-30 21:32:53 -0700214fn write_struct_with_methods(out: &mut OutFile, ety: &ExternType, methods: &[&ExternFn]) {
Adrian Taylorc8713432020-10-21 18:20:55 -0700215 let guard = format!("CXXBRIDGE05_STRUCT_{}", ety.ident.cxx.to_symbol());
David Tolnaya25ea9c2020-08-27 22:59:38 -0700216 writeln!(out, "#ifndef {}", guard);
217 writeln!(out, "#define {}", guard);
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700218 for line in ety.doc.to_string().lines() {
219 writeln!(out, "//{}", line);
220 }
Adrian Taylorc8713432020-10-21 18:20:55 -0700221 writeln!(out, "struct {} final {{", ety.ident.cxx.ident);
222 writeln!(out, " {}() = delete;", ety.ident.cxx.ident);
223 writeln!(
224 out,
225 " {}(const {} &) = delete;",
226 ety.ident.cxx.ident, ety.ident.cxx.ident
227 );
Joel Galenson968738f2020-04-15 14:19:33 -0700228 for method in methods {
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700229 write!(out, " ");
230 let sig = &method.sig;
Adrian Taylorc8713432020-10-21 18:20:55 -0700231 let local_name = method.ident.cxx.ident.to_string();
David Tolnaya7c2ea12020-10-30 21:32:53 -0700232 write_rust_function_shim_decl(out, &local_name, sig, false);
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700233 writeln!(out, ";");
234 }
235 writeln!(out, "}};");
David Tolnaya25ea9c2020-08-27 22:59:38 -0700236 writeln!(out, "#endif // {}", guard);
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700237}
238
Joel Galensonc03402a2020-04-23 17:31:09 -0700239fn write_enum(out: &mut OutFile, enm: &Enum) {
Adrian Taylorc8713432020-10-21 18:20:55 -0700240 let guard = format!("CXXBRIDGE05_ENUM_{}", enm.ident.cxx.to_symbol());
David Tolnaya25ea9c2020-08-27 22:59:38 -0700241 writeln!(out, "#ifndef {}", guard);
242 writeln!(out, "#define {}", guard);
Joel Galensonc03402a2020-04-23 17:31:09 -0700243 for line in enm.doc.to_string().lines() {
244 writeln!(out, "//{}", line);
245 }
Adrian Taylorc8713432020-10-21 18:20:55 -0700246 write!(out, "enum class {} : ", enm.ident.cxx.ident);
David Tolnayf6a89f22020-05-10 23:39:27 -0700247 write_atom(out, enm.repr);
248 writeln!(out, " {{");
Joel Galensonc03402a2020-04-23 17:31:09 -0700249 for variant in &enm.variants {
Joel Galenson88547732020-05-05 08:23:42 -0700250 writeln!(out, " {} = {},", variant.ident, variant.discriminant);
Joel Galensonc03402a2020-04-23 17:31:09 -0700251 }
252 writeln!(out, "}};");
David Tolnaya25ea9c2020-08-27 22:59:38 -0700253 writeln!(out, "#endif // {}", guard);
Joel Galensonc03402a2020-04-23 17:31:09 -0700254}
255
Joel Galenson905eb2e2020-05-04 14:58:14 -0700256fn check_enum(out: &mut OutFile, enm: &Enum) {
Adrian Taylorc8713432020-10-21 18:20:55 -0700257 write!(
258 out,
259 "static_assert(sizeof({}) == sizeof(",
260 enm.ident.cxx.ident
261 );
David Tolnayf6a89f22020-05-10 23:39:27 -0700262 write_atom(out, enm.repr);
263 writeln!(out, "), \"incorrect size\");");
Joel Galenson0f654ff2020-05-04 20:04:21 -0700264 for variant in &enm.variants {
David Tolnayf6a89f22020-05-10 23:39:27 -0700265 write!(out, "static_assert(static_cast<");
266 write_atom(out, enm.repr);
Joel Galenson0f654ff2020-05-04 20:04:21 -0700267 writeln!(
268 out,
David Tolnayf6a89f22020-05-10 23:39:27 -0700269 ">({}::{}) == {}, \"disagrees with the value in #[cxx::bridge]\");",
Adrian Taylorc8713432020-10-21 18:20:55 -0700270 enm.ident.cxx.ident, variant.ident, variant.discriminant,
Joel Galenson0f654ff2020-05-04 20:04:21 -0700271 );
Joel Galenson0f654ff2020-05-04 20:04:21 -0700272 }
Joel Galenson905eb2e2020-05-04 14:58:14 -0700273}
274
Adrian Taylorc8713432020-10-21 18:20:55 -0700275fn check_trivial_extern_type(out: &mut OutFile, id: &CppName) {
David Tolnayfd0034e2020-10-04 13:15:34 -0700276 // NOTE: The following two static assertions are just nice-to-have and not
277 // necessary for soundness. That's because triviality is always declared by
278 // the user in the form of an unsafe impl of cxx::ExternType:
279 //
280 // unsafe impl ExternType for MyType {
281 // type Id = cxx::type_id!("...");
282 // type Kind = cxx::kind::Trivial;
283 // }
284 //
285 // Since the user went on the record with their unsafe impl to unsafely
286 // claim they KNOW that the type is trivial, it's fine for that to be on
287 // them if that were wrong.
288 //
289 // There may be a legitimate reason we'll want to remove these assertions
290 // for support of types that the programmer knows are Rust-movable despite
291 // not being recognized as such by the C++ type system due to a move
292 // constructor or destructor.
293
Adrian Taylorc8713432020-10-21 18:20:55 -0700294 let id = &id.to_fully_qualified();
David Tolnayf57f7562020-10-04 19:56:26 -0700295 out.include.type_traits = true;
David Tolnay7426cc12020-10-03 19:04:04 -0700296 writeln!(out, "static_assert(");
297 writeln!(
298 out,
David Tolnaycc44c7a2020-10-04 13:20:03 -0700299 " ::std::is_trivially_move_constructible<{}>::value,",
David Tolnay7426cc12020-10-03 19:04:04 -0700300 id,
301 );
302 writeln!(
303 out,
304 " \"type {} marked as Trivial in Rust is not trivially move constructible in C++\");",
305 id,
306 );
307 writeln!(out, "static_assert(");
David Tolnaycc44c7a2020-10-04 13:20:03 -0700308 writeln!(out, " ::std::is_trivially_destructible<{}>::value,", id);
David Tolnay7426cc12020-10-03 19:04:04 -0700309 writeln!(
310 out,
311 " \"type {} marked as Trivial in Rust is not trivially destructible in C++\");",
312 id,
313 );
Adrian Taylor405e8742020-09-25 14:01:25 -0700314}
315
David Tolnaye1476af2020-11-01 13:47:25 -0800316fn write_cxx_function_shim(out: &mut OutFile, efn: &ExternFn) {
David Tolnay04770742020-11-01 13:50:50 -0800317 out.next_section();
David Tolnayca563ee2020-11-01 20:12:27 -0800318 out.begin_block(Block::ExternC);
David Tolnaye1476af2020-11-01 13:47:25 -0800319 if let Some(annotation) = &out.opt.cxx_impl_annotations {
David Tolnaycc1ae762020-10-31 15:53:50 -0700320 write!(out, "{} ", annotation);
Adrian Taylor21f0ff02020-07-21 16:21:48 -0700321 }
David Tolnayebef4a22020-03-17 15:33:47 -0700322 if efn.throws {
David Tolnay919085c2020-10-31 22:32:22 -0700323 out.builtin.ptr_len = true;
David Tolnayd68dfa82020-10-31 16:01:24 -0700324 write!(out, "::rust::repr::PtrLen ");
David Tolnayebef4a22020-03-17 15:33:47 -0700325 } else {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700326 write_extern_return_type_space(out, &efn.ret);
David Tolnayebef4a22020-03-17 15:33:47 -0700327 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700328 let mangled = mangle::extern_fn(efn, out.types);
David Tolnay3caa50a2020-04-19 21:25:34 -0700329 write!(out, "{}(", mangled);
David Tolnaye439c772020-04-20 00:23:55 -0700330 if let Some(receiver) = &efn.receiver {
David Tolnay86710612020-04-20 00:30:32 -0700331 if receiver.mutability.is_none() {
332 write!(out, "const ");
333 }
Adrian Taylorc8713432020-10-21 18:20:55 -0700334 write!(
335 out,
336 "{} &self",
David Tolnaya7c2ea12020-10-30 21:32:53 -0700337 out.types.resolve(&receiver.ty).to_fully_qualified()
Adrian Taylorc8713432020-10-21 18:20:55 -0700338 );
Joel Galenson3d4f6122020-04-07 15:54:05 -0700339 }
David Tolnay7db73692019-10-20 14:51:12 -0400340 for (i, arg) in efn.args.iter().enumerate() {
Joel Galenson3d4f6122020-04-07 15:54:05 -0700341 if i > 0 || efn.receiver.is_some() {
David Tolnay7db73692019-10-20 14:51:12 -0400342 write!(out, ", ");
343 }
David Tolnaya46a2372020-03-06 10:03:48 -0800344 if arg.ty == RustString {
345 write!(out, "const ");
David Tolnay313b10e2020-04-25 16:30:51 -0700346 } else if let Type::RustVec(_) = arg.ty {
347 write!(out, "const ");
David Tolnaya46a2372020-03-06 10:03:48 -0800348 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700349 write_extern_arg(out, arg);
David Tolnay7db73692019-10-20 14:51:12 -0400350 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700351 let indirect_return = indirect_return(efn, out.types);
David Tolnay7db73692019-10-20 14:51:12 -0400352 if indirect_return {
myronahne3b78ea2020-05-23 01:08:13 +0700353 if !efn.args.is_empty() || efn.receiver.is_some() {
David Tolnay7db73692019-10-20 14:51:12 -0400354 write!(out, ", ");
355 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700356 write_indirect_return_type_space(out, efn.ret.as_ref().unwrap());
David Tolnay7db73692019-10-20 14:51:12 -0400357 write!(out, "*return$");
358 }
359 writeln!(out, ") noexcept {{");
360 write!(out, " ");
David Tolnaya7c2ea12020-10-30 21:32:53 -0700361 write_return_type(out, &efn.ret);
Joel Galenson3d4f6122020-04-07 15:54:05 -0700362 match &efn.receiver {
David Tolnaya4641c72020-09-08 14:05:53 -0700363 None => write!(out, "(*{}$)(", efn.ident.rust),
Adrian Taylorc8713432020-10-21 18:20:55 -0700364 Some(receiver) => write!(
365 out,
366 "({}::*{}$)(",
David Tolnaya7c2ea12020-10-30 21:32:53 -0700367 out.types.resolve(&receiver.ty).to_fully_qualified(),
Adrian Taylorc8713432020-10-21 18:20:55 -0700368 efn.ident.rust
369 ),
Joel Galenson3d4f6122020-04-07 15:54:05 -0700370 }
David Tolnay7db73692019-10-20 14:51:12 -0400371 for (i, arg) in efn.args.iter().enumerate() {
372 if i > 0 {
373 write!(out, ", ");
374 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700375 write_type(out, &arg.ty);
David Tolnay7db73692019-10-20 14:51:12 -0400376 }
Joel Galenson3d4f6122020-04-07 15:54:05 -0700377 write!(out, ")");
David Tolnay4e7123f2020-04-19 21:11:37 -0700378 if let Some(receiver) = &efn.receiver {
379 if receiver.mutability.is_none() {
380 write!(out, " const");
381 }
Joel Galenson3d4f6122020-04-07 15:54:05 -0700382 }
383 write!(out, " = ");
384 match &efn.receiver {
Adrian Taylorc8713432020-10-21 18:20:55 -0700385 None => write!(out, "{}", efn.ident.cxx.to_fully_qualified()),
386 Some(receiver) => write!(
387 out,
388 "&{}::{}",
David Tolnaya7c2ea12020-10-30 21:32:53 -0700389 out.types.resolve(&receiver.ty).to_fully_qualified(),
Adrian Taylorc8713432020-10-21 18:20:55 -0700390 efn.ident.cxx.ident
391 ),
Joel Galenson3d4f6122020-04-07 15:54:05 -0700392 }
393 writeln!(out, ";");
David Tolnay7db73692019-10-20 14:51:12 -0400394 write!(out, " ");
David Tolnayebef4a22020-03-17 15:33:47 -0700395 if efn.throws {
David Tolnay919085c2020-10-31 22:32:22 -0700396 out.builtin.ptr_len = true;
David Tolnay74d6d512020-10-31 22:22:03 -0700397 out.builtin.trycatch = true;
David Tolnayd68dfa82020-10-31 16:01:24 -0700398 writeln!(out, "::rust::repr::PtrLen throw$;");
David Tolnay3e3e0af2020-03-17 22:42:49 -0700399 writeln!(out, " ::rust::behavior::trycatch(");
David Tolnay5d121442020-03-17 22:14:40 -0700400 writeln!(out, " [&] {{");
401 write!(out, " ");
David Tolnayebef4a22020-03-17 15:33:47 -0700402 }
David Tolnay7db73692019-10-20 14:51:12 -0400403 if indirect_return {
David Tolnay0ecd05a2020-07-29 16:32:03 -0700404 out.include.new = true;
David Tolnay7db73692019-10-20 14:51:12 -0400405 write!(out, "new (return$) ");
David Tolnaya7c2ea12020-10-30 21:32:53 -0700406 write_indirect_return_type(out, efn.ret.as_ref().unwrap());
David Tolnay7db73692019-10-20 14:51:12 -0400407 write!(out, "(");
David Tolnay99642622020-03-25 13:07:35 -0700408 } else if efn.ret.is_some() {
David Tolnay7db73692019-10-20 14:51:12 -0400409 write!(out, "return ");
David Tolnay99642622020-03-25 13:07:35 -0700410 }
411 match &efn.ret {
412 Some(Type::Ref(_)) => write!(out, "&"),
David Tolnay74d6d512020-10-31 22:22:03 -0700413 Some(Type::Str(_)) if !indirect_return => {
414 out.builtin.rust_str_repr = true;
415 write!(out, "::rust::impl<::rust::Str>::repr(");
416 }
David Tolnayeb952ba2020-04-14 15:02:24 -0700417 Some(Type::SliceRefU8(_)) if !indirect_return => {
David Tolnay36aa9e02020-10-31 23:08:21 -0700418 out.builtin.rust_slice_repr = true;
419 write!(out, "::rust::impl<::rust::Slice<uint8_t>>::repr(")
David Tolnayeb952ba2020-04-14 15:02:24 -0700420 }
David Tolnay99642622020-03-25 13:07:35 -0700421 _ => {}
David Tolnay7db73692019-10-20 14:51:12 -0400422 }
Joel Galenson3d4f6122020-04-07 15:54:05 -0700423 match &efn.receiver {
David Tolnaya4641c72020-09-08 14:05:53 -0700424 None => write!(out, "{}$(", efn.ident.rust),
425 Some(_) => write!(out, "(self.*{}$)(", efn.ident.rust),
Joel Galenson3d4f6122020-04-07 15:54:05 -0700426 }
David Tolnay7db73692019-10-20 14:51:12 -0400427 for (i, arg) in efn.args.iter().enumerate() {
428 if i > 0 {
429 write!(out, ", ");
430 }
431 if let Type::RustBox(_) = &arg.ty {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700432 write_type(out, &arg.ty);
David Tolnay7db73692019-10-20 14:51:12 -0400433 write!(out, "::from_raw({})", arg.ident);
434 } else if let Type::UniquePtr(_) = &arg.ty {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700435 write_type(out, &arg.ty);
David Tolnay7db73692019-10-20 14:51:12 -0400436 write!(out, "({})", arg.ident);
David Tolnay0356d332020-10-31 19:46:41 -0700437 } else if let Type::Str(_) = arg.ty {
David Tolnay74d6d512020-10-31 22:22:03 -0700438 out.builtin.rust_str_new_unchecked = true;
David Tolnay0356d332020-10-31 19:46:41 -0700439 write!(
440 out,
441 "::rust::impl<::rust::Str>::new_unchecked({})",
442 arg.ident,
443 );
David Tolnaya46a2372020-03-06 10:03:48 -0800444 } else if arg.ty == RustString {
David Tolnay74d6d512020-10-31 22:22:03 -0700445 out.builtin.unsafe_bitcopy = true;
David Tolnaycc3767f2020-03-06 10:41:51 -0800446 write!(
447 out,
448 "::rust::String(::rust::unsafe_bitcopy, *{})",
449 arg.ident,
450 );
David Tolnay313b10e2020-04-25 16:30:51 -0700451 } else if let Type::RustVec(_) = arg.ty {
David Tolnay74d6d512020-10-31 22:22:03 -0700452 out.builtin.unsafe_bitcopy = true;
David Tolnaya7c2ea12020-10-30 21:32:53 -0700453 write_type(out, &arg.ty);
David Tolnay313b10e2020-04-25 16:30:51 -0700454 write!(out, "(::rust::unsafe_bitcopy, *{})", arg.ident);
David Tolnay36aa9e02020-10-31 23:08:21 -0700455 } else if let Type::SliceRefU8(_) = arg.ty {
456 write!(
457 out,
458 "::rust::Slice<uint8_t>(static_cast<const uint8_t *>({0}.ptr), {0}.len)",
459 arg.ident,
460 );
David Tolnaya7c2ea12020-10-30 21:32:53 -0700461 } else if out.types.needs_indirect_abi(&arg.ty) {
David Tolnay4791f1c2020-03-17 21:53:16 -0700462 out.include.utility = true;
David Tolnay7e219b82020-03-01 13:14:51 -0800463 write!(out, "::std::move(*{})", arg.ident);
David Tolnay7db73692019-10-20 14:51:12 -0400464 } else {
465 write!(out, "{}", arg.ident);
466 }
467 }
468 write!(out, ")");
469 match &efn.ret {
470 Some(Type::RustBox(_)) => write!(out, ".into_raw()"),
471 Some(Type::UniquePtr(_)) => write!(out, ".release()"),
David Tolnay0356d332020-10-31 19:46:41 -0700472 Some(Type::Str(_)) | Some(Type::SliceRefU8(_)) if !indirect_return => write!(out, ")"),
David Tolnay7db73692019-10-20 14:51:12 -0400473 _ => {}
474 }
475 if indirect_return {
476 write!(out, ")");
477 }
478 writeln!(out, ";");
David Tolnayebef4a22020-03-17 15:33:47 -0700479 if efn.throws {
480 out.include.cstring = true;
David Tolnay1f010c62020-11-01 20:27:46 -0800481 out.builtin.exception = true;
David Tolnay5d121442020-03-17 22:14:40 -0700482 writeln!(out, " throw$.ptr = nullptr;");
483 writeln!(out, " }},");
David Tolnay82c16172020-03-17 22:54:12 -0700484 writeln!(out, " [&](const char *catch$) noexcept {{");
David Tolnay5d121442020-03-17 22:14:40 -0700485 writeln!(out, " throw$.len = ::std::strlen(catch$);");
David Tolnayebef4a22020-03-17 15:33:47 -0700486 writeln!(
487 out,
David Tolnay1f010c62020-11-01 20:27:46 -0800488 " throw$.ptr = ::cxxbridge05$exception(catch$, throw$.len);",
David Tolnayebef4a22020-03-17 15:33:47 -0700489 );
David Tolnay5d121442020-03-17 22:14:40 -0700490 writeln!(out, " }});");
David Tolnayebef4a22020-03-17 15:33:47 -0700491 writeln!(out, " return throw$;");
492 }
David Tolnay7db73692019-10-20 14:51:12 -0400493 writeln!(out, "}}");
David Tolnay75dca2e2020-03-25 20:17:52 -0700494 for arg in &efn.args {
495 if let Type::Fn(f) = &arg.ty {
496 let var = &arg.ident;
David Tolnaya7c2ea12020-10-30 21:32:53 -0700497 write_function_pointer_trampoline(out, efn, var, f);
David Tolnay75dca2e2020-03-25 20:17:52 -0700498 }
499 }
David Tolnayca563ee2020-11-01 20:12:27 -0800500 out.end_block(Block::ExternC);
David Tolnay75dca2e2020-03-25 20:17:52 -0700501}
502
503fn write_function_pointer_trampoline(
504 out: &mut OutFile,
505 efn: &ExternFn,
506 var: &Ident,
507 f: &Signature,
David Tolnay75dca2e2020-03-25 20:17:52 -0700508) {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700509 let r_trampoline = mangle::r_trampoline(efn, var, out.types);
David Tolnay75dca2e2020-03-25 20:17:52 -0700510 let indirect_call = true;
David Tolnaya7c2ea12020-10-30 21:32:53 -0700511 write_rust_function_decl_impl(out, &r_trampoline, f, indirect_call);
David Tolnay75dca2e2020-03-25 20:17:52 -0700512
513 out.next_section();
David Tolnaya7c2ea12020-10-30 21:32:53 -0700514 let c_trampoline = mangle::c_trampoline(efn, var, out.types).to_string();
515 write_rust_function_shim_impl(out, &c_trampoline, f, &r_trampoline, indirect_call);
David Tolnay7db73692019-10-20 14:51:12 -0400516}
517
David Tolnaye1476af2020-11-01 13:47:25 -0800518fn write_rust_function_decl(out: &mut OutFile, efn: &ExternFn) {
David Tolnayca563ee2020-11-01 20:12:27 -0800519 out.begin_block(Block::ExternC);
David Tolnaya7c2ea12020-10-30 21:32:53 -0700520 let link_name = mangle::extern_fn(efn, out.types);
David Tolnay75dca2e2020-03-25 20:17:52 -0700521 let indirect_call = false;
David Tolnaya7c2ea12020-10-30 21:32:53 -0700522 write_rust_function_decl_impl(out, &link_name, efn, indirect_call);
David Tolnayca563ee2020-11-01 20:12:27 -0800523 out.end_block(Block::ExternC);
David Tolnay75dca2e2020-03-25 20:17:52 -0700524}
525
526fn write_rust_function_decl_impl(
527 out: &mut OutFile,
David Tolnay891061b2020-04-19 22:42:33 -0700528 link_name: &Symbol,
David Tolnay75dca2e2020-03-25 20:17:52 -0700529 sig: &Signature,
David Tolnay75dca2e2020-03-25 20:17:52 -0700530 indirect_call: bool,
531) {
David Tolnay04770742020-11-01 13:50:50 -0800532 out.next_section();
David Tolnay75dca2e2020-03-25 20:17:52 -0700533 if sig.throws {
David Tolnay919085c2020-10-31 22:32:22 -0700534 out.builtin.ptr_len = true;
David Tolnayd68dfa82020-10-31 16:01:24 -0700535 write!(out, "::rust::repr::PtrLen ");
David Tolnay1e548172020-03-16 13:37:09 -0700536 } else {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700537 write_extern_return_type_space(out, &sig.ret);
David Tolnay1e548172020-03-16 13:37:09 -0700538 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700539 write!(out, "{}(", link_name);
540 let mut needs_comma = false;
David Tolnaye439c772020-04-20 00:23:55 -0700541 if let Some(receiver) = &sig.receiver {
David Tolnay86710612020-04-20 00:30:32 -0700542 if receiver.mutability.is_none() {
543 write!(out, "const ");
544 }
Adrian Taylorc8713432020-10-21 18:20:55 -0700545 write!(
546 out,
547 "{} &self",
David Tolnaya7c2ea12020-10-30 21:32:53 -0700548 out.types.resolve(&receiver.ty).to_fully_qualified()
Adrian Taylorc8713432020-10-21 18:20:55 -0700549 );
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700550 needs_comma = true;
551 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700552 for arg in &sig.args {
553 if needs_comma {
David Tolnay7db73692019-10-20 14:51:12 -0400554 write!(out, ", ");
555 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700556 write_extern_arg(out, arg);
David Tolnay75dca2e2020-03-25 20:17:52 -0700557 needs_comma = true;
David Tolnay7db73692019-10-20 14:51:12 -0400558 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700559 if indirect_return(sig, out.types) {
David Tolnay75dca2e2020-03-25 20:17:52 -0700560 if needs_comma {
David Tolnay7db73692019-10-20 14:51:12 -0400561 write!(out, ", ");
562 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700563 write_return_type(out, &sig.ret);
David Tolnay7db73692019-10-20 14:51:12 -0400564 write!(out, "*return$");
David Tolnay75dca2e2020-03-25 20:17:52 -0700565 needs_comma = true;
566 }
567 if indirect_call {
568 if needs_comma {
569 write!(out, ", ");
570 }
571 write!(out, "void *");
David Tolnay7db73692019-10-20 14:51:12 -0400572 }
573 writeln!(out, ") noexcept;");
574}
575
David Tolnaya7c2ea12020-10-30 21:32:53 -0700576fn write_rust_function_shim(out: &mut OutFile, efn: &ExternFn) {
David Tolnay7db73692019-10-20 14:51:12 -0400577 for line in efn.doc.to_string().lines() {
578 writeln!(out, "//{}", line);
579 }
David Tolnaya73853b2020-04-20 01:19:56 -0700580 let local_name = match &efn.sig.receiver {
Adrian Taylorc8713432020-10-21 18:20:55 -0700581 None => efn.ident.cxx.ident.to_string(),
582 Some(receiver) => format!(
583 "{}::{}",
David Tolnaya7c2ea12020-10-30 21:32:53 -0700584 out.types.resolve(&receiver.ty).ident,
Adrian Taylorc8713432020-10-21 18:20:55 -0700585 efn.ident.cxx.ident
586 ),
David Tolnaya73853b2020-04-20 01:19:56 -0700587 };
David Tolnaya7c2ea12020-10-30 21:32:53 -0700588 let invoke = mangle::extern_fn(efn, out.types);
David Tolnay75dca2e2020-03-25 20:17:52 -0700589 let indirect_call = false;
David Tolnaya7c2ea12020-10-30 21:32:53 -0700590 write_rust_function_shim_impl(out, &local_name, efn, &invoke, indirect_call);
David Tolnay75dca2e2020-03-25 20:17:52 -0700591}
592
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700593fn write_rust_function_shim_decl(
David Tolnay75dca2e2020-03-25 20:17:52 -0700594 out: &mut OutFile,
David Tolnaya73853b2020-04-20 01:19:56 -0700595 local_name: &str,
David Tolnay75dca2e2020-03-25 20:17:52 -0700596 sig: &Signature,
David Tolnay75dca2e2020-03-25 20:17:52 -0700597 indirect_call: bool,
598) {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700599 write_return_type(out, &sig.ret);
David Tolnay75dca2e2020-03-25 20:17:52 -0700600 write!(out, "{}(", local_name);
601 for (i, arg) in sig.args.iter().enumerate() {
David Tolnay7db73692019-10-20 14:51:12 -0400602 if i > 0 {
603 write!(out, ", ");
604 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700605 write_type_space(out, &arg.ty);
David Tolnay7db73692019-10-20 14:51:12 -0400606 write!(out, "{}", arg.ident);
607 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700608 if indirect_call {
609 if !sig.args.is_empty() {
610 write!(out, ", ");
611 }
612 write!(out, "void *extern$");
613 }
David Tolnay1e548172020-03-16 13:37:09 -0700614 write!(out, ")");
David Tolnay86710612020-04-20 00:30:32 -0700615 if let Some(receiver) = &sig.receiver {
616 if receiver.mutability.is_none() {
617 write!(out, " const");
618 }
619 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700620 if !sig.throws {
David Tolnay1e548172020-03-16 13:37:09 -0700621 write!(out, " noexcept");
622 }
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700623}
624
625fn write_rust_function_shim_impl(
626 out: &mut OutFile,
David Tolnaya73853b2020-04-20 01:19:56 -0700627 local_name: &str,
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700628 sig: &Signature,
David Tolnay891061b2020-04-19 22:42:33 -0700629 invoke: &Symbol,
Joel Galensonc1c4e7a2020-04-15 10:21:00 -0700630 indirect_call: bool,
631) {
632 if out.header && sig.receiver.is_some() {
633 // We've already defined this inside the struct.
634 return;
635 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700636 write_rust_function_shim_decl(out, local_name, sig, indirect_call);
David Tolnay7db73692019-10-20 14:51:12 -0400637 if out.header {
638 writeln!(out, ";");
David Tolnay439cde22020-04-20 00:46:25 -0700639 return;
David Tolnay7db73692019-10-20 14:51:12 -0400640 }
David Tolnay439cde22020-04-20 00:46:25 -0700641 writeln!(out, " {{");
642 for arg in &sig.args {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700643 if arg.ty != RustString && out.types.needs_indirect_abi(&arg.ty) {
David Tolnay439cde22020-04-20 00:46:25 -0700644 out.include.utility = true;
David Tolnay74d6d512020-10-31 22:22:03 -0700645 out.builtin.manually_drop = true;
David Tolnay439cde22020-04-20 00:46:25 -0700646 write!(out, " ::rust::ManuallyDrop<");
David Tolnaya7c2ea12020-10-30 21:32:53 -0700647 write_type(out, &arg.ty);
David Tolnay439cde22020-04-20 00:46:25 -0700648 writeln!(out, "> {}$(::std::move({0}));", arg.ident);
649 }
650 }
651 write!(out, " ");
David Tolnaya7c2ea12020-10-30 21:32:53 -0700652 let indirect_return = indirect_return(sig, out.types);
David Tolnay439cde22020-04-20 00:46:25 -0700653 if indirect_return {
David Tolnay74d6d512020-10-31 22:22:03 -0700654 out.builtin.maybe_uninit = true;
David Tolnay439cde22020-04-20 00:46:25 -0700655 write!(out, "::rust::MaybeUninit<");
David Tolnaya7c2ea12020-10-30 21:32:53 -0700656 write_type(out, sig.ret.as_ref().unwrap());
David Tolnay439cde22020-04-20 00:46:25 -0700657 writeln!(out, "> return$;");
658 write!(out, " ");
659 } else if let Some(ret) = &sig.ret {
660 write!(out, "return ");
661 match ret {
662 Type::RustBox(_) => {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700663 write_type(out, ret);
David Tolnay439cde22020-04-20 00:46:25 -0700664 write!(out, "::from_raw(");
665 }
666 Type::UniquePtr(_) => {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700667 write_type(out, ret);
David Tolnay439cde22020-04-20 00:46:25 -0700668 write!(out, "(");
669 }
670 Type::Ref(_) => write!(out, "*"),
David Tolnay74d6d512020-10-31 22:22:03 -0700671 Type::Str(_) => {
672 out.builtin.rust_str_new_unchecked = true;
673 write!(out, "::rust::impl<::rust::Str>::new_unchecked(");
674 }
David Tolnay36aa9e02020-10-31 23:08:21 -0700675 Type::SliceRefU8(_) => {
676 out.builtin.rust_slice_new = true;
677 write!(out, "::rust::impl<::rust::Slice<uint8_t>>::slice(");
678 }
David Tolnay439cde22020-04-20 00:46:25 -0700679 _ => {}
680 }
681 }
682 if sig.throws {
David Tolnay919085c2020-10-31 22:32:22 -0700683 out.builtin.ptr_len = true;
David Tolnayd68dfa82020-10-31 16:01:24 -0700684 write!(out, "::rust::repr::PtrLen error$ = ");
David Tolnay439cde22020-04-20 00:46:25 -0700685 }
686 write!(out, "{}(", invoke);
687 if sig.receiver.is_some() {
688 write!(out, "*this");
689 }
690 for (i, arg) in sig.args.iter().enumerate() {
691 if i > 0 || sig.receiver.is_some() {
692 write!(out, ", ");
693 }
694 match &arg.ty {
David Tolnay74d6d512020-10-31 22:22:03 -0700695 Type::Str(_) => {
696 out.builtin.rust_str_repr = true;
697 write!(out, "::rust::impl<::rust::Str>::repr(");
698 }
David Tolnay36aa9e02020-10-31 23:08:21 -0700699 Type::SliceRefU8(_) => {
700 out.builtin.rust_slice_repr = true;
701 write!(out, "::rust::impl<::rust::Slice<uint8_t>>::repr(");
702 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700703 ty if out.types.needs_indirect_abi(ty) => write!(out, "&"),
David Tolnay439cde22020-04-20 00:46:25 -0700704 _ => {}
705 }
706 write!(out, "{}", arg.ident);
707 match &arg.ty {
708 Type::RustBox(_) => write!(out, ".into_raw()"),
709 Type::UniquePtr(_) => write!(out, ".release()"),
David Tolnay0356d332020-10-31 19:46:41 -0700710 Type::Str(_) | Type::SliceRefU8(_) => write!(out, ")"),
David Tolnaya7c2ea12020-10-30 21:32:53 -0700711 ty if ty != RustString && out.types.needs_indirect_abi(ty) => write!(out, "$.value"),
David Tolnay439cde22020-04-20 00:46:25 -0700712 _ => {}
713 }
714 }
715 if indirect_return {
716 if !sig.args.is_empty() {
717 write!(out, ", ");
718 }
719 write!(out, "&return$.value");
720 }
721 if indirect_call {
722 if !sig.args.is_empty() || indirect_return {
723 write!(out, ", ");
724 }
725 write!(out, "extern$");
726 }
727 write!(out, ")");
David Tolnay22602b42020-09-21 18:04:05 -0400728 if !indirect_return {
729 if let Some(ret) = &sig.ret {
David Tolnay36aa9e02020-10-31 23:08:21 -0700730 if let Type::RustBox(_) | Type::UniquePtr(_) | Type::Str(_) | Type::SliceRefU8(_) = ret
731 {
David Tolnay22602b42020-09-21 18:04:05 -0400732 write!(out, ")");
733 }
David Tolnay439cde22020-04-20 00:46:25 -0700734 }
735 }
736 writeln!(out, ";");
737 if sig.throws {
David Tolnay74d6d512020-10-31 22:22:03 -0700738 out.include.exception = true;
739 out.builtin.rust_error = true;
David Tolnayd68dfa82020-10-31 16:01:24 -0700740 writeln!(out, " if (error$.ptr) {{");
David Tolnay84ddf9e2020-10-31 15:36:48 -0700741 writeln!(out, " throw ::rust::impl<::rust::Error>::error(error$);");
David Tolnay439cde22020-04-20 00:46:25 -0700742 writeln!(out, " }}");
743 }
744 if indirect_return {
745 out.include.utility = true;
746 writeln!(out, " return ::std::move(return$.value);");
747 }
748 writeln!(out, "}}");
David Tolnay7db73692019-10-20 14:51:12 -0400749}
750
David Tolnaya7c2ea12020-10-30 21:32:53 -0700751fn write_return_type(out: &mut OutFile, ty: &Option<Type>) {
David Tolnay7db73692019-10-20 14:51:12 -0400752 match ty {
753 None => write!(out, "void "),
David Tolnaya7c2ea12020-10-30 21:32:53 -0700754 Some(ty) => write_type_space(out, ty),
David Tolnay7db73692019-10-20 14:51:12 -0400755 }
756}
757
David Tolnay75dca2e2020-03-25 20:17:52 -0700758fn indirect_return(sig: &Signature, types: &Types) -> bool {
759 sig.ret
David Tolnay277e3cc2020-03-17 00:11:01 -0700760 .as_ref()
David Tolnay75dca2e2020-03-25 20:17:52 -0700761 .map_or(false, |ret| sig.throws || types.needs_indirect_abi(ret))
David Tolnay277e3cc2020-03-17 00:11:01 -0700762}
763
David Tolnaya7c2ea12020-10-30 21:32:53 -0700764fn write_indirect_return_type(out: &mut OutFile, ty: &Type) {
David Tolnay99642622020-03-25 13:07:35 -0700765 match ty {
766 Type::RustBox(ty) | Type::UniquePtr(ty) => {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700767 write_type_space(out, &ty.inner);
David Tolnay99642622020-03-25 13:07:35 -0700768 write!(out, "*");
769 }
770 Type::Ref(ty) => {
771 if ty.mutability.is_none() {
772 write!(out, "const ");
773 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700774 write_type(out, &ty.inner);
David Tolnay99642622020-03-25 13:07:35 -0700775 write!(out, " *");
776 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700777 _ => write_type(out, ty),
David Tolnay99642622020-03-25 13:07:35 -0700778 }
779}
780
David Tolnaya7c2ea12020-10-30 21:32:53 -0700781fn write_indirect_return_type_space(out: &mut OutFile, ty: &Type) {
782 write_indirect_return_type(out, ty);
David Tolnay99642622020-03-25 13:07:35 -0700783 match ty {
784 Type::RustBox(_) | Type::UniquePtr(_) | Type::Ref(_) => {}
Adrian Taylorf5dd5522020-04-13 16:50:14 -0700785 Type::Str(_) | Type::SliceRefU8(_) => write!(out, " "),
David Tolnay99642622020-03-25 13:07:35 -0700786 _ => write_space_after_type(out, ty),
787 }
788}
789
David Tolnaya7c2ea12020-10-30 21:32:53 -0700790fn write_extern_return_type_space(out: &mut OutFile, ty: &Option<Type>) {
David Tolnay7db73692019-10-20 14:51:12 -0400791 match ty {
792 Some(Type::RustBox(ty)) | Some(Type::UniquePtr(ty)) => {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700793 write_type_space(out, &ty.inner);
David Tolnay7db73692019-10-20 14:51:12 -0400794 write!(out, "*");
795 }
David Tolnay4a441222020-01-25 16:24:27 -0800796 Some(Type::Ref(ty)) => {
797 if ty.mutability.is_none() {
798 write!(out, "const ");
799 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700800 write_type(out, &ty.inner);
David Tolnay4a441222020-01-25 16:24:27 -0800801 write!(out, " *");
802 }
David Tolnay36aa9e02020-10-31 23:08:21 -0700803 Some(Type::Str(_)) | Some(Type::SliceRefU8(_)) => {
David Tolnay919085c2020-10-31 22:32:22 -0700804 out.builtin.ptr_len = true;
805 write!(out, "::rust::repr::PtrLen ");
806 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700807 Some(ty) if out.types.needs_indirect_abi(ty) => write!(out, "void "),
808 _ => write_return_type(out, ty),
David Tolnay7db73692019-10-20 14:51:12 -0400809 }
810}
811
David Tolnaya7c2ea12020-10-30 21:32:53 -0700812fn write_extern_arg(out: &mut OutFile, arg: &Var) {
David Tolnay7db73692019-10-20 14:51:12 -0400813 match &arg.ty {
David Tolnay4377a9e2020-04-24 15:20:26 -0700814 Type::RustBox(ty) | Type::UniquePtr(ty) | Type::CxxVector(ty) => {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700815 write_type_space(out, &ty.inner);
David Tolnay7db73692019-10-20 14:51:12 -0400816 write!(out, "*");
817 }
David Tolnay36aa9e02020-10-31 23:08:21 -0700818 Type::Str(_) | Type::SliceRefU8(_) => {
David Tolnay919085c2020-10-31 22:32:22 -0700819 out.builtin.ptr_len = true;
820 write!(out, "::rust::repr::PtrLen ");
821 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700822 _ => write_type_space(out, &arg.ty),
David Tolnay7db73692019-10-20 14:51:12 -0400823 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700824 if out.types.needs_indirect_abi(&arg.ty) {
David Tolnay7db73692019-10-20 14:51:12 -0400825 write!(out, "*");
826 }
827 write!(out, "{}", arg.ident);
828}
829
David Tolnaya7c2ea12020-10-30 21:32:53 -0700830fn write_type(out: &mut OutFile, ty: &Type) {
David Tolnay7db73692019-10-20 14:51:12 -0400831 match ty {
Adrian Taylorc8713432020-10-21 18:20:55 -0700832 Type::Ident(ident) => match Atom::from(&ident.rust) {
David Tolnayf6a89f22020-05-10 23:39:27 -0700833 Some(atom) => write_atom(out, atom),
David Tolnaya7c2ea12020-10-30 21:32:53 -0700834 None => write!(out, "{}", out.types.resolve(ident).to_fully_qualified()),
David Tolnay7db73692019-10-20 14:51:12 -0400835 },
836 Type::RustBox(ty) => {
David Tolnay750755e2020-03-01 13:04:08 -0800837 write!(out, "::rust::Box<");
David Tolnaya7c2ea12020-10-30 21:32:53 -0700838 write_type(out, &ty.inner);
David Tolnay7db73692019-10-20 14:51:12 -0400839 write!(out, ">");
840 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700841 Type::RustVec(ty) => {
842 write!(out, "::rust::Vec<");
David Tolnaya7c2ea12020-10-30 21:32:53 -0700843 write_type(out, &ty.inner);
Myron Ahneba35cf2020-02-05 19:41:51 +0700844 write!(out, ">");
845 }
David Tolnay7db73692019-10-20 14:51:12 -0400846 Type::UniquePtr(ptr) => {
David Tolnay7e219b82020-03-01 13:14:51 -0800847 write!(out, "::std::unique_ptr<");
David Tolnaya7c2ea12020-10-30 21:32:53 -0700848 write_type(out, &ptr.inner);
David Tolnay7db73692019-10-20 14:51:12 -0400849 write!(out, ">");
850 }
David Tolnay4377a9e2020-04-24 15:20:26 -0700851 Type::CxxVector(ty) => {
Myron Ahneba35cf2020-02-05 19:41:51 +0700852 write!(out, "::std::vector<");
David Tolnaya7c2ea12020-10-30 21:32:53 -0700853 write_type(out, &ty.inner);
Myron Ahneba35cf2020-02-05 19:41:51 +0700854 write!(out, ">");
855 }
David Tolnay7db73692019-10-20 14:51:12 -0400856 Type::Ref(r) => {
857 if r.mutability.is_none() {
858 write!(out, "const ");
859 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700860 write_type(out, &r.inner);
David Tolnay7db73692019-10-20 14:51:12 -0400861 write!(out, " &");
862 }
Adrian Taylorf5dd5522020-04-13 16:50:14 -0700863 Type::Slice(_) => {
864 // For now, only U8 slices are supported, which are covered separately below
865 unreachable!()
866 }
David Tolnay7db73692019-10-20 14:51:12 -0400867 Type::Str(_) => {
David Tolnay750755e2020-03-01 13:04:08 -0800868 write!(out, "::rust::Str");
David Tolnay7db73692019-10-20 14:51:12 -0400869 }
Adrian Taylorf5dd5522020-04-13 16:50:14 -0700870 Type::SliceRefU8(_) => {
871 write!(out, "::rust::Slice<uint8_t>");
872 }
David Tolnay75dca2e2020-03-25 20:17:52 -0700873 Type::Fn(f) => {
874 write!(out, "::rust::{}<", if f.throws { "TryFn" } else { "Fn" });
875 match &f.ret {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700876 Some(ret) => write_type(out, ret),
David Tolnay75dca2e2020-03-25 20:17:52 -0700877 None => write!(out, "void"),
878 }
879 write!(out, "(");
880 for (i, arg) in f.args.iter().enumerate() {
881 if i > 0 {
882 write!(out, ", ");
883 }
David Tolnaya7c2ea12020-10-30 21:32:53 -0700884 write_type(out, &arg.ty);
David Tolnay75dca2e2020-03-25 20:17:52 -0700885 }
886 write!(out, ")>");
887 }
David Tolnay2fb14e92020-03-15 23:11:38 -0700888 Type::Void(_) => unreachable!(),
David Tolnay7db73692019-10-20 14:51:12 -0400889 }
890}
891
David Tolnayf6a89f22020-05-10 23:39:27 -0700892fn write_atom(out: &mut OutFile, atom: Atom) {
893 match atom {
894 Bool => write!(out, "bool"),
895 U8 => write!(out, "uint8_t"),
896 U16 => write!(out, "uint16_t"),
897 U32 => write!(out, "uint32_t"),
898 U64 => write!(out, "uint64_t"),
899 Usize => write!(out, "size_t"),
900 I8 => write!(out, "int8_t"),
901 I16 => write!(out, "int16_t"),
902 I32 => write!(out, "int32_t"),
903 I64 => write!(out, "int64_t"),
904 Isize => write!(out, "::rust::isize"),
905 F32 => write!(out, "float"),
906 F64 => write!(out, "double"),
907 CxxString => write!(out, "::std::string"),
908 RustString => write!(out, "::rust::String"),
909 }
910}
911
David Tolnaya7c2ea12020-10-30 21:32:53 -0700912fn write_type_space(out: &mut OutFile, ty: &Type) {
913 write_type(out, ty);
David Tolnay99642622020-03-25 13:07:35 -0700914 write_space_after_type(out, ty);
915}
916
917fn write_space_after_type(out: &mut OutFile, ty: &Type) {
David Tolnay7db73692019-10-20 14:51:12 -0400918 match ty {
David Tolnayeb952ba2020-04-14 15:02:24 -0700919 Type::Ident(_)
920 | Type::RustBox(_)
921 | Type::UniquePtr(_)
922 | Type::Str(_)
David Tolnay4377a9e2020-04-24 15:20:26 -0700923 | Type::CxxVector(_)
Myron Ahneba35cf2020-02-05 19:41:51 +0700924 | Type::RustVec(_)
David Tolnayeb952ba2020-04-14 15:02:24 -0700925 | Type::SliceRefU8(_)
926 | Type::Fn(_) => write!(out, " "),
David Tolnay7db73692019-10-20 14:51:12 -0400927 Type::Ref(_) => {}
Adrian Taylorf5dd5522020-04-13 16:50:14 -0700928 Type::Void(_) | Type::Slice(_) => unreachable!(),
David Tolnay7db73692019-10-20 14:51:12 -0400929 }
930}
931
David Tolnaycd08c442020-04-25 10:16:33 -0700932// Only called for legal referent types of unique_ptr and element types of
933// std::vector and Vec.
Adrian Taylorc8713432020-10-21 18:20:55 -0700934fn to_typename(ty: &Type, types: &Types) -> String {
David Tolnay2eca4a02020-04-24 19:50:51 -0700935 match ty {
Adrian Taylorc8713432020-10-21 18:20:55 -0700936 Type::Ident(ident) => types.resolve(&ident).to_fully_qualified(),
937 Type::CxxVector(ptr) => format!("::std::vector<{}>", to_typename(&ptr.inner, types)),
David Tolnaycd08c442020-04-25 10:16:33 -0700938 _ => unreachable!(),
David Tolnay2eca4a02020-04-24 19:50:51 -0700939 }
940}
941
David Tolnayacdf20a2020-04-25 12:40:53 -0700942// Only called for legal referent types of unique_ptr and element types of
943// std::vector and Vec.
Adrian Taylorc8713432020-10-21 18:20:55 -0700944fn to_mangled(ty: &Type, types: &Types) -> Symbol {
David Tolnaybae50ef2020-04-25 12:38:41 -0700945 match ty {
Adrian Taylorc8713432020-10-21 18:20:55 -0700946 Type::Ident(ident) => ident.to_symbol(types),
947 Type::CxxVector(ptr) => to_mangled(&ptr.inner, types).prefix_with("std$vector$"),
David Tolnayacdf20a2020-04-25 12:40:53 -0700948 _ => unreachable!(),
David Tolnaybae50ef2020-04-25 12:38:41 -0700949 }
950}
951
David Tolnaya7c2ea12020-10-30 21:32:53 -0700952fn write_generic_instantiations(out: &mut OutFile) {
David Tolnay078c90f2020-11-01 13:31:08 -0800953 out.set_namespace(Default::default());
David Tolnay0c033e32020-11-01 15:15:48 -0800954 out.begin_block(Block::ExternC);
David Tolnaya7c2ea12020-10-30 21:32:53 -0700955 for ty in out.types {
David Tolnay7db73692019-10-20 14:51:12 -0400956 if let Type::RustBox(ty) = ty {
957 if let Type::Ident(inner) = &ty.inner {
958 out.next_section();
David Tolnaya7c2ea12020-10-30 21:32:53 -0700959 write_rust_box_extern(out, &out.types.resolve(&inner));
David Tolnay7db73692019-10-20 14:51:12 -0400960 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700961 } else if let Type::RustVec(ty) = ty {
David Tolnay6787be62020-04-25 11:01:02 -0700962 if let Type::Ident(inner) = &ty.inner {
Adrian Taylorc8713432020-10-21 18:20:55 -0700963 if Atom::from(&inner.rust).is_none() {
David Tolnay6787be62020-04-25 11:01:02 -0700964 out.next_section();
David Tolnaya7c2ea12020-10-30 21:32:53 -0700965 write_rust_vec_extern(out, inner);
David Tolnay6787be62020-04-25 11:01:02 -0700966 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700967 }
David Tolnay7db73692019-10-20 14:51:12 -0400968 } else if let Type::UniquePtr(ptr) = ty {
969 if let Type::Ident(inner) = &ptr.inner {
Adrian Taylorc8713432020-10-21 18:20:55 -0700970 if Atom::from(&inner.rust).is_none()
David Tolnaya7c2ea12020-10-30 21:32:53 -0700971 && (!out.types.aliases.contains_key(&inner.rust)
972 || out.types.explicit_impls.contains(ty))
David Tolnay7e69f892020-10-03 22:20:22 -0700973 {
David Tolnay7db73692019-10-20 14:51:12 -0400974 out.next_section();
David Tolnaya7c2ea12020-10-30 21:32:53 -0700975 write_unique_ptr(out, inner);
Myron Ahneba35cf2020-02-05 19:41:51 +0700976 }
977 }
David Tolnay4377a9e2020-04-24 15:20:26 -0700978 } else if let Type::CxxVector(ptr) = ty {
Myron Ahneba35cf2020-02-05 19:41:51 +0700979 if let Type::Ident(inner) = &ptr.inner {
Adrian Taylorc8713432020-10-21 18:20:55 -0700980 if Atom::from(&inner.rust).is_none()
David Tolnaya7c2ea12020-10-30 21:32:53 -0700981 && (!out.types.aliases.contains_key(&inner.rust)
982 || out.types.explicit_impls.contains(ty))
David Tolnay7e69f892020-10-03 22:20:22 -0700983 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700984 out.next_section();
David Tolnaya7c2ea12020-10-30 21:32:53 -0700985 write_cxx_vector(out, ty, inner);
David Tolnay7db73692019-10-20 14:51:12 -0400986 }
987 }
988 }
989 }
David Tolnay0c033e32020-11-01 15:15:48 -0800990 out.end_block(Block::ExternC);
David Tolnay7db73692019-10-20 14:51:12 -0400991
David Tolnay0c033e32020-11-01 15:15:48 -0800992 out.begin_block(Block::Namespace("rust"));
993 out.begin_block(Block::InlineNamespace("cxxbridge05"));
David Tolnaya7c2ea12020-10-30 21:32:53 -0700994 for ty in out.types {
David Tolnay7db73692019-10-20 14:51:12 -0400995 if let Type::RustBox(ty) = ty {
996 if let Type::Ident(inner) = &ty.inner {
David Tolnaya7c2ea12020-10-30 21:32:53 -0700997 write_rust_box_impl(out, &out.types.resolve(&inner));
David Tolnay7db73692019-10-20 14:51:12 -0400998 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700999 } else if let Type::RustVec(ty) = ty {
David Tolnay6787be62020-04-25 11:01:02 -07001000 if let Type::Ident(inner) = &ty.inner {
Adrian Taylorc8713432020-10-21 18:20:55 -07001001 if Atom::from(&inner.rust).is_none() {
David Tolnaya7c2ea12020-10-30 21:32:53 -07001002 write_rust_vec_impl(out, inner);
David Tolnay6787be62020-04-25 11:01:02 -07001003 }
Myron Ahneba35cf2020-02-05 19:41:51 +07001004 }
David Tolnay7db73692019-10-20 14:51:12 -04001005 }
1006 }
David Tolnay0c033e32020-11-01 15:15:48 -08001007 out.end_block(Block::InlineNamespace("cxxbridge05"));
1008 out.end_block(Block::Namespace("rust"));
David Tolnay7db73692019-10-20 14:51:12 -04001009}
1010
Adrian Taylorc8713432020-10-21 18:20:55 -07001011fn write_rust_box_extern(out: &mut OutFile, ident: &CppName) {
1012 let inner = ident.to_fully_qualified();
1013 let instance = ident.to_symbol();
David Tolnay7db73692019-10-20 14:51:12 -04001014
David Tolnay8f16ae72020-10-08 18:21:13 -07001015 writeln!(out, "#ifndef CXXBRIDGE05_RUST_BOX_{}", instance);
1016 writeln!(out, "#define CXXBRIDGE05_RUST_BOX_{}", instance);
David Tolnay7db73692019-10-20 14:51:12 -04001017 writeln!(
1018 out,
David Tolnay8f16ae72020-10-08 18:21:13 -07001019 "void cxxbridge05$box${}$uninit(::rust::Box<{}> *ptr) noexcept;",
David Tolnay7db73692019-10-20 14:51:12 -04001020 instance, inner,
1021 );
1022 writeln!(
1023 out,
David Tolnay8f16ae72020-10-08 18:21:13 -07001024 "void cxxbridge05$box${}$drop(::rust::Box<{}> *ptr) noexcept;",
David Tolnay7db73692019-10-20 14:51:12 -04001025 instance, inner,
1026 );
David Tolnay8f16ae72020-10-08 18:21:13 -07001027 writeln!(out, "#endif // CXXBRIDGE05_RUST_BOX_{}", instance);
David Tolnay7db73692019-10-20 14:51:12 -04001028}
1029
David Tolnaya7c2ea12020-10-30 21:32:53 -07001030fn write_rust_vec_extern(out: &mut OutFile, element: &ResolvableName) {
David Tolnay6787be62020-04-25 11:01:02 -07001031 let element = Type::Ident(element.clone());
David Tolnaya7c2ea12020-10-30 21:32:53 -07001032 let inner = to_typename(&element, out.types);
1033 let instance = to_mangled(&element, out.types);
Myron Ahneba35cf2020-02-05 19:41:51 +07001034
David Tolnay8f16ae72020-10-08 18:21:13 -07001035 writeln!(out, "#ifndef CXXBRIDGE05_RUST_VEC_{}", instance);
1036 writeln!(out, "#define CXXBRIDGE05_RUST_VEC_{}", instance);
Myron Ahneba35cf2020-02-05 19:41:51 +07001037 writeln!(
1038 out,
David Tolnay8f16ae72020-10-08 18:21:13 -07001039 "void cxxbridge05$rust_vec${}$new(const ::rust::Vec<{}> *ptr) noexcept;",
David Tolnayf97c2d52020-04-25 16:37:48 -07001040 instance, inner,
1041 );
1042 writeln!(
1043 out,
David Tolnay8f16ae72020-10-08 18:21:13 -07001044 "void cxxbridge05$rust_vec${}$drop(::rust::Vec<{}> *ptr) noexcept;",
Myron Ahneba35cf2020-02-05 19:41:51 +07001045 instance, inner,
1046 );
1047 writeln!(
1048 out,
David Tolnay8f16ae72020-10-08 18:21:13 -07001049 "size_t cxxbridge05$rust_vec${}$len(const ::rust::Vec<{}> *ptr) noexcept;",
Myron Ahneba35cf2020-02-05 19:41:51 +07001050 instance, inner,
1051 );
David Tolnay219c0792020-04-24 20:31:37 -07001052 writeln!(
1053 out,
David Tolnay8f16ae72020-10-08 18:21:13 -07001054 "const {} *cxxbridge05$rust_vec${}$data(const ::rust::Vec<{0}> *ptr) noexcept;",
David Tolnay219c0792020-04-24 20:31:37 -07001055 inner, instance,
1056 );
David Tolnay503d0192020-04-24 22:18:56 -07001057 writeln!(
1058 out,
David Tolnay8f16ae72020-10-08 18:21:13 -07001059 "size_t cxxbridge05$rust_vec${}$stride() noexcept;",
David Tolnay503d0192020-04-24 22:18:56 -07001060 instance,
1061 );
David Tolnay8f16ae72020-10-08 18:21:13 -07001062 writeln!(out, "#endif // CXXBRIDGE05_RUST_VEC_{}", instance);
Myron Ahneba35cf2020-02-05 19:41:51 +07001063}
1064
Adrian Taylorc8713432020-10-21 18:20:55 -07001065fn write_rust_box_impl(out: &mut OutFile, ident: &CppName) {
1066 let inner = ident.to_fully_qualified();
1067 let instance = ident.to_symbol();
David Tolnay7db73692019-10-20 14:51:12 -04001068
1069 writeln!(out, "template <>");
David Tolnay324437a2020-03-01 13:02:24 -08001070 writeln!(out, "void Box<{}>::uninit() noexcept {{", inner);
David Tolnay8f16ae72020-10-08 18:21:13 -07001071 writeln!(out, " cxxbridge05$box${}$uninit(this);", instance);
David Tolnay7db73692019-10-20 14:51:12 -04001072 writeln!(out, "}}");
1073
1074 writeln!(out, "template <>");
David Tolnay324437a2020-03-01 13:02:24 -08001075 writeln!(out, "void Box<{}>::drop() noexcept {{", inner);
David Tolnay8f16ae72020-10-08 18:21:13 -07001076 writeln!(out, " cxxbridge05$box${}$drop(this);", instance);
David Tolnay7db73692019-10-20 14:51:12 -04001077 writeln!(out, "}}");
David Tolnay7db73692019-10-20 14:51:12 -04001078}
1079
David Tolnaya7c2ea12020-10-30 21:32:53 -07001080fn write_rust_vec_impl(out: &mut OutFile, element: &ResolvableName) {
David Tolnay6787be62020-04-25 11:01:02 -07001081 let element = Type::Ident(element.clone());
David Tolnaya7c2ea12020-10-30 21:32:53 -07001082 let inner = to_typename(&element, out.types);
1083 let instance = to_mangled(&element, out.types);
David Tolnay4791f1c2020-03-17 21:53:16 -07001084
Myron Ahneba35cf2020-02-05 19:41:51 +07001085 writeln!(out, "template <>");
David Tolnayf97c2d52020-04-25 16:37:48 -07001086 writeln!(out, "Vec<{}>::Vec() noexcept {{", inner);
David Tolnay8f16ae72020-10-08 18:21:13 -07001087 writeln!(out, " cxxbridge05$rust_vec${}$new(this);", instance);
David Tolnayf97c2d52020-04-25 16:37:48 -07001088 writeln!(out, "}}");
1089
1090 writeln!(out, "template <>");
Myron Ahneba35cf2020-02-05 19:41:51 +07001091 writeln!(out, "void Vec<{}>::drop() noexcept {{", inner);
1092 writeln!(
1093 out,
David Tolnay8f16ae72020-10-08 18:21:13 -07001094 " return cxxbridge05$rust_vec${}$drop(this);",
David Tolnay85db5a02020-04-25 13:17:27 -07001095 instance,
Myron Ahneba35cf2020-02-05 19:41:51 +07001096 );
1097 writeln!(out, "}}");
1098
1099 writeln!(out, "template <>");
1100 writeln!(out, "size_t Vec<{}>::size() const noexcept {{", inner);
David Tolnay8f16ae72020-10-08 18:21:13 -07001101 writeln!(out, " return cxxbridge05$rust_vec${}$len(this);", instance);
Myron Ahneba35cf2020-02-05 19:41:51 +07001102 writeln!(out, "}}");
David Tolnay219c0792020-04-24 20:31:37 -07001103
1104 writeln!(out, "template <>");
1105 writeln!(out, "const {} *Vec<{0}>::data() const noexcept {{", inner);
1106 writeln!(
1107 out,
David Tolnay8f16ae72020-10-08 18:21:13 -07001108 " return cxxbridge05$rust_vec${}$data(this);",
David Tolnay219c0792020-04-24 20:31:37 -07001109 instance,
1110 );
1111 writeln!(out, "}}");
David Tolnay503d0192020-04-24 22:18:56 -07001112
1113 writeln!(out, "template <>");
1114 writeln!(out, "size_t Vec<{}>::stride() noexcept {{", inner);
David Tolnay8f16ae72020-10-08 18:21:13 -07001115 writeln!(out, " return cxxbridge05$rust_vec${}$stride();", instance);
David Tolnay503d0192020-04-24 22:18:56 -07001116 writeln!(out, "}}");
Myron Ahneba35cf2020-02-05 19:41:51 +07001117}
1118
David Tolnaya7c2ea12020-10-30 21:32:53 -07001119fn write_unique_ptr(out: &mut OutFile, ident: &ResolvableName) {
David Tolnay63da4d32020-04-25 09:41:12 -07001120 let ty = Type::Ident(ident.clone());
David Tolnaya7c2ea12020-10-30 21:32:53 -07001121 let instance = to_mangled(&ty, out.types);
David Tolnay63da4d32020-04-25 09:41:12 -07001122
David Tolnay8f16ae72020-10-08 18:21:13 -07001123 writeln!(out, "#ifndef CXXBRIDGE05_UNIQUE_PTR_{}", instance);
1124 writeln!(out, "#define CXXBRIDGE05_UNIQUE_PTR_{}", instance);
David Tolnay63da4d32020-04-25 09:41:12 -07001125
David Tolnaya7c2ea12020-10-30 21:32:53 -07001126 write_unique_ptr_common(out, &ty);
David Tolnay63da4d32020-04-25 09:41:12 -07001127
David Tolnay8f16ae72020-10-08 18:21:13 -07001128 writeln!(out, "#endif // CXXBRIDGE05_UNIQUE_PTR_{}", instance);
David Tolnay63da4d32020-04-25 09:41:12 -07001129}
1130
1131// Shared by UniquePtr<T> and UniquePtr<CxxVector<T>>.
David Tolnaya7c2ea12020-10-30 21:32:53 -07001132fn write_unique_ptr_common(out: &mut OutFile, ty: &Type) {
David Tolnay0ecd05a2020-07-29 16:32:03 -07001133 out.include.new = true;
Myron Ahneba35cf2020-02-05 19:41:51 +07001134 out.include.utility = true;
David Tolnaya7c2ea12020-10-30 21:32:53 -07001135 let inner = to_typename(ty, out.types);
1136 let instance = to_mangled(ty, out.types);
David Tolnay7db73692019-10-20 14:51:12 -04001137
David Tolnay63da4d32020-04-25 09:41:12 -07001138 let can_construct_from_value = match ty {
David Tolnayca0f9da2020-10-16 13:16:17 -07001139 // Some aliases are to opaque types; some are to trivial types. We can't
1140 // know at code generation time, so we generate both C++ and Rust side
1141 // bindings for a "new" method anyway. But the Rust code can't be called
1142 // for Opaque types because the 'new' method is not implemented.
1143 Type::Ident(ident) => {
David Tolnaya7c2ea12020-10-30 21:32:53 -07001144 out.types.structs.contains_key(&ident.rust)
1145 || out.types.aliases.contains_key(&ident.rust)
David Tolnayca0f9da2020-10-16 13:16:17 -07001146 }
David Tolnay63da4d32020-04-25 09:41:12 -07001147 _ => false,
1148 };
1149
David Tolnay7db73692019-10-20 14:51:12 -04001150 writeln!(
1151 out,
David Tolnay7e219b82020-03-01 13:14:51 -08001152 "static_assert(sizeof(::std::unique_ptr<{}>) == sizeof(void *), \"\");",
David Tolnay7db73692019-10-20 14:51:12 -04001153 inner,
1154 );
1155 writeln!(
1156 out,
David Tolnay7e219b82020-03-01 13:14:51 -08001157 "static_assert(alignof(::std::unique_ptr<{}>) == alignof(void *), \"\");",
David Tolnay7db73692019-10-20 14:51:12 -04001158 inner,
1159 );
1160 writeln!(
1161 out,
David Tolnay8f16ae72020-10-08 18:21:13 -07001162 "void cxxbridge05$unique_ptr${}$null(::std::unique_ptr<{}> *ptr) noexcept {{",
David Tolnay7db73692019-10-20 14:51:12 -04001163 instance, inner,
1164 );
David Tolnay7e219b82020-03-01 13:14:51 -08001165 writeln!(out, " new (ptr) ::std::unique_ptr<{}>();", inner);
David Tolnay7db73692019-10-20 14:51:12 -04001166 writeln!(out, "}}");
David Tolnay63da4d32020-04-25 09:41:12 -07001167 if can_construct_from_value {
1168 writeln!(
David Tolnay53838912020-04-09 20:56:44 -07001169 out,
David Tolnay8f16ae72020-10-08 18:21:13 -07001170 "void cxxbridge05$unique_ptr${}$new(::std::unique_ptr<{}> *ptr, {} *value) noexcept {{",
David Tolnay53838912020-04-09 20:56:44 -07001171 instance, inner, inner,
1172 );
David Tolnay63da4d32020-04-25 09:41:12 -07001173 writeln!(
1174 out,
1175 " new (ptr) ::std::unique_ptr<{}>(new {}(::std::move(*value)));",
1176 inner, inner,
1177 );
1178 writeln!(out, "}}");
David Tolnay53838912020-04-09 20:56:44 -07001179 }
David Tolnay7db73692019-10-20 14:51:12 -04001180 writeln!(
1181 out,
David Tolnay8f16ae72020-10-08 18:21:13 -07001182 "void cxxbridge05$unique_ptr${}$raw(::std::unique_ptr<{}> *ptr, {} *raw) noexcept {{",
David Tolnay7db73692019-10-20 14:51:12 -04001183 instance, inner, inner,
1184 );
David Tolnay7e219b82020-03-01 13:14:51 -08001185 writeln!(out, " new (ptr) ::std::unique_ptr<{}>(raw);", inner);
David Tolnay7db73692019-10-20 14:51:12 -04001186 writeln!(out, "}}");
1187 writeln!(
1188 out,
David Tolnay8f16ae72020-10-08 18:21:13 -07001189 "const {} *cxxbridge05$unique_ptr${}$get(const ::std::unique_ptr<{}>& ptr) noexcept {{",
David Tolnay7db73692019-10-20 14:51:12 -04001190 inner, instance, inner,
1191 );
1192 writeln!(out, " return ptr.get();");
1193 writeln!(out, "}}");
1194 writeln!(
1195 out,
David Tolnay8f16ae72020-10-08 18:21:13 -07001196 "{} *cxxbridge05$unique_ptr${}$release(::std::unique_ptr<{}>& ptr) noexcept {{",
David Tolnay7db73692019-10-20 14:51:12 -04001197 inner, instance, inner,
1198 );
1199 writeln!(out, " return ptr.release();");
1200 writeln!(out, "}}");
1201 writeln!(
1202 out,
David Tolnay8f16ae72020-10-08 18:21:13 -07001203 "void cxxbridge05$unique_ptr${}$drop(::std::unique_ptr<{}> *ptr) noexcept {{",
David Tolnay7db73692019-10-20 14:51:12 -04001204 instance, inner,
1205 );
1206 writeln!(out, " ptr->~unique_ptr();");
1207 writeln!(out, "}}");
David Tolnay7db73692019-10-20 14:51:12 -04001208}
Myron Ahneba35cf2020-02-05 19:41:51 +07001209
David Tolnaya7c2ea12020-10-30 21:32:53 -07001210fn write_cxx_vector(out: &mut OutFile, vector_ty: &Type, element: &ResolvableName) {
David Tolnay63da4d32020-04-25 09:41:12 -07001211 let element = Type::Ident(element.clone());
David Tolnaya7c2ea12020-10-30 21:32:53 -07001212 let inner = to_typename(&element, out.types);
1213 let instance = to_mangled(&element, out.types);
Myron Ahneba35cf2020-02-05 19:41:51 +07001214
David Tolnay8f16ae72020-10-08 18:21:13 -07001215 writeln!(out, "#ifndef CXXBRIDGE05_VECTOR_{}", instance);
1216 writeln!(out, "#define CXXBRIDGE05_VECTOR_{}", instance);
Myron Ahneba35cf2020-02-05 19:41:51 +07001217 writeln!(
1218 out,
David Tolnay8f16ae72020-10-08 18:21:13 -07001219 "size_t cxxbridge05$std$vector${}$size(const ::std::vector<{}> &s) noexcept {{",
Myron Ahneba35cf2020-02-05 19:41:51 +07001220 instance, inner,
1221 );
1222 writeln!(out, " return s.size();");
1223 writeln!(out, "}}");
Myron Ahneba35cf2020-02-05 19:41:51 +07001224 writeln!(
1225 out,
David Tolnay8f16ae72020-10-08 18:21:13 -07001226 "const {} *cxxbridge05$std$vector${}$get_unchecked(const ::std::vector<{}> &s, size_t pos) noexcept {{",
Myron Ahneba35cf2020-02-05 19:41:51 +07001227 inner, instance, inner,
1228 );
David Tolnayb3fcf7b2020-04-30 22:58:28 -07001229 writeln!(out, " return &s[pos];");
Myron Ahneba35cf2020-02-05 19:41:51 +07001230 writeln!(out, "}}");
David Tolnay63da4d32020-04-25 09:41:12 -07001231
David Tolnaya7c2ea12020-10-30 21:32:53 -07001232 write_unique_ptr_common(out, vector_ty);
David Tolnay63da4d32020-04-25 09:41:12 -07001233
David Tolnay8f16ae72020-10-08 18:21:13 -07001234 writeln!(out, "#endif // CXXBRIDGE05_VECTOR_{}", instance);
Myron Ahneba35cf2020-02-05 19:41:51 +07001235}