1use crate::syntax::cfg::ComputedCfg;
2use crate::syntax::instantiate::ImplKey;
3use crate::syntax::map::{OrderedMap, UnorderedMap};
4use crate::syntax::set::{OrderedSet as Set, UnorderedSet};
5use crate::syntax::types::ConditionalImpl;
6use crate::syntax::{Api, Enum, ExternFn, NamedType, Pair, SliceRef, Struct, Type, TypeAlias};
7use proc_macro2::Ident;
8use std::fmt::{self, Display};
9
10#[derive(Copy, Clone)]
11pub(crate) enum TrivialReason<'a> {
12 StructField(&'a Struct),
13 FunctionArgument(&'a ExternFn),
14 FunctionReturn(&'a ExternFn),
15 BoxTarget {
16 #[cfg_attr(not(proc_macro), expect(dead_code))]
20 local: bool,
21 },
22 VecElement {
23 #[cfg_attr(not(proc_macro), expect(dead_code))]
24 local: bool,
25 },
26 SliceElement(&'a SliceRef),
27}
28
29pub(crate) fn required_trivial_reasons<'a>(
30 apis: &'a [Api],
31 all: &OrderedMap<&'a Type, ComputedCfg>,
32 structs: &UnorderedMap<&'a Ident, &'a Struct>,
33 enums: &UnorderedMap<&'a Ident, &'a Enum>,
34 cxx: &UnorderedSet<&'a Ident>,
35 aliases: &UnorderedMap<&'a Ident, &'a TypeAlias>,
36 impls: &OrderedMap<ImplKey<'a>, ConditionalImpl<'a>>,
37) -> UnorderedMap<&'a Ident, Vec<TrivialReason<'a>>> {
38 let mut required_trivial = UnorderedMap::new();
39
40 let mut insist_extern_types_are_trivial = |ident: &'a NamedType, reason| {
41 if cxx.contains(&ident.rust)
42 && !structs.contains_key(&ident.rust)
43 && !enums.contains_key(&ident.rust)
44 {
45 required_trivial
46 .entry(&ident.rust)
47 .or_insert_with(Vec::new)
48 .push(reason);
49 }
50 };
51
52 for api in apis {
53 match api {
54 Api::Struct(strct) => {
55 for field in &strct.fields {
56 if let Type::Ident(ident) = &field.ty {
57 let reason = TrivialReason::StructField(strct);
58 insist_extern_types_are_trivial(ident, reason);
59 }
60 }
61 }
62 Api::CxxFunction(efn) | Api::RustFunction(efn) => {
63 for arg in &efn.args {
64 if let Type::Ident(ident) = &arg.ty {
65 let reason = TrivialReason::FunctionArgument(efn);
66 insist_extern_types_are_trivial(ident, reason);
67 }
68 }
69 if let Some(Type::Ident(ident)) = &efn.ret {
70 let reason = TrivialReason::FunctionReturn(efn);
71 insist_extern_types_are_trivial(ident, reason);
72 }
73 }
74 _ => {}
75 }
76 }
77
78 for (ty, _cfg) in all {
79 match ty {
83 Type::RustBox(ty1) => {
84 if let Type::Ident(ident) = &ty1.inner {
85 let local = !aliases.contains_key(&ident.rust)
86 || impls.contains_key(&ty.impl_key().unwrap());
87 let reason = TrivialReason::BoxTarget { local };
88 insist_extern_types_are_trivial(ident, reason);
89 }
90 }
91 Type::RustVec(ty1) => {
92 if let Type::Ident(ident) = &ty1.inner {
93 let local = !aliases.contains_key(&ident.rust)
94 || impls.contains_key(&ty.impl_key().unwrap());
95 let reason = TrivialReason::VecElement { local };
96 insist_extern_types_are_trivial(ident, reason);
97 }
98 }
99 Type::SliceRef(ty) => {
100 if let Type::Ident(ident) = &ty.inner {
101 let reason = TrivialReason::SliceElement(ty);
102 insist_extern_types_are_trivial(ident, reason);
103 }
104 }
105 _ => {}
106 }
107 }
108
109 required_trivial
110}
111
112pub(crate) fn as_what<'a>(name: &'a Pair, reasons: &'a [TrivialReason]) -> impl Display + 'a {
116 struct Description<'a> {
117 name: &'a Pair,
118 reasons: &'a [TrivialReason<'a>],
119 }
120
121 impl<'a> Display for Description<'a> {
122 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
123 let mut field_of = Set::new();
124 let mut argument_of = Set::new();
125 let mut return_of = Set::new();
126 let mut box_target = false;
127 let mut vec_element = false;
128 let mut slice_shared_element = false;
129 let mut slice_mut_element = false;
130
131 for reason in self.reasons {
132 match reason {
133 TrivialReason::StructField(strct) => {
134 field_of.insert(&strct.name.rust);
135 }
136 TrivialReason::FunctionArgument(efn) => {
137 argument_of.insert(&efn.name.rust);
138 }
139 TrivialReason::FunctionReturn(efn) => {
140 return_of.insert(&efn.name.rust);
141 }
142 TrivialReason::BoxTarget { .. } => box_target = true,
143 TrivialReason::VecElement { .. } => vec_element = true,
144 TrivialReason::SliceElement(slice) => {
145 if slice.mutable {
146 slice_mut_element = true;
147 } else {
148 slice_shared_element = true;
149 }
150 }
151 }
152 }
153
154 let mut clauses = Vec::new();
155 if !field_of.is_empty() {
156 clauses.push(Clause::Set {
157 article: "a",
158 desc: "field of",
159 set: &field_of,
160 });
161 }
162 if !argument_of.is_empty() {
163 clauses.push(Clause::Set {
164 article: "an",
165 desc: "argument of",
166 set: &argument_of,
167 });
168 }
169 if !return_of.is_empty() {
170 clauses.push(Clause::Set {
171 article: "a",
172 desc: "return value of",
173 set: &return_of,
174 });
175 }
176 if box_target {
177 clauses.push(Clause::Ty1 {
178 article: "type",
179 desc: "Box",
180 param: self.name,
181 });
182 }
183 if vec_element {
184 clauses.push(Clause::Ty1 {
185 article: "a",
186 desc: "vector element in Vec",
187 param: self.name,
188 });
189 }
190 if slice_shared_element || slice_mut_element {
191 clauses.push(Clause::Slice {
192 article: "a",
193 desc: "slice element in",
194 shared: slice_shared_element,
195 mutable: slice_mut_element,
196 param: self.name,
197 });
198 }
199
200 for (i, clause) in clauses.iter().enumerate() {
201 if i == 0 {
202 write!(f, "{} ", clause.article())?;
203 } else if i + 1 < clauses.len() {
204 write!(f, ", ")?;
205 } else {
206 write!(f, " or ")?;
207 }
208 clause.fmt(f)?;
209 }
210
211 Ok(())
212 }
213 }
214
215 enum Clause<'a> {
216 Set {
217 article: &'a str,
218 desc: &'a str,
219 set: &'a Set<&'a Ident>,
220 },
221 Ty1 {
222 article: &'a str,
223 desc: &'a str,
224 param: &'a Pair,
225 },
226 Slice {
227 article: &'a str,
228 desc: &'a str,
229 shared: bool,
230 mutable: bool,
231 param: &'a Pair,
232 },
233 }
234
235 impl<'a> Clause<'a> {
236 fn article(&self) -> &'a str {
237 match self {
238 Clause::Set { article, .. }
239 | Clause::Ty1 { article, .. }
240 | Clause::Slice { article, .. } => article,
241 }
242 }
243
244 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
245 match self {
246 Clause::Set {
247 article: _,
248 desc,
249 set,
250 } => {
251 write!(f, "{} ", desc)?;
252 for (i, ident) in set.iter().take(3).enumerate() {
253 if i > 0 {
254 write!(f, ", ")?;
255 }
256 write!(f, "`{}`", ident)?;
257 }
258 Ok(())
259 }
260 Clause::Ty1 {
261 article: _,
262 desc,
263 param,
264 } => write!(f, "{}<{}>", desc, param.rust),
265 Clause::Slice {
266 article: _,
267 desc,
268 shared,
269 mutable,
270 param,
271 } => {
272 write!(f, "{} ", desc)?;
273 if *shared {
274 write!(f, "&[{}]", param.rust)?;
275 }
276 if *shared && *mutable {
277 write!(f, " and ")?;
278 }
279 if *mutable {
280 write!(f, "&mut [{}]", param.rust)?;
281 }
282 Ok(())
283 }
284 }
285 }
286 }
287
288 Description { name, reasons }
289}