1use crate::syntax::map::UnorderedMap; 2use crate::syntax::set::{OrderedSet as Set, UnorderedSet}; 3use crate::syntax::{Api, Enum, ExternFn, NamedType, Pair, Struct, Type}; 4use proc_macro2::Ident; 5use std::fmt::{self, Display}; 6 7#[derive(Copy, Clone)] 8pub 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 18pub 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}" 127pub 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