Squashed 'third_party/autocxx/' content from commit 629e8fa53
git-subtree-dir: third_party/autocxx
git-subtree-split: 629e8fa531a633164c0b52e2a3cab536d4cd0849
Signed-off-by: Brian Silverman <bsilver16384@gmail.com>
Change-Id: I62a03b0049f49adf029e0204639cdb5468dde1a1
diff --git a/engine/src/conversion/analysis/casts.rs b/engine/src/conversion/analysis/casts.rs
new file mode 100644
index 0000000..5f493f9
--- /dev/null
+++ b/engine/src/conversion/analysis/casts.rs
@@ -0,0 +1,141 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use itertools::Itertools;
+use quote::quote;
+use syn::{parse_quote, FnArg};
+
+use crate::{
+ conversion::{
+ api::{Api, ApiName, CastMutability, Provenance, References, TraitSynthesis},
+ apivec::ApiVec,
+ },
+ types::{make_ident, QualifiedName},
+};
+
+/// If A is a base of B, we might want to be able to cast from
+/// &B to &A, or from Pin<&mut A> to &B, or from Pin<&mut A> to &B.
+/// The first is OK; the others turn out to be hard due to all
+/// the Pin stuff. For now therefore, we simply don't allow them.
+/// But the related code may be useful in future so I'm keeping it around.
+const SUPPORT_MUTABLE_CASTS: bool = false;
+
+use super::{
+ fun::function_wrapper::{CppFunctionBody, CppFunctionKind},
+ pod::{PodAnalysis, PodPhase},
+};
+
+pub(crate) fn add_casts(apis: ApiVec<PodPhase>) -> ApiVec<PodPhase> {
+ apis.into_iter()
+ .flat_map(|api| {
+ let mut resultant_apis = match api {
+ Api::Struct {
+ ref name,
+ details: _,
+ ref analysis,
+ } => create_casts(&name.name, analysis).collect_vec(),
+ _ => Vec::new(),
+ };
+ resultant_apis.push(api);
+ resultant_apis.into_iter()
+ })
+ .collect()
+}
+
+fn create_casts<'a>(
+ name: &'a QualifiedName,
+ analysis: &'a PodAnalysis,
+) -> impl Iterator<Item = Api<PodPhase>> + 'a {
+ // Create casts only to base classes which are on the allowlist
+ // because otherwise we won't know for sure whether they're abstract or not.
+ analysis
+ .castable_bases
+ .iter()
+ .flat_map(move |base| cast_types().map(|mutable| create_cast(name, base, mutable)))
+}
+
+/// Iterate through the types of cast we should make.
+fn cast_types() -> impl Iterator<Item = CastMutability> {
+ if SUPPORT_MUTABLE_CASTS {
+ vec![
+ CastMutability::ConstToConst,
+ CastMutability::MutToConst,
+ CastMutability::MutToMut,
+ ]
+ .into_iter()
+ } else {
+ vec![CastMutability::ConstToConst].into_iter()
+ }
+}
+
+fn create_cast(from: &QualifiedName, to: &QualifiedName, mutable: CastMutability) -> Api<PodPhase> {
+ let name = name_for_cast(from, to, mutable);
+ let ident = name.get_final_ident();
+ let from_typ = from.to_type_path();
+ let to_typ = to.to_type_path();
+ let return_mutability = match mutable {
+ CastMutability::ConstToConst | CastMutability::MutToConst => quote! { const },
+ CastMutability::MutToMut => quote! { mut },
+ };
+ let param_mutability = match mutable {
+ CastMutability::ConstToConst => quote! { const },
+ CastMutability::MutToConst | CastMutability::MutToMut => quote! { mut },
+ };
+ let fnarg: FnArg = parse_quote! {
+ this: * #param_mutability #from_typ
+ };
+ Api::Function {
+ name: ApiName::new_from_qualified_name(name),
+ fun: Box::new(crate::conversion::api::FuncToConvert {
+ ident,
+ doc_attrs: Vec::new(),
+ inputs: [fnarg].into_iter().collect(),
+ output: parse_quote! {
+ -> * #return_mutability #to_typ
+ },
+ vis: parse_quote! { pub },
+ virtualness: crate::conversion::api::Virtualness::None,
+ cpp_vis: crate::conversion::api::CppVisibility::Public,
+ special_member: None,
+ unused_template_param: false,
+ references: References::new_with_this_and_return_as_reference(),
+ original_name: None,
+ self_ty: Some(from.clone()),
+ synthesized_this_type: None,
+ add_to_trait: Some(TraitSynthesis::Cast {
+ to_type: to.clone(),
+ mutable,
+ }),
+ synthetic_cpp: Some((CppFunctionBody::Cast, CppFunctionKind::Function)),
+ is_deleted: false,
+ provenance: Provenance::SynthesizedOther,
+ variadic: false,
+ }),
+ analysis: (),
+ }
+}
+
+fn name_for_cast(
+ from: &QualifiedName,
+ to: &QualifiedName,
+ mutable: CastMutability,
+) -> QualifiedName {
+ let suffix = match mutable {
+ CastMutability::ConstToConst => "",
+ CastMutability::MutToConst => "_to_const",
+ CastMutability::MutToMut => "_mut",
+ };
+ let name = format!(
+ "cast_{}_to_{}{}",
+ from.get_final_item(),
+ to.get_final_item(),
+ suffix
+ );
+ let name = make_ident(name);
+ QualifiedName::new(from.get_namespace(), name)
+}