blob: 2426a50564fc8b4d6d30b1baadb08099b760dd95 [file] [log] [blame]
Brian Silverman4e662aa2022-05-11 23:10:19 -07001// Copyright 2022 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
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07009use crate::minisyn::FnArg;
Brian Silverman4e662aa2022-05-11 23:10:19 -070010use itertools::Itertools;
11use quote::quote;
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070012use syn::parse_quote;
Brian Silverman4e662aa2022-05-11 23:10:19 -070013
14use crate::{
15 conversion::{
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070016 api::{
17 Api, ApiName, CastMutability, DeletedOrDefaulted, Provenance, References,
18 TraitSynthesis,
19 },
Brian Silverman4e662aa2022-05-11 23:10:19 -070020 apivec::ApiVec,
21 },
22 types::{make_ident, QualifiedName},
23};
24
25/// If A is a base of B, we might want to be able to cast from
26/// &B to &A, or from Pin<&mut A> to &B, or from Pin<&mut A> to &B.
27/// The first is OK; the others turn out to be hard due to all
28/// the Pin stuff. For now therefore, we simply don't allow them.
29/// But the related code may be useful in future so I'm keeping it around.
30const SUPPORT_MUTABLE_CASTS: bool = false;
31
32use super::{
33 fun::function_wrapper::{CppFunctionBody, CppFunctionKind},
34 pod::{PodAnalysis, PodPhase},
35};
36
37pub(crate) fn add_casts(apis: ApiVec<PodPhase>) -> ApiVec<PodPhase> {
38 apis.into_iter()
39 .flat_map(|api| {
40 let mut resultant_apis = match api {
41 Api::Struct {
42 ref name,
43 details: _,
44 ref analysis,
45 } => create_casts(&name.name, analysis).collect_vec(),
46 _ => Vec::new(),
47 };
48 resultant_apis.push(api);
49 resultant_apis.into_iter()
50 })
51 .collect()
52}
53
54fn create_casts<'a>(
55 name: &'a QualifiedName,
56 analysis: &'a PodAnalysis,
57) -> impl Iterator<Item = Api<PodPhase>> + 'a {
58 // Create casts only to base classes which are on the allowlist
59 // because otherwise we won't know for sure whether they're abstract or not.
60 analysis
61 .castable_bases
62 .iter()
63 .flat_map(move |base| cast_types().map(|mutable| create_cast(name, base, mutable)))
64}
65
66/// Iterate through the types of cast we should make.
67fn cast_types() -> impl Iterator<Item = CastMutability> {
68 if SUPPORT_MUTABLE_CASTS {
69 vec![
70 CastMutability::ConstToConst,
71 CastMutability::MutToConst,
72 CastMutability::MutToMut,
73 ]
74 .into_iter()
75 } else {
76 vec![CastMutability::ConstToConst].into_iter()
77 }
78}
79
80fn create_cast(from: &QualifiedName, to: &QualifiedName, mutable: CastMutability) -> Api<PodPhase> {
81 let name = name_for_cast(from, to, mutable);
82 let ident = name.get_final_ident();
83 let from_typ = from.to_type_path();
84 let to_typ = to.to_type_path();
85 let return_mutability = match mutable {
86 CastMutability::ConstToConst | CastMutability::MutToConst => quote! { const },
87 CastMutability::MutToMut => quote! { mut },
88 };
89 let param_mutability = match mutable {
90 CastMutability::ConstToConst => quote! { const },
91 CastMutability::MutToConst | CastMutability::MutToMut => quote! { mut },
92 };
93 let fnarg: FnArg = parse_quote! {
94 this: * #param_mutability #from_typ
95 };
96 Api::Function {
97 name: ApiName::new_from_qualified_name(name),
98 fun: Box::new(crate::conversion::api::FuncToConvert {
99 ident,
100 doc_attrs: Vec::new(),
101 inputs: [fnarg].into_iter().collect(),
102 output: parse_quote! {
103 -> * #return_mutability #to_typ
104 },
105 vis: parse_quote! { pub },
106 virtualness: crate::conversion::api::Virtualness::None,
107 cpp_vis: crate::conversion::api::CppVisibility::Public,
108 special_member: None,
109 unused_template_param: false,
110 references: References::new_with_this_and_return_as_reference(),
111 original_name: None,
112 self_ty: Some(from.clone()),
113 synthesized_this_type: None,
114 add_to_trait: Some(TraitSynthesis::Cast {
115 to_type: to.clone(),
116 mutable,
117 }),
118 synthetic_cpp: Some((CppFunctionBody::Cast, CppFunctionKind::Function)),
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700119 is_deleted: DeletedOrDefaulted::Neither,
Brian Silverman4e662aa2022-05-11 23:10:19 -0700120 provenance: Provenance::SynthesizedOther,
121 variadic: false,
122 }),
123 analysis: (),
124 }
125}
126
127fn name_for_cast(
128 from: &QualifiedName,
129 to: &QualifiedName,
130 mutable: CastMutability,
131) -> QualifiedName {
132 let suffix = match mutable {
133 CastMutability::ConstToConst => "",
134 CastMutability::MutToConst => "_to_const",
135 CastMutability::MutToMut => "_mut",
136 };
137 let name = format!(
138 "cast_{}_to_{}{}",
139 from.get_final_item(),
140 to.get_final_item(),
141 suffix
142 );
143 let name = make_ident(name);
144 QualifiedName::new(from.get_namespace(), name)
145}