blob: d5da41c5240b923bd713c04e9137cf494748c0af [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
9use indexmap::set::IndexSet as HashSet;
10use std::fmt::Display;
11
Brian Silverman4e662aa2022-05-11 23:10:19 -070012use syn::{
13 parse::Parse,
14 punctuated::Punctuated,
15 token::{Comma, Unsafe},
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070016};
17
18use crate::minisyn::{
Brian Silverman4e662aa2022-05-11 23:10:19 -070019 Attribute, FnArg, Ident, ItemConst, ItemEnum, ItemStruct, ItemType, ItemUse, LitBool, LitInt,
20 Pat, ReturnType, Type, Visibility,
21};
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070022use crate::types::{make_ident, Namespace, QualifiedName};
23use autocxx_parser::{ExternCppType, RustFun, RustPath};
24use itertools::Itertools;
25use quote::ToTokens;
Brian Silverman4e662aa2022-05-11 23:10:19 -070026
27use super::{
28 analysis::{
29 fun::{
30 function_wrapper::{CppFunction, CppFunctionBody, CppFunctionKind},
31 ReceiverMutability,
32 },
33 PointerTreatment,
34 },
35 convert_error::{ConvertErrorWithContext, ErrorContext},
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070036 ConvertErrorFromCpp,
Brian Silverman4e662aa2022-05-11 23:10:19 -070037};
38
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070039#[derive(Copy, Clone, Eq, PartialEq, Debug)]
Brian Silverman4e662aa2022-05-11 23:10:19 -070040pub(crate) enum TypeKind {
41 Pod, // trivial. Can be moved and copied in Rust.
42 NonPod, // has destructor or non-trivial move constructors. Can only hold by UniquePtr
43 Abstract, // has pure virtual members - can't even generate UniquePtr.
44 // It's possible that the type itself isn't pure virtual, but it inherits from
45 // some other type which is pure virtual. Alternatively, maybe we just don't
46 // know if the base class is pure virtual because it wasn't on the allowlist,
47 // in which case we'll err on the side of caution.
48}
49
50/// C++ visibility.
51#[derive(Debug, Clone, PartialEq, Eq, Copy)]
52pub(crate) enum CppVisibility {
53 Public,
54 Protected,
55 Private,
56}
57
58/// Details about a C++ struct.
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070059#[derive(Debug)]
Brian Silverman4e662aa2022-05-11 23:10:19 -070060pub(crate) struct StructDetails {
Brian Silverman4e662aa2022-05-11 23:10:19 -070061 pub(crate) item: ItemStruct,
62 pub(crate) layout: Option<Layout>,
63 pub(crate) has_rvalue_reference_fields: bool,
64}
65
66/// Layout of a type, equivalent to the same type in ir/layout.rs in bindgen
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070067#[derive(Clone, Debug)]
Brian Silverman4e662aa2022-05-11 23:10:19 -070068pub(crate) struct Layout {
69 /// The size (in bytes) of this layout.
70 pub(crate) size: usize,
71 /// The alignment (in bytes) of this layout.
72 pub(crate) align: usize,
73 /// Whether this layout's members are packed or not.
74 pub(crate) packed: bool,
75}
76
77impl Parse for Layout {
78 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
79 let size: LitInt = input.parse()?;
80 input.parse::<syn::token::Comma>()?;
81 let align: LitInt = input.parse()?;
82 input.parse::<syn::token::Comma>()?;
83 let packed: LitBool = input.parse()?;
84 Ok(Layout {
85 size: size.base10_parse().unwrap(),
86 align: align.base10_parse().unwrap(),
87 packed: packed.value(),
88 })
89 }
90}
91
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070092#[derive(Clone, Debug)]
Brian Silverman4e662aa2022-05-11 23:10:19 -070093pub(crate) enum Virtualness {
94 None,
95 Virtual,
96 PureVirtual,
97}
98
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070099#[derive(Clone, Copy, Debug)]
Brian Silverman4e662aa2022-05-11 23:10:19 -0700100pub(crate) enum CastMutability {
101 ConstToConst,
102 MutToConst,
103 MutToMut,
104}
105
106/// Indicates that this function (which is synthetic) should
107/// be a trait implementation rather than a method or free function.
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700108#[derive(Clone, Debug)]
Brian Silverman4e662aa2022-05-11 23:10:19 -0700109pub(crate) enum TraitSynthesis {
110 Cast {
111 to_type: QualifiedName,
112 mutable: CastMutability,
113 },
114 AllocUninitialized(QualifiedName),
115 FreeUninitialized(QualifiedName),
116}
117
118/// Details of a subclass constructor.
119/// TODO: zap this; replace with an extra API.
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700120#[derive(Clone, Debug)]
Brian Silverman4e662aa2022-05-11 23:10:19 -0700121pub(crate) struct SubclassConstructorDetails {
122 pub(crate) subclass: SubclassName,
123 pub(crate) is_trivial: bool,
124 /// Implementation of the constructor _itself_ as distinct
125 /// from any wrapper function we create to call it.
126 pub(crate) cpp_impl: CppFunction,
127}
128
129/// Contributions to traits representing C++ superclasses that
130/// we may implement as Rust subclasses.
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700131#[derive(Clone, Debug)]
Brian Silverman4e662aa2022-05-11 23:10:19 -0700132pub(crate) struct SuperclassMethod {
133 pub(crate) name: Ident,
134 pub(crate) receiver: QualifiedName,
135 pub(crate) params: Punctuated<FnArg, Comma>,
136 pub(crate) param_names: Vec<Pat>,
137 pub(crate) ret_type: ReturnType,
138 pub(crate) receiver_mutability: ReceiverMutability,
139 pub(crate) requires_unsafe: UnsafetyNeeded,
140 pub(crate) is_pure_virtual: bool,
141}
142
143/// Information about references (as opposed to pointers) to be found
144/// within the function signature. This is derived from bindgen annotations
145/// which is why it's not within `FuncToConvert::inputs`
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700146#[derive(Default, Clone, Debug)]
Brian Silverman4e662aa2022-05-11 23:10:19 -0700147pub(crate) struct References {
148 pub(crate) rvalue_ref_params: HashSet<Ident>,
149 pub(crate) ref_params: HashSet<Ident>,
150 pub(crate) ref_return: bool,
151 pub(crate) rvalue_ref_return: bool,
152}
153
154impl References {
155 pub(crate) fn new_with_this_and_return_as_reference() -> Self {
156 Self {
157 ref_return: true,
158 ref_params: [make_ident("this")].into_iter().collect(),
159 ..Default::default()
160 }
161 }
162 pub(crate) fn param_treatment(&self, param: &Ident) -> PointerTreatment {
163 if self.rvalue_ref_params.contains(param) {
164 PointerTreatment::RValueReference
165 } else if self.ref_params.contains(param) {
166 PointerTreatment::Reference
167 } else {
168 PointerTreatment::Pointer
169 }
170 }
171 pub(crate) fn return_treatment(&self) -> PointerTreatment {
172 if self.rvalue_ref_return {
173 PointerTreatment::RValueReference
174 } else if self.ref_return {
175 PointerTreatment::Reference
176 } else {
177 PointerTreatment::Pointer
178 }
179 }
180}
181
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700182#[derive(Clone, Debug)]
Brian Silverman4e662aa2022-05-11 23:10:19 -0700183pub(crate) struct TraitImplSignature {
184 pub(crate) ty: Type,
185 pub(crate) trait_signature: Type,
186 /// The trait is 'unsafe' itself
187 pub(crate) unsafety: Option<Unsafe>,
188}
189
190impl Eq for TraitImplSignature {}
191
192impl PartialEq for TraitImplSignature {
193 fn eq(&self, other: &Self) -> bool {
194 totokens_equal(&self.unsafety, &other.unsafety)
195 && totokens_equal(&self.ty, &other.ty)
196 && totokens_equal(&self.trait_signature, &other.trait_signature)
197 }
198}
199
200fn totokens_to_string<T: ToTokens>(a: &T) -> String {
201 a.to_token_stream().to_string()
202}
203
204fn totokens_equal<T: ToTokens>(a: &T, b: &T) -> bool {
205 totokens_to_string(a) == totokens_to_string(b)
206}
207
208fn hash_totokens<T: ToTokens, H: std::hash::Hasher>(a: &T, state: &mut H) {
209 use std::hash::Hash;
210 totokens_to_string(a).hash(state)
211}
212
213impl std::hash::Hash for TraitImplSignature {
214 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
215 hash_totokens(&self.ty, state);
216 hash_totokens(&self.trait_signature, state);
217 hash_totokens(&self.unsafety, state);
218 }
219}
220
221#[derive(Clone, Debug)]
222pub(crate) enum SpecialMemberKind {
223 DefaultConstructor,
224 CopyConstructor,
225 MoveConstructor,
226 Destructor,
227 AssignmentOperator,
228}
229
230impl Display for SpecialMemberKind {
231 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
232 write!(
233 f,
234 "{}",
235 match self {
236 SpecialMemberKind::DefaultConstructor => "default constructor",
237 SpecialMemberKind::CopyConstructor => "copy constructor",
238 SpecialMemberKind::MoveConstructor => "move constructor",
239 SpecialMemberKind::Destructor => "destructor",
240 SpecialMemberKind::AssignmentOperator => "assignment operator",
241 }
242 )
243 }
244}
245
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700246#[derive(Clone, Debug)]
Brian Silverman4e662aa2022-05-11 23:10:19 -0700247pub(crate) enum Provenance {
248 Bindgen,
249 SynthesizedOther,
250 SynthesizedSubclassConstructor(Box<SubclassConstructorDetails>),
251}
252
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700253/// Whether a function has =delete or =default
254#[derive(Clone, Copy, Debug)]
255pub(crate) enum DeletedOrDefaulted {
256 Neither,
257 Deleted,
258 Defaulted,
259}
260
Brian Silverman4e662aa2022-05-11 23:10:19 -0700261/// A C++ function for which we need to generate bindings, but haven't
262/// yet analyzed in depth. This is little more than a `ForeignItemFn`
263/// broken down into its constituent parts, plus some metadata from the
264/// surrounding bindgen parsing context.
265///
266/// Some parts of the code synthesize additional functions and then
267/// pass them through the same pipeline _as if_ they were discovered
268/// during normal bindgen parsing. If that happens, they'll create one
269/// of these structures, and typically fill in some of the
270/// `synthesized_*` members which are not filled in from bindgen.
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700271#[derive(Clone, Debug)]
Brian Silverman4e662aa2022-05-11 23:10:19 -0700272pub(crate) struct FuncToConvert {
273 pub(crate) provenance: Provenance,
274 pub(crate) ident: Ident,
275 pub(crate) doc_attrs: Vec<Attribute>,
276 pub(crate) inputs: Punctuated<FnArg, Comma>,
277 pub(crate) variadic: bool,
278 pub(crate) output: ReturnType,
279 pub(crate) vis: Visibility,
280 pub(crate) virtualness: Virtualness,
281 pub(crate) cpp_vis: CppVisibility,
282 pub(crate) special_member: Option<SpecialMemberKind>,
283 pub(crate) unused_template_param: bool,
284 pub(crate) references: References,
285 pub(crate) original_name: Option<String>,
286 /// Used for static functions only. For all other functons,
287 /// this is figured out from the receiver type in the inputs.
288 pub(crate) self_ty: Option<QualifiedName>,
289 /// If we wish to use a different 'this' type than the original
290 /// method receiver, e.g. because we're making a subclass
291 /// constructor, fill it in here.
292 pub(crate) synthesized_this_type: Option<QualifiedName>,
293 /// If this function should actually belong to a trait.
294 pub(crate) add_to_trait: Option<TraitSynthesis>,
295 /// If Some, this function didn't really exist in the original
296 /// C++ and instead we're synthesizing it.
297 pub(crate) synthetic_cpp: Option<(CppFunctionBody, CppFunctionKind)>,
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700298 /// =delete
299 pub(crate) is_deleted: DeletedOrDefaulted,
Brian Silverman4e662aa2022-05-11 23:10:19 -0700300}
301
302/// Layers of analysis which may be applied to decorate each API.
303/// See description of the purpose of this trait within `Api`.
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700304pub(crate) trait AnalysisPhase: std::fmt::Debug {
305 type TypedefAnalysis: std::fmt::Debug;
306 type StructAnalysis: std::fmt::Debug;
307 type FunAnalysis: std::fmt::Debug;
Brian Silverman4e662aa2022-05-11 23:10:19 -0700308}
309
310/// No analysis has been applied to this API.
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700311#[derive(std::fmt::Debug)]
Brian Silverman4e662aa2022-05-11 23:10:19 -0700312pub(crate) struct NullPhase;
313
314impl AnalysisPhase for NullPhase {
315 type TypedefAnalysis = ();
316 type StructAnalysis = ();
317 type FunAnalysis = ();
318}
319
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700320#[derive(Clone, Debug)]
Brian Silverman4e662aa2022-05-11 23:10:19 -0700321pub(crate) enum TypedefKind {
322 Use(ItemUse, Box<Type>),
323 Type(ItemType),
324}
325
326/// Name information for an API. This includes the name by
327/// which we know it in Rust, and its C++ name, which may differ.
328#[derive(Clone, Hash, PartialEq, Eq)]
329pub(crate) struct ApiName {
330 pub(crate) name: QualifiedName,
331 cpp_name: Option<String>,
332}
333
334impl ApiName {
335 pub(crate) fn new(ns: &Namespace, id: Ident) -> Self {
336 Self::new_from_qualified_name(QualifiedName::new(ns, id))
337 }
338
339 pub(crate) fn new_with_cpp_name(ns: &Namespace, id: Ident, cpp_name: Option<String>) -> Self {
340 Self {
341 name: QualifiedName::new(ns, id),
342 cpp_name,
343 }
344 }
345
346 pub(crate) fn new_from_qualified_name(name: QualifiedName) -> Self {
347 Self {
348 name,
349 cpp_name: None,
350 }
351 }
352
353 pub(crate) fn new_in_root_namespace(id: Ident) -> Self {
354 Self::new(&Namespace::new(), id)
355 }
356
357 pub(crate) fn cpp_name(&self) -> String {
358 self.cpp_name
359 .as_ref()
360 .cloned()
361 .unwrap_or_else(|| self.name.get_final_item().to_string())
362 }
363
364 pub(crate) fn qualified_cpp_name(&self) -> String {
365 let cpp_name = self.cpp_name();
366 self.name
367 .ns_segment_iter()
368 .cloned()
369 .chain(std::iter::once(cpp_name))
370 .join("::")
371 }
372
373 pub(crate) fn cpp_name_if_present(&self) -> Option<&String> {
374 self.cpp_name.as_ref()
375 }
376}
377
378impl std::fmt::Debug for ApiName {
379 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
380 write!(f, "{}", self.name)?;
381 if let Some(cpp_name) = &self.cpp_name {
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700382 write!(f, " (cpp={cpp_name})")?;
Brian Silverman4e662aa2022-05-11 23:10:19 -0700383 }
384 Ok(())
385 }
386}
387
388/// A name representing a subclass.
389/// This is a simple newtype wrapper which exists such that
390/// we can consistently generate the names of the various subsidiary
391/// types which are required both in C++ and Rust codegen.
392#[derive(Clone, Hash, PartialEq, Eq, Debug)]
393pub(crate) struct SubclassName(pub(crate) ApiName);
394
395impl SubclassName {
396 pub(crate) fn new(id: Ident) -> Self {
397 Self(ApiName::new_in_root_namespace(id))
398 }
399 pub(crate) fn from_holder_name(id: &Ident) -> Self {
400 Self::new(make_ident(id.to_string().strip_suffix("Holder").unwrap()))
401 }
402 pub(crate) fn id(&self) -> Ident {
403 self.0.name.get_final_ident()
404 }
405 /// Generate the name for the 'Holder' type
406 pub(crate) fn holder(&self) -> Ident {
407 self.with_suffix("Holder")
408 }
409 /// Generate the name for the 'Cpp' type
410 pub(crate) fn cpp(&self) -> QualifiedName {
411 let id = self.with_suffix("Cpp");
412 QualifiedName::new(self.0.name.get_namespace(), id)
413 }
414 pub(crate) fn cpp_remove_ownership(&self) -> Ident {
415 self.with_suffix("Cpp_remove_ownership")
416 }
417 pub(crate) fn remove_ownership(&self) -> Ident {
418 self.with_suffix("_remove_ownership")
419 }
420 fn with_suffix(&self, suffix: &str) -> Ident {
421 make_ident(format!("{}{}", self.0.name.get_final_item(), suffix))
422 }
423 pub(crate) fn get_trait_api_name(sup: &QualifiedName, method_name: &str) -> QualifiedName {
424 QualifiedName::new(
425 sup.get_namespace(),
426 make_ident(format!(
427 "{}_{}_trait_item",
428 sup.get_final_item(),
429 method_name
430 )),
431 )
432 }
433 // TODO this and the following should probably include both class name and method name
434 pub(crate) fn get_super_fn_name(superclass_namespace: &Namespace, id: &str) -> QualifiedName {
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700435 let id = make_ident(format!("{id}_super"));
Brian Silverman4e662aa2022-05-11 23:10:19 -0700436 QualifiedName::new(superclass_namespace, id)
437 }
438 pub(crate) fn get_methods_trait_name(superclass_name: &QualifiedName) -> QualifiedName {
439 Self::with_qualified_name_suffix(superclass_name, "methods")
440 }
441 pub(crate) fn get_supers_trait_name(superclass_name: &QualifiedName) -> QualifiedName {
442 Self::with_qualified_name_suffix(superclass_name, "supers")
443 }
444
445 fn with_qualified_name_suffix(name: &QualifiedName, suffix: &str) -> QualifiedName {
446 let id = make_ident(format!("{}_{}", name.get_final_item(), suffix));
447 QualifiedName::new(name.get_namespace(), id)
448 }
449}
450
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700451#[derive(std::fmt::Debug)]
Brian Silverman4e662aa2022-05-11 23:10:19 -0700452/// Different types of API we might encounter.
453///
454/// This type is parameterized over an `ApiAnalysis`. This is any additional
455/// information which we wish to apply to our knowledge of our APIs later
456/// during analysis phases.
457///
458/// This is not as high-level as the equivalent types in `cxx` or `bindgen`,
459/// because sometimes we pass on the `bindgen` output directly in the
460/// Rust codegen output.
461///
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700462/// Any `syn` types represented in this `Api` type, or any of the types from
463/// which it is composed, should be wrapped in `crate::minisyn` equivalents
464/// to avoid excessively verbose `Debug` logging.
Brian Silverman4e662aa2022-05-11 23:10:19 -0700465pub(crate) enum Api<T: AnalysisPhase> {
466 /// A forward declaration, which we mustn't store in a UniquePtr.
467 ForwardDeclaration {
468 name: ApiName,
469 /// If we found a problem parsing this forward declaration, we'll
470 /// ephemerally store the error here, as opposed to immediately
471 /// converting it to an `IgnoredItem`. That's because the
472 /// 'replace_hopeless_typedef_targets' analysis phase needs to spot
473 /// cases where there was an error which was _also_ a forward declaration.
474 /// That phase will then discard such Api::ForwardDeclarations
475 /// and replace them with normal Api::IgnoredItems.
476 err: Option<ConvertErrorWithContext>,
477 },
478 /// We found a typedef to something that we didn't fully understand.
479 /// We'll treat it as an opaque unsized type.
480 OpaqueTypedef {
481 name: ApiName,
482 /// Further store whether this was a typedef to a forward declaration.
483 /// If so we can't allow it to live in a UniquePtr, just like a regular
484 /// Api::ForwardDeclaration.
485 forward_declaration: bool,
486 },
487 /// A synthetic type we've manufactured in order to
488 /// concretize some templated C++ type.
489 ConcreteType {
490 name: ApiName,
491 rs_definition: Option<Box<Type>>,
492 cpp_definition: String,
493 },
494 /// A simple note that we want to make a constructor for
495 /// a `std::string` on the heap.
496 StringConstructor { name: ApiName },
497 /// A function. May include some analysis.
498 Function {
499 name: ApiName,
500 fun: Box<FuncToConvert>,
501 analysis: T::FunAnalysis,
502 },
503 /// A constant.
504 Const {
505 name: ApiName,
506 const_item: ItemConst,
507 },
508 /// A typedef found in the bindgen output which we wish
509 /// to pass on in our output
510 Typedef {
511 name: ApiName,
512 item: TypedefKind,
513 old_tyname: Option<QualifiedName>,
514 analysis: T::TypedefAnalysis,
515 },
516 /// An enum encountered in the
517 /// `bindgen` output.
518 Enum { name: ApiName, item: ItemEnum },
519 /// A struct encountered in the
520 /// `bindgen` output.
521 Struct {
522 name: ApiName,
523 details: Box<StructDetails>,
524 analysis: T::StructAnalysis,
525 },
526 /// A variable-length C integer type (e.g. int, unsigned long).
527 CType {
528 name: ApiName,
529 typename: QualifiedName,
530 },
531 /// Some item which couldn't be processed by autocxx for some reason.
532 /// We will have emitted a warning message about this, but we want
533 /// to mark that it's ignored so that we don't attempt to process
534 /// dependent items.
535 IgnoredItem {
536 name: ApiName,
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700537 err: ConvertErrorFromCpp,
Brian Silverman4e662aa2022-05-11 23:10:19 -0700538 ctx: Option<ErrorContext>,
539 },
540 /// A Rust type which is not a C++ type.
541 RustType { name: ApiName, path: RustPath },
542 /// A function for the 'extern Rust' block which is not a C++ type.
543 RustFn {
544 name: ApiName,
545 details: RustFun,
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700546 deps: Vec<QualifiedName>,
Brian Silverman4e662aa2022-05-11 23:10:19 -0700547 },
548 /// Some function for the extern "Rust" block.
549 RustSubclassFn {
550 name: ApiName,
551 subclass: SubclassName,
552 details: Box<RustSubclassFnDetails>,
553 },
554 /// A Rust subclass of a C++ class.
555 Subclass {
556 name: SubclassName,
557 superclass: QualifiedName,
558 },
559 /// Contributions to the traits representing superclass methods that we might
560 /// subclass in Rust.
561 SubclassTraitItem {
562 name: ApiName,
563 details: SuperclassMethod,
564 },
565 /// A type which we shouldn't ourselves generate, but can use in functions
566 /// and so-forth by referring to some definition elsewhere.
567 ExternCppType {
568 name: ApiName,
569 details: ExternCppType,
570 pod: bool,
571 },
572}
573
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700574#[derive(Debug)]
Brian Silverman4e662aa2022-05-11 23:10:19 -0700575pub(crate) struct RustSubclassFnDetails {
576 pub(crate) params: Punctuated<FnArg, Comma>,
577 pub(crate) ret: ReturnType,
578 pub(crate) cpp_impl: CppFunction,
579 pub(crate) method_name: Ident,
580 pub(crate) superclass: QualifiedName,
581 pub(crate) receiver_mutability: ReceiverMutability,
582 pub(crate) dependencies: Vec<QualifiedName>,
583 pub(crate) requires_unsafe: UnsafetyNeeded,
584 pub(crate) is_pure_virtual: bool,
585}
586
587#[derive(Clone, Debug)]
588pub(crate) enum UnsafetyNeeded {
589 None,
590 JustBridge,
591 Always,
592}
593
594impl<T: AnalysisPhase> Api<T> {
595 pub(crate) fn name_info(&self) -> &ApiName {
596 match self {
597 Api::ForwardDeclaration { name, .. } => name,
598 Api::OpaqueTypedef { name, .. } => name,
599 Api::ConcreteType { name, .. } => name,
600 Api::StringConstructor { name } => name,
601 Api::Function { name, .. } => name,
602 Api::Const { name, .. } => name,
603 Api::Typedef { name, .. } => name,
604 Api::Enum { name, .. } => name,
605 Api::Struct { name, .. } => name,
606 Api::CType { name, .. } => name,
607 Api::IgnoredItem { name, .. } => name,
608 Api::RustType { name, .. } => name,
609 Api::RustFn { name, .. } => name,
610 Api::RustSubclassFn { name, .. } => name,
611 Api::Subclass { name, .. } => &name.0,
612 Api::SubclassTraitItem { name, .. } => name,
613 Api::ExternCppType { name, .. } => name,
614 }
615 }
616
617 /// The name of this API as used in Rust code.
618 /// For types, it's important that this never changes, since
619 /// functions or other types may refer to this.
620 /// Yet for functions, this may not actually be the name
621 /// used in the [cxx::bridge] mod - see
622 /// [Api<FnAnalysis>::cxxbridge_name]
623 pub(crate) fn name(&self) -> &QualifiedName {
624 &self.name_info().name
625 }
626
627 /// The name recorded for use in C++, if and only if
628 /// it differs from Rust.
629 pub(crate) fn cpp_name(&self) -> &Option<String> {
630 &self.name_info().cpp_name
631 }
632
633 /// The name for use in C++, whether or not it differs
634 /// from Rust.
635 pub(crate) fn effective_cpp_name(&self) -> &str {
636 self.cpp_name()
637 .as_deref()
638 .unwrap_or_else(|| self.name().get_final_item())
639 }
640
641 /// If this API turns out to have the same QualifiedName as another,
642 /// whether it's OK to just discard it?
643 pub(crate) fn discard_duplicates(&self) -> bool {
644 matches!(self, Api::IgnoredItem { .. })
645 }
646
647 pub(crate) fn valid_types(&self) -> Box<dyn Iterator<Item = QualifiedName>> {
648 match self {
649 Api::Subclass { name, .. } => Box::new(
650 vec![
651 self.name().clone(),
652 QualifiedName::new(&Namespace::new(), name.holder()),
653 name.cpp(),
654 ]
655 .into_iter(),
656 ),
657 _ => Box::new(std::iter::once(self.name().clone())),
658 }
659 }
660}
661
Brian Silverman4e662aa2022-05-11 23:10:19 -0700662pub(crate) type UnanalyzedApi = Api<NullPhase>;
663
664impl<T: AnalysisPhase> Api<T> {
665 pub(crate) fn typedef_unchanged(
666 name: ApiName,
667 item: TypedefKind,
668 old_tyname: Option<QualifiedName>,
669 analysis: T::TypedefAnalysis,
670 ) -> Result<Box<dyn Iterator<Item = Api<T>>>, ConvertErrorWithContext>
671 where
672 T: 'static,
673 {
674 Ok(Box::new(std::iter::once(Api::Typedef {
675 name,
676 item,
677 old_tyname,
678 analysis,
679 })))
680 }
681
682 pub(crate) fn struct_unchanged(
683 name: ApiName,
684 details: Box<StructDetails>,
685 analysis: T::StructAnalysis,
686 ) -> Result<Box<dyn Iterator<Item = Api<T>>>, ConvertErrorWithContext>
687 where
688 T: 'static,
689 {
690 Ok(Box::new(std::iter::once(Api::Struct {
691 name,
692 details,
693 analysis,
694 })))
695 }
696
697 pub(crate) fn fun_unchanged(
698 name: ApiName,
699 fun: Box<FuncToConvert>,
700 analysis: T::FunAnalysis,
701 ) -> Result<Box<dyn Iterator<Item = Api<T>>>, ConvertErrorWithContext>
702 where
703 T: 'static,
704 {
705 Ok(Box::new(std::iter::once(Api::Function {
706 name,
707 fun,
708 analysis,
709 })))
710 }
711
712 pub(crate) fn enum_unchanged(
713 name: ApiName,
714 item: ItemEnum,
715 ) -> Result<Box<dyn Iterator<Item = Api<T>>>, ConvertErrorWithContext>
716 where
717 T: 'static,
718 {
719 Ok(Box::new(std::iter::once(Api::Enum { name, item })))
720 }
721}
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700722
723/// Whether a type is a pointer of some kind.
724pub(crate) enum Pointerness {
725 Not,
726 ConstPtr,
727 MutPtr,
728}