blob: bb341a86fcf4b977a779e18730f2f1235227f324 [file] [log] [blame]
Brian Silverman4e662aa2022-05-11 23:10:19 -07001// Copyright 2020 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9mod function_wrapper_cpp;
10mod new_and_delete_prelude;
11pub(crate) mod type_to_cpp;
12
13use crate::{
14 conversion::analysis::fun::{function_wrapper::CppFunctionKind, FnAnalysis},
15 types::{make_ident, QualifiedName},
16 CppCodegenOptions, CppFilePair,
17};
18use autocxx_parser::IncludeCppConfig;
19use indexmap::map::IndexMap as HashMap;
20use indexmap::set::IndexSet as HashSet;
21use itertools::Itertools;
22use std::borrow::Cow;
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070023use type_to_cpp::CppNameMap;
Brian Silverman4e662aa2022-05-11 23:10:19 -070024
25use super::{
26 analysis::{
27 fun::{
28 function_wrapper::{CppFunction, CppFunctionBody},
29 FnPhase, PodAndDepAnalysis,
30 },
31 pod::PodAnalysis,
32 },
33 api::{Api, Provenance, SubclassName, TypeKind},
34 apivec::ApiVec,
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070035 ConvertErrorFromCpp,
Brian Silverman4e662aa2022-05-11 23:10:19 -070036};
37
38#[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Hash)]
39enum Header {
40 System(&'static str),
41 CxxH,
42 CxxgenH,
43 NewDeletePrelude,
44}
45
46impl Header {
47 fn include_stmt(
48 &self,
49 cpp_codegen_options: &CppCodegenOptions,
50 cxxgen_header_name: &str,
51 ) -> String {
52 let blank = "".to_string();
53 match self {
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070054 Self::System(name) => format!("#include <{name}>"),
Brian Silverman4e662aa2022-05-11 23:10:19 -070055 Self::CxxH => {
56 let prefix = cpp_codegen_options.path_to_cxx_h.as_ref().unwrap_or(&blank);
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070057 format!("#include \"{prefix}cxx.h\"")
Brian Silverman4e662aa2022-05-11 23:10:19 -070058 }
59 Self::CxxgenH => {
60 let prefix = cpp_codegen_options
61 .path_to_cxxgen_h
62 .as_ref()
63 .unwrap_or(&blank);
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070064 format!("#include \"{prefix}{cxxgen_header_name}\"")
Brian Silverman4e662aa2022-05-11 23:10:19 -070065 }
66 Header::NewDeletePrelude => new_and_delete_prelude::NEW_AND_DELETE_PRELUDE.to_string(),
67 }
68 }
69
70 fn is_system(&self) -> bool {
71 matches!(self, Header::System(_) | Header::CxxH)
72 }
73}
74
75enum ConversionDirection {
76 RustCallsCpp,
77 CppCallsCpp,
78 CppCallsRust,
79}
80
81/// Some extra snippet of C++ which we (autocxx) need to generate, beyond
82/// that which cxx itself generates.
83#[derive(Default)]
84struct ExtraCpp {
85 type_definition: Option<String>, // are output before main declarations
86 declaration: Option<String>,
87 definition: Option<String>,
88 headers: Vec<Header>,
89 cpp_headers: Vec<Header>,
90}
91
92/// Generates additional C++ glue functions needed by autocxx.
93/// In some ways it would be preferable to be able to pass snippets
94/// of C++ through to `cxx` for inclusion in the C++ file which it
95/// generates, and perhaps we'll explore that in future. But for now,
96/// autocxx generates its own _additional_ C++ files which therefore
97/// need to be built and included in linking procedures.
98pub(crate) struct CppCodeGenerator<'a> {
99 additional_functions: Vec<ExtraCpp>,
100 inclusions: String,
101 original_name_map: CppNameMap,
102 config: &'a IncludeCppConfig,
103 cpp_codegen_options: &'a CppCodegenOptions<'a>,
104 cxxgen_header_name: &'a str,
105}
106
107struct SubclassFunction<'a> {
108 fun: &'a CppFunction,
109 is_pure_virtual: bool,
110}
111
112impl<'a> CppCodeGenerator<'a> {
113 pub(crate) fn generate_cpp_code(
114 inclusions: String,
115 apis: &ApiVec<FnPhase>,
116 config: &'a IncludeCppConfig,
117 cpp_codegen_options: &CppCodegenOptions,
118 cxxgen_header_name: &str,
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700119 ) -> Result<Option<CppFilePair>, ConvertErrorFromCpp> {
Brian Silverman4e662aa2022-05-11 23:10:19 -0700120 let mut gen = CppCodeGenerator {
121 additional_functions: Vec::new(),
122 inclusions,
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700123 original_name_map: CppNameMap::new_from_apis(apis),
Brian Silverman4e662aa2022-05-11 23:10:19 -0700124 config,
125 cpp_codegen_options,
126 cxxgen_header_name,
127 };
128 // The 'filter' on the following line is designed to ensure we don't accidentally
129 // end up out of sync with needs_cpp_codegen
130 gen.add_needs(apis.iter().filter(|api| api.needs_cpp_codegen()))?;
131 Ok(gen.generate())
132 }
133
134 // It's important to keep this in sync with Api::needs_cpp_codegen.
135 fn add_needs<'b>(
136 &mut self,
137 apis: impl Iterator<Item = &'a Api<FnPhase>>,
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700138 ) -> Result<(), ConvertErrorFromCpp> {
Brian Silverman4e662aa2022-05-11 23:10:19 -0700139 let mut constructors_by_subclass: HashMap<SubclassName, Vec<&CppFunction>> = HashMap::new();
140 let mut methods_by_subclass: HashMap<SubclassName, Vec<SubclassFunction>> = HashMap::new();
141 let mut deferred_apis = Vec::new();
142 for api in apis {
143 match &api {
144 Api::StringConstructor { .. } => self.generate_string_constructor(),
145 Api::Function {
146 analysis:
147 FnAnalysis {
148 cpp_wrapper: Some(cpp_wrapper),
149 ignore_reason: Ok(_),
150 externally_callable: true,
151 ..
152 },
153 fun,
154 ..
155 } => {
156 if let Provenance::SynthesizedSubclassConstructor(details) = &fun.provenance {
157 constructors_by_subclass
158 .entry(details.subclass.clone())
159 .or_default()
160 .push(&details.cpp_impl);
161 }
162 self.generate_cpp_function(cpp_wrapper)?
163 }
164 Api::ConcreteType {
165 rs_definition,
166 cpp_definition,
167 ..
168 } => {
169 let effective_cpp_definition = match rs_definition {
170 Some(rs_definition) => {
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700171 Cow::Owned(self.original_name_map.type_to_cpp(rs_definition)?)
Brian Silverman4e662aa2022-05-11 23:10:19 -0700172 }
173 None => Cow::Borrowed(cpp_definition),
174 };
175
176 self.generate_typedef(api.name(), &effective_cpp_definition)
177 }
178 Api::CType { typename, .. } => self.generate_ctype_typedef(typename),
179 Api::Subclass { .. } => deferred_apis.push(api),
180 Api::RustSubclassFn {
181 subclass, details, ..
182 } => {
183 methods_by_subclass
184 .entry(subclass.clone())
185 .or_default()
186 .push(SubclassFunction {
187 fun: &details.cpp_impl,
188 is_pure_virtual: details.is_pure_virtual,
189 });
190 }
191 Api::Struct {
192 name,
193 analysis:
194 PodAndDepAnalysis {
195 pod:
196 PodAnalysis {
197 kind: TypeKind::Pod,
198 ..
199 },
200 ..
201 },
202 ..
203 } => {
204 self.generate_pod_assertion(name.qualified_cpp_name());
205 }
206 _ => panic!("Should have filtered on needs_cpp_codegen"),
207 }
208 }
209
210 for api in deferred_apis.into_iter() {
211 match api {
212 Api::Subclass { name, superclass } => self.generate_subclass(
213 superclass,
214 name,
215 constructors_by_subclass.remove(name).unwrap_or_default(),
216 methods_by_subclass.remove(name).unwrap_or_default(),
217 )?,
218 _ => panic!("Unexpected deferred API"),
219 }
220 }
221 Ok(())
222 }
223
224 fn generate(&self) -> Option<CppFilePair> {
225 if self.additional_functions.is_empty() {
226 None
227 } else {
228 let headers = self.collect_headers(|additional_need| &additional_need.headers);
229 let cpp_headers = self.collect_headers(|additional_need| &additional_need.cpp_headers);
230 let type_definitions = self.concat_additional_items(|x| x.type_definition.as_ref());
231 let declarations = self.concat_additional_items(|x| x.declaration.as_ref());
232 let declarations = format!(
233 "#ifndef __AUTOCXXGEN_H__\n#define __AUTOCXXGEN_H__\n\n{}\n{}\n{}\n{}#endif // __AUTOCXXGEN_H__\n",
234 headers, self.inclusions, type_definitions, declarations
235 );
236 log::info!("Additional C++ decls:\n{}", declarations);
237 let header_name = self
238 .cpp_codegen_options
239 .autocxxgen_header_namer
240 .name_header(self.config.get_mod_name().to_string());
241 let implementation = if self
242 .additional_functions
243 .iter()
244 .any(|x| x.definition.is_some())
245 {
246 let definitions = self.concat_additional_items(|x| x.definition.as_ref());
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700247 let definitions =
248 format!("#include \"{header_name}\"\n{cpp_headers}\n{definitions}");
Brian Silverman4e662aa2022-05-11 23:10:19 -0700249 log::info!("Additional C++ defs:\n{}", definitions);
250 Some(definitions.into_bytes())
251 } else {
252 None
253 };
254 Some(CppFilePair {
255 header: declarations.into_bytes(),
256 implementation,
257 header_name,
258 })
259 }
260 }
261
262 fn collect_headers<F>(&self, filter: F) -> String
263 where
264 F: Fn(&ExtraCpp) -> &[Header],
265 {
266 let cpp_headers: HashSet<_> = self
267 .additional_functions
268 .iter()
269 .flat_map(|x| filter(x).iter())
270 .filter(|x| !self.cpp_codegen_options.suppress_system_headers || !x.is_system())
271 .collect(); // uniqify
272 cpp_headers
273 .iter()
274 .map(|x| x.include_stmt(self.cpp_codegen_options, self.cxxgen_header_name))
275 .join("\n")
276 }
277
278 fn concat_additional_items<F>(&self, field_access: F) -> String
279 where
280 F: FnMut(&ExtraCpp) -> Option<&String>,
281 {
282 let mut s = self
283 .additional_functions
284 .iter()
285 .flat_map(field_access)
286 .join("\n");
287 s.push('\n');
288 s
289 }
290
291 fn generate_pod_assertion(&mut self, name: String) {
292 // These assertions are generated by cxx for trivial ExternTypes but
293 // *only if* such types are used as trivial types in the cxx::bridge.
294 // It's possible for types which we generate to be used even without
295 // passing through the cxx::bridge, and as we generate Drop impls, that
296 // can result in destructors for nested types being called multiple times
297 // if we represent them as trivial types. So generate an extra
298 // assertion to make sure.
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700299 let declaration = Some(format!("static_assert(::rust::IsRelocatable<{name}>::value, \"type {name} should be trivially move constructible and trivially destructible to be used with generate_pod! in autocxx\");"));
Brian Silverman4e662aa2022-05-11 23:10:19 -0700300 self.additional_functions.push(ExtraCpp {
301 declaration,
302 headers: vec![Header::CxxH],
303 ..Default::default()
304 })
305 }
306
307 fn generate_string_constructor(&mut self) {
308 let makestring_name = self.config.get_makestring_name();
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700309 let declaration = Some(format!("inline std::unique_ptr<std::string> {makestring_name}(::rust::Str str) {{ return std::make_unique<std::string>(std::string(str)); }}"));
Brian Silverman4e662aa2022-05-11 23:10:19 -0700310 self.additional_functions.push(ExtraCpp {
311 declaration,
312 headers: vec![
313 Header::System("memory"),
314 Header::System("string"),
315 Header::CxxH,
316 ],
317 ..Default::default()
318 })
319 }
320
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700321 fn generate_cpp_function(&mut self, details: &CppFunction) -> Result<(), ConvertErrorFromCpp> {
Brian Silverman4e662aa2022-05-11 23:10:19 -0700322 self.additional_functions
323 .push(self.generate_cpp_function_inner(
324 details,
325 false,
326 ConversionDirection::RustCallsCpp,
327 false,
328 None,
329 )?);
330 Ok(())
331 }
332
333 fn generate_cpp_function_inner(
334 &self,
335 details: &CppFunction,
336 avoid_this: bool,
337 conversion_direction: ConversionDirection,
338 requires_rust_declarations: bool,
339 force_name: Option<&str>,
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700340 ) -> Result<ExtraCpp, ConvertErrorFromCpp> {
Brian Silverman4e662aa2022-05-11 23:10:19 -0700341 // Even if the original function call is in a namespace,
342 // we generate this wrapper in the global namespace.
343 // We could easily do this the other way round, and when
344 // cxx::bridge comes to support nested namespace mods then
345 // we wil wish to do that to avoid name conflicts. However,
346 // at the moment this is simpler because it avoids us having
347 // to generate namespace blocks in the generated C++.
348 let is_a_method = !avoid_this
349 && matches!(
350 details.kind,
351 CppFunctionKind::Method
352 | CppFunctionKind::ConstMethod
353 | CppFunctionKind::Constructor
354 );
355 let name = match force_name {
356 Some(n) => n.to_string(),
357 None => details.wrapper_function_name.to_string(),
358 };
359 let get_arg_name = |counter: usize| -> String {
360 if is_a_method && counter == 0 {
361 // For method calls that we generate, the first
362 // argument name needs to be such that we recognize
363 // it as a method in the second invocation of
364 // bridge_converter after it's flowed again through
365 // bindgen.
366 // TODO this may not be the case any longer. We
367 // may be able to remove this.
368 "autocxx_gen_this".to_string()
369 } else {
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700370 format!("arg{counter}")
Brian Silverman4e662aa2022-05-11 23:10:19 -0700371 }
372 };
373 // If this returns a non-POD value, we may instead wish to emplace
374 // it into a parameter, let's see.
375 let args: Result<Vec<_>, _> = details
376 .argument_conversion
377 .iter()
378 .enumerate()
379 .map(|(counter, ty)| {
380 Ok(format!(
381 "{} {}",
382 match conversion_direction {
383 ConversionDirection::RustCallsCpp =>
384 ty.unconverted_type(&self.original_name_map)?,
385 ConversionDirection::CppCallsCpp =>
386 ty.converted_type(&self.original_name_map)?,
387 ConversionDirection::CppCallsRust =>
388 ty.inverse().unconverted_type(&self.original_name_map)?,
389 },
390 get_arg_name(counter)
391 ))
392 })
393 .collect();
394 let args = args?.join(", ");
395 let default_return = match details.kind {
396 CppFunctionKind::SynthesizedConstructor => "",
397 _ => "void",
398 };
399 let ret_type = details
400 .return_conversion
401 .as_ref()
402 .and_then(|x| match conversion_direction {
403 ConversionDirection::RustCallsCpp => {
404 if x.populate_return_value() {
405 Some(x.converted_type(&self.original_name_map))
406 } else {
407 None
408 }
409 }
410 ConversionDirection::CppCallsCpp => {
411 Some(x.unconverted_type(&self.original_name_map))
412 }
413 ConversionDirection::CppCallsRust => {
414 Some(x.inverse().converted_type(&self.original_name_map))
415 }
416 })
417 .unwrap_or_else(|| Ok(default_return.to_string()))?;
418 let constness = match details.kind {
419 CppFunctionKind::ConstMethod => " const",
420 _ => "",
421 };
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700422 let declaration = format!("{ret_type} {name}({args}){constness}");
Brian Silverman4e662aa2022-05-11 23:10:19 -0700423 let qualification = if let Some(qualification) = &details.qualification {
424 format!("{}::", qualification.to_cpp_name())
425 } else {
426 "".to_string()
427 };
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700428 let qualified_declaration = format!("{ret_type} {qualification}{name}({args}){constness}");
Brian Silverman4e662aa2022-05-11 23:10:19 -0700429 // Whether there's a placement param in which to put the return value
430 let placement_param = details
431 .argument_conversion
432 .iter()
433 .enumerate()
434 .filter_map(|(counter, conv)| {
435 if conv.is_placement_parameter() {
436 Some(get_arg_name(counter))
437 } else {
438 None
439 }
440 })
441 .next();
442 // Arguments to underlying function call
443 let arg_list: Result<Vec<_>, _> = details
444 .argument_conversion
445 .iter()
446 .enumerate()
447 .map(|(counter, conv)| match conversion_direction {
448 ConversionDirection::RustCallsCpp => {
449 conv.cpp_conversion(&get_arg_name(counter), &self.original_name_map, false)
450 }
451 ConversionDirection::CppCallsCpp => Ok(Some(get_arg_name(counter))),
452 ConversionDirection::CppCallsRust => conv.inverse().cpp_conversion(
453 &get_arg_name(counter),
454 &self.original_name_map,
455 false,
456 ),
457 })
458 .collect();
459 let mut arg_list = arg_list?.into_iter().flatten();
460 let receiver = if is_a_method { arg_list.next() } else { None };
461 if matches!(&details.payload, CppFunctionBody::ConstructSuperclass(_)) {
462 arg_list.next();
463 }
464 let arg_list = if details.pass_obs_field {
465 std::iter::once("*obs".to_string())
466 .chain(arg_list)
467 .join(",")
468 } else {
469 arg_list.join(", ")
470 };
471 let (mut underlying_function_call, field_assignments, need_allocators) = match &details
472 .payload
473 {
474 CppFunctionBody::Cast => (arg_list, "".to_string(), false),
475 CppFunctionBody::PlacementNew(ns, id) => {
476 let ty_id = QualifiedName::new(ns, id.clone());
477 let ty_id = self.namespaced_name(&ty_id);
478 (
479 format!("new ({}) {}({})", receiver.unwrap(), ty_id, arg_list),
480 "".to_string(),
481 false,
482 )
483 }
484 CppFunctionBody::Destructor(ns, id) => {
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700485 let full_name = QualifiedName::new(ns, id.clone());
486 let ty_id = self.original_name_map.get_final_item(&full_name);
487 let is_a_nested_struct = self.original_name_map.get(&full_name).is_some();
488 // This is all super duper fiddly.
489 // All we want to do is call a destructor. Constraints:
490 // * an unnamed struct, e.g. typedef struct { .. } A, does not
491 // have any way of fully qualifying its destructor name.
492 // We have to use a 'using' statement.
493 // * we don't get enough information from bindgen to distinguish
494 // typedef struct { .. } A // unnamed struct
495 // from
496 // struct A { .. } // named struct
497 // * we can only do 'using A::B::C' if 'B' is a namespace,
498 // as opposed to a type with an inner type.
499 // * we can always do 'using C = A::B::C' but then SOME C++
500 // compilers complain that it's unused, iff it's a named struct.
501 let destructor_call = format!("{arg_list}->{ty_id}::~{ty_id}()");
502 let destructor_call = if ns.is_empty() {
503 destructor_call
504 } else {
505 let path = self.original_name_map.map(&full_name);
506 if is_a_nested_struct {
507 format!("{{ using {ty_id} = {path}; {destructor_call}; {ty_id}* pointless; (void)pointless; }}")
508 } else {
509 format!("{{ using {path}; {destructor_call}; }}")
510 }
511 };
512 (destructor_call, "".to_string(), false)
Brian Silverman4e662aa2022-05-11 23:10:19 -0700513 }
514 CppFunctionBody::FunctionCall(ns, id) => match receiver {
515 Some(receiver) => (
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700516 format!("{receiver}.{id}({arg_list})"),
Brian Silverman4e662aa2022-05-11 23:10:19 -0700517 "".to_string(),
518 false,
519 ),
520 None => {
521 let underlying_function_call = ns
522 .into_iter()
523 .cloned()
524 .chain(std::iter::once(id.to_string()))
525 .join("::");
526 (
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700527 format!("{underlying_function_call}({arg_list})"),
Brian Silverman4e662aa2022-05-11 23:10:19 -0700528 "".to_string(),
529 false,
530 )
531 }
532 },
533 CppFunctionBody::StaticMethodCall(ns, ty_id, fn_id) => {
534 let underlying_function_call = ns
535 .into_iter()
536 .cloned()
537 .chain([ty_id.to_string(), fn_id.to_string()].iter().cloned())
538 .join("::");
539 (
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700540 format!("{underlying_function_call}({arg_list})"),
Brian Silverman4e662aa2022-05-11 23:10:19 -0700541 "".to_string(),
542 false,
543 )
544 }
545 CppFunctionBody::ConstructSuperclass(_) => ("".to_string(), arg_list, false),
546 CppFunctionBody::AllocUninitialized(ty) => {
547 let namespaced_ty = self.namespaced_name(ty);
548 (
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700549 format!("new_appropriately<{namespaced_ty}>();",),
Brian Silverman4e662aa2022-05-11 23:10:19 -0700550 "".to_string(),
551 true,
552 )
553 }
554 CppFunctionBody::FreeUninitialized(ty) => (
555 format!("delete_appropriately<{}>(arg0);", self.namespaced_name(ty)),
556 "".to_string(),
557 true,
558 ),
559 };
560 if let Some(ret) = &details.return_conversion {
561 let call_itself = match conversion_direction {
562 ConversionDirection::RustCallsCpp => {
563 ret.cpp_conversion(&underlying_function_call, &self.original_name_map, true)?
564 }
565 ConversionDirection::CppCallsCpp => Some(underlying_function_call),
566 ConversionDirection::CppCallsRust => ret.inverse().cpp_conversion(
567 &underlying_function_call,
568 &self.original_name_map,
569 true,
570 )?,
571 }
572 .expect(
573 "Expected some conversion type for return value which resulted in a parameter name",
574 );
575
576 underlying_function_call = match placement_param {
577 Some(placement_param) => {
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700578 let tyname = self.original_name_map.type_to_cpp(ret.cxxbridge_type())?;
579 format!("new({placement_param}) {tyname}({call_itself})")
Brian Silverman4e662aa2022-05-11 23:10:19 -0700580 }
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700581 None => format!("return {call_itself}"),
Brian Silverman4e662aa2022-05-11 23:10:19 -0700582 };
583 };
584 if !underlying_function_call.is_empty() {
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700585 underlying_function_call = format!("{underlying_function_call};");
Brian Silverman4e662aa2022-05-11 23:10:19 -0700586 }
587 let field_assignments =
588 if let CppFunctionBody::ConstructSuperclass(superclass_name) = &details.payload {
589 let superclass_assignments = if field_assignments.is_empty() {
590 "".to_string()
591 } else {
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700592 format!("{superclass_name}({field_assignments}), ")
Brian Silverman4e662aa2022-05-11 23:10:19 -0700593 };
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700594 format!(": {superclass_assignments}obs(std::move(arg0))")
Brian Silverman4e662aa2022-05-11 23:10:19 -0700595 } else {
596 "".into()
597 };
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700598 let definition_after_sig = format!("{field_assignments} {{ {underlying_function_call} }}",);
Brian Silverman4e662aa2022-05-11 23:10:19 -0700599 let (declaration, definition) = if requires_rust_declarations {
600 (
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700601 Some(format!("{declaration};")),
602 Some(format!("{qualified_declaration} {definition_after_sig}")),
Brian Silverman4e662aa2022-05-11 23:10:19 -0700603 )
604 } else {
605 (
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700606 Some(format!("inline {declaration} {definition_after_sig}")),
Brian Silverman4e662aa2022-05-11 23:10:19 -0700607 None,
608 )
609 };
610 let mut headers = vec![Header::System("memory")];
611 if need_allocators {
612 headers.push(Header::System("stddef.h"));
613 headers.push(Header::NewDeletePrelude);
614 }
615 Ok(ExtraCpp {
616 declaration,
617 definition,
618 headers,
619 ..Default::default()
620 })
621 }
622
623 fn namespaced_name(&self, name: &QualifiedName) -> String {
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700624 self.original_name_map.map(name)
Brian Silverman4e662aa2022-05-11 23:10:19 -0700625 }
626
627 fn generate_ctype_typedef(&mut self, tn: &QualifiedName) {
628 let cpp_name = tn.to_cpp_name();
629 self.generate_typedef(tn, &cpp_name)
630 }
631
632 fn generate_typedef(&mut self, tn: &QualifiedName, definition: &str) {
633 let our_name = tn.get_final_item();
634 self.additional_functions.push(ExtraCpp {
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700635 type_definition: Some(format!("typedef {definition} {our_name};")),
Brian Silverman4e662aa2022-05-11 23:10:19 -0700636 ..Default::default()
637 })
638 }
639
640 fn generate_subclass(
641 &mut self,
642 superclass: &QualifiedName,
643 subclass: &SubclassName,
644 constructors: Vec<&CppFunction>,
645 methods: Vec<SubclassFunction>,
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700646 ) -> Result<(), ConvertErrorFromCpp> {
Brian Silverman4e662aa2022-05-11 23:10:19 -0700647 let holder = subclass.holder();
648 self.additional_functions.push(ExtraCpp {
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700649 type_definition: Some(format!("struct {holder};")),
Brian Silverman4e662aa2022-05-11 23:10:19 -0700650 ..Default::default()
651 });
652 let mut method_decls = Vec::new();
653 for method in methods {
654 // First the method which calls from C++ to Rust
655 let mut fn_impl = self.generate_cpp_function_inner(
656 method.fun,
657 true,
658 ConversionDirection::CppCallsRust,
659 true,
660 Some(&method.fun.original_cpp_name),
661 )?;
662 method_decls.push(fn_impl.declaration.take().unwrap());
663 self.additional_functions.push(fn_impl);
664 // And now the function to be called from Rust for default implementation (calls superclass in C++)
665 if !method.is_pure_virtual {
666 let mut super_method = method.fun.clone();
667 super_method.pass_obs_field = false;
668 super_method.wrapper_function_name = SubclassName::get_super_fn_name(
669 superclass.get_namespace(),
670 &method.fun.wrapper_function_name.to_string(),
671 )
672 .get_final_ident();
673 super_method.payload = CppFunctionBody::StaticMethodCall(
674 superclass.get_namespace().clone(),
675 superclass.get_final_ident(),
676 make_ident(&method.fun.original_cpp_name),
677 );
678 let mut super_fn_impl = self.generate_cpp_function_inner(
679 &super_method,
680 true,
681 ConversionDirection::CppCallsCpp,
682 false,
683 None,
684 )?;
685 method_decls.push(super_fn_impl.declaration.take().unwrap());
686 self.additional_functions.push(super_fn_impl);
687 }
688 }
689 // In future, for each superclass..
690 let super_name = superclass.get_final_item();
691 method_decls.push(format!(
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700692 "const {super_name}& As_{super_name}() const {{ return *this; }}",
Brian Silverman4e662aa2022-05-11 23:10:19 -0700693 ));
694 method_decls.push(format!(
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700695 "{super_name}& As_{super_name}_mut() {{ return *this; }}"
Brian Silverman4e662aa2022-05-11 23:10:19 -0700696 ));
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700697 self.additional_functions.push(ExtraCpp {
698 declaration: Some(format!(
699 "inline std::unique_ptr<{}> {}_As_{}_UniquePtr(std::unique_ptr<{}> u) {{ return std::unique_ptr<{}>(u.release()); }}",
700 superclass.to_cpp_name(), subclass.cpp(), super_name, subclass.cpp(), superclass.to_cpp_name(),
701 )),
702 ..Default::default()
703 });
Brian Silverman4e662aa2022-05-11 23:10:19 -0700704 // And now constructors
705 let mut constructor_decls: Vec<String> = Vec::new();
706 for constructor in constructors {
707 let mut fn_impl = self.generate_cpp_function_inner(
708 constructor,
709 false,
710 ConversionDirection::CppCallsCpp,
711 false,
712 None,
713 )?;
714 let decl = fn_impl.declaration.take().unwrap();
715 constructor_decls.push(decl);
716 self.additional_functions.push(fn_impl);
717 }
718 self.additional_functions.push(ExtraCpp {
719 type_definition: Some(format!(
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700720 "class {} : public {}\n{{\npublic:\n{}\n{}\nvoid {}() const;\nprivate:rust::Box<{}> obs;\nvoid really_remove_ownership();\n\n}};",
Brian Silverman4e662aa2022-05-11 23:10:19 -0700721 subclass.cpp(),
722 superclass.to_cpp_name(),
723 constructor_decls.join("\n"),
724 method_decls.join("\n"),
725 subclass.cpp_remove_ownership(),
726 holder
727 )),
728 definition: Some(format!(
729 "void {}::{}() const {{\nconst_cast<{}*>(this)->really_remove_ownership();\n}}\nvoid {}::really_remove_ownership() {{\nauto new_obs = {}(std::move(obs));\nobs = std::move(new_obs);\n}}\n",
730 subclass.cpp(),
731 subclass.cpp_remove_ownership(),
732 subclass.cpp(),
733 subclass.cpp(),
734 subclass.remove_ownership()
735 )),
736 cpp_headers: vec![Header::CxxgenH],
737 ..Default::default()
738 });
739 Ok(())
740 }
741}