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