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