• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::syntax::map::UnorderedMap;
2 use crate::syntax::set::{OrderedSet as Set, UnorderedSet};
3 use crate::syntax::{Api, Enum, ExternFn, NamedType, Pair, Struct, Type};
4 use proc_macro2::Ident;
5 use std::fmt::{self, Display};
6 
7 #[derive(Copy, Clone)]
8 pub enum TrivialReason<'a> {
9     StructField(&'a Struct),
10     FunctionArgument(&'a ExternFn),
11     FunctionReturn(&'a ExternFn),
12     BoxTarget,
13     VecElement,
14     UnpinnedMut(&'a ExternFn),
15 }
16 
required_trivial_reasons<'a>( apis: &'a [Api], all: &Set<&'a Type>, structs: &UnorderedMap<&'a Ident, &'a Struct>, enums: &UnorderedMap<&'a Ident, &'a Enum>, cxx: &UnorderedSet<&'a Ident>, ) -> UnorderedMap<&'a Ident, Vec<TrivialReason<'a>>>17 pub fn required_trivial_reasons<'a>(
18     apis: &'a [Api],
19     all: &Set<&'a Type>,
20     structs: &UnorderedMap<&'a Ident, &'a Struct>,
21     enums: &UnorderedMap<&'a Ident, &'a Enum>,
22     cxx: &UnorderedSet<&'a Ident>,
23 ) -> UnorderedMap<&'a Ident, Vec<TrivialReason<'a>>> {
24     let mut required_trivial = UnorderedMap::new();
25 
26     let mut insist_extern_types_are_trivial = |ident: &'a NamedType, reason| {
27         if cxx.contains(&ident.rust)
28             && !structs.contains_key(&ident.rust)
29             && !enums.contains_key(&ident.rust)
30         {
31             required_trivial
32                 .entry(&ident.rust)
33                 .or_insert_with(Vec::new)
34                 .push(reason);
35         }
36     };
37 
38     for api in apis {
39         match api {
40             Api::Struct(strct) => {
41                 for field in &strct.fields {
42                     if let Type::Ident(ident) = &field.ty {
43                         let reason = TrivialReason::StructField(strct);
44                         insist_extern_types_are_trivial(ident, reason);
45                     }
46                 }
47             }
48             Api::CxxFunction(efn) | Api::RustFunction(efn) => {
49                 if let Some(receiver) = &efn.receiver {
50                     if receiver.mutable && !receiver.pinned {
51                         let reason = TrivialReason::UnpinnedMut(efn);
52                         insist_extern_types_are_trivial(&receiver.ty, reason);
53                     }
54                 }
55                 for arg in &efn.args {
56                     match &arg.ty {
57                         Type::Ident(ident) => {
58                             let reason = TrivialReason::FunctionArgument(efn);
59                             insist_extern_types_are_trivial(ident, reason);
60                         }
61                         Type::Ref(ty) => {
62                             if ty.mutable && !ty.pinned {
63                                 if let Type::Ident(ident) = &ty.inner {
64                                     let reason = TrivialReason::UnpinnedMut(efn);
65                                     insist_extern_types_are_trivial(ident, reason);
66                                 }
67                             }
68                         }
69                         _ => {}
70                     }
71                 }
72                 if let Some(ret) = &efn.ret {
73                     match ret {
74                         Type::Ident(ident) => {
75                             let reason = TrivialReason::FunctionReturn(efn);
76                             insist_extern_types_are_trivial(ident, reason);
77                         }
78                         Type::Ref(ty) => {
79                             if ty.mutable && !ty.pinned {
80                                 if let Type::Ident(ident) = &ty.inner {
81                                     let reason = TrivialReason::UnpinnedMut(efn);
82                                     insist_extern_types_are_trivial(ident, reason);
83                                 }
84                             }
85                         }
86                         _ => {}
87                     }
88                 }
89             }
90             _ => {}
91         }
92     }
93 
94     for ty in all {
95         match ty {
96             Type::RustBox(ty) => {
97                 if let Type::Ident(ident) = &ty.inner {
98                     let reason = TrivialReason::BoxTarget;
99                     insist_extern_types_are_trivial(ident, reason);
100                 }
101             }
102             Type::RustVec(ty) => {
103                 if let Type::Ident(ident) = &ty.inner {
104                     let reason = TrivialReason::VecElement;
105                     insist_extern_types_are_trivial(ident, reason);
106                 }
107             }
108             _ => {}
109         }
110     }
111 
112     required_trivial
113 }
114 
115 // Context:
116 // "type {type} should be trivially move constructible and trivially destructible in C++ to be used as {what} in Rust"
117 // "needs a cxx::ExternType impl in order to be used as {what}"
as_what<'a>(name: &'a Pair, reasons: &'a [TrivialReason]) -> impl Display + 'a118 pub fn as_what<'a>(name: &'a Pair, reasons: &'a [TrivialReason]) -> impl Display + 'a {
119     struct Description<'a> {
120         name: &'a Pair,
121         reasons: &'a [TrivialReason<'a>],
122     }
123 
124     impl<'a> Display for Description<'a> {
125         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
126             let mut field_of = Set::new();
127             let mut argument_of = Set::new();
128             let mut return_of = Set::new();
129             let mut box_target = false;
130             let mut vec_element = false;
131             let mut unpinned_mut = Set::new();
132 
133             for reason in self.reasons {
134                 match reason {
135                     TrivialReason::StructField(strct) => {
136                         field_of.insert(&strct.name.rust);
137                     }
138                     TrivialReason::FunctionArgument(efn) => {
139                         argument_of.insert(&efn.name.rust);
140                     }
141                     TrivialReason::FunctionReturn(efn) => {
142                         return_of.insert(&efn.name.rust);
143                     }
144                     TrivialReason::BoxTarget => box_target = true,
145                     TrivialReason::VecElement => vec_element = true,
146                     TrivialReason::UnpinnedMut(efn) => {
147                         unpinned_mut.insert(&efn.name.rust);
148                     }
149                 }
150             }
151 
152             let mut clauses = Vec::new();
153             if !field_of.is_empty() {
154                 clauses.push(Clause::Set {
155                     article: "a",
156                     desc: "field of",
157                     set: &field_of,
158                 });
159             }
160             if !argument_of.is_empty() {
161                 clauses.push(Clause::Set {
162                     article: "an",
163                     desc: "argument of",
164                     set: &argument_of,
165                 });
166             }
167             if !return_of.is_empty() {
168                 clauses.push(Clause::Set {
169                     article: "a",
170                     desc: "return value of",
171                     set: &return_of,
172                 });
173             }
174             if box_target {
175                 clauses.push(Clause::Ty1 {
176                     article: "type",
177                     desc: "Box",
178                     param: self.name,
179                 });
180             }
181             if vec_element {
182                 clauses.push(Clause::Ty1 {
183                     article: "a",
184                     desc: "vector element in Vec",
185                     param: self.name,
186                 });
187             }
188             if !unpinned_mut.is_empty() {
189                 clauses.push(Clause::Set {
190                     article: "a",
191                     desc: "non-pinned mutable reference in signature of",
192                     set: &unpinned_mut,
193                 });
194             }
195 
196             for (i, clause) in clauses.iter().enumerate() {
197                 if i == 0 {
198                     write!(f, "{} ", clause.article())?;
199                 } else if i + 1 < clauses.len() {
200                     write!(f, ", ")?;
201                 } else {
202                     write!(f, " or ")?;
203                 }
204                 clause.fmt(f)?;
205             }
206 
207             Ok(())
208         }
209     }
210 
211     enum Clause<'a> {
212         Set {
213             article: &'a str,
214             desc: &'a str,
215             set: &'a Set<&'a Ident>,
216         },
217         Ty1 {
218             article: &'a str,
219             desc: &'a str,
220             param: &'a Pair,
221         },
222     }
223 
224     impl<'a> Clause<'a> {
225         fn article(&self) -> &'a str {
226             match self {
227                 Clause::Set { article, .. } | Clause::Ty1 { article, .. } => article,
228             }
229         }
230 
231         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
232             match self {
233                 Clause::Set {
234                     article: _,
235                     desc,
236                     set,
237                 } => {
238                     write!(f, "{} ", desc)?;
239                     for (i, ident) in set.iter().take(3).enumerate() {
240                         if i > 0 {
241                             write!(f, ", ")?;
242                         }
243                         write!(f, "`{}`", ident)?;
244                     }
245                     Ok(())
246                 }
247                 Clause::Ty1 {
248                     article: _,
249                     desc,
250                     param,
251                 } => write!(f, "{}<{}>", desc, param.rust),
252             }
253         }
254     }
255 
256     Description { name, reasons }
257 }
258