133d722a9Sopenharmony_ciuse crate::syntax::map::UnorderedMap; 233d722a9Sopenharmony_ciuse crate::syntax::set::{OrderedSet as Set, UnorderedSet}; 333d722a9Sopenharmony_ciuse crate::syntax::{Api, Enum, ExternFn, NamedType, Pair, Struct, Type}; 433d722a9Sopenharmony_ciuse proc_macro2::Ident; 533d722a9Sopenharmony_ciuse std::fmt::{self, Display}; 633d722a9Sopenharmony_ci 733d722a9Sopenharmony_ci#[derive(Copy, Clone)] 833d722a9Sopenharmony_cipub enum TrivialReason<'a> { 933d722a9Sopenharmony_ci StructField(&'a Struct), 1033d722a9Sopenharmony_ci FunctionArgument(&'a ExternFn), 1133d722a9Sopenharmony_ci FunctionReturn(&'a ExternFn), 1233d722a9Sopenharmony_ci BoxTarget, 1333d722a9Sopenharmony_ci VecElement, 1433d722a9Sopenharmony_ci SliceElement { mutable: bool }, 1533d722a9Sopenharmony_ci UnpinnedMut(&'a ExternFn), 1633d722a9Sopenharmony_ci} 1733d722a9Sopenharmony_ci 1833d722a9Sopenharmony_cipub fn required_trivial_reasons<'a>( 1933d722a9Sopenharmony_ci apis: &'a [Api], 2033d722a9Sopenharmony_ci all: &Set<&'a Type>, 2133d722a9Sopenharmony_ci structs: &UnorderedMap<&'a Ident, &'a Struct>, 2233d722a9Sopenharmony_ci enums: &UnorderedMap<&'a Ident, &'a Enum>, 2333d722a9Sopenharmony_ci cxx: &UnorderedSet<&'a Ident>, 2433d722a9Sopenharmony_ci) -> UnorderedMap<&'a Ident, Vec<TrivialReason<'a>>> { 2533d722a9Sopenharmony_ci let mut required_trivial = UnorderedMap::new(); 2633d722a9Sopenharmony_ci 2733d722a9Sopenharmony_ci let mut insist_extern_types_are_trivial = |ident: &'a NamedType, reason| { 2833d722a9Sopenharmony_ci if cxx.contains(&ident.rust) 2933d722a9Sopenharmony_ci && !structs.contains_key(&ident.rust) 3033d722a9Sopenharmony_ci && !enums.contains_key(&ident.rust) 3133d722a9Sopenharmony_ci { 3233d722a9Sopenharmony_ci required_trivial 3333d722a9Sopenharmony_ci .entry(&ident.rust) 3433d722a9Sopenharmony_ci .or_insert_with(Vec::new) 3533d722a9Sopenharmony_ci .push(reason); 3633d722a9Sopenharmony_ci } 3733d722a9Sopenharmony_ci }; 3833d722a9Sopenharmony_ci 3933d722a9Sopenharmony_ci for api in apis { 4033d722a9Sopenharmony_ci match api { 4133d722a9Sopenharmony_ci Api::Struct(strct) => { 4233d722a9Sopenharmony_ci for field in &strct.fields { 4333d722a9Sopenharmony_ci if let Type::Ident(ident) = &field.ty { 4433d722a9Sopenharmony_ci let reason = TrivialReason::StructField(strct); 4533d722a9Sopenharmony_ci insist_extern_types_are_trivial(ident, reason); 4633d722a9Sopenharmony_ci } 4733d722a9Sopenharmony_ci } 4833d722a9Sopenharmony_ci } 4933d722a9Sopenharmony_ci Api::CxxFunction(efn) | Api::RustFunction(efn) => { 5033d722a9Sopenharmony_ci if let Some(receiver) = &efn.receiver { 5133d722a9Sopenharmony_ci if receiver.mutable && !receiver.pinned { 5233d722a9Sopenharmony_ci let reason = TrivialReason::UnpinnedMut(efn); 5333d722a9Sopenharmony_ci insist_extern_types_are_trivial(&receiver.ty, reason); 5433d722a9Sopenharmony_ci } 5533d722a9Sopenharmony_ci } 5633d722a9Sopenharmony_ci for arg in &efn.args { 5733d722a9Sopenharmony_ci match &arg.ty { 5833d722a9Sopenharmony_ci Type::Ident(ident) => { 5933d722a9Sopenharmony_ci let reason = TrivialReason::FunctionArgument(efn); 6033d722a9Sopenharmony_ci insist_extern_types_are_trivial(ident, reason); 6133d722a9Sopenharmony_ci } 6233d722a9Sopenharmony_ci Type::Ref(ty) => { 6333d722a9Sopenharmony_ci if ty.mutable && !ty.pinned { 6433d722a9Sopenharmony_ci if let Type::Ident(ident) = &ty.inner { 6533d722a9Sopenharmony_ci let reason = TrivialReason::UnpinnedMut(efn); 6633d722a9Sopenharmony_ci insist_extern_types_are_trivial(ident, reason); 6733d722a9Sopenharmony_ci } 6833d722a9Sopenharmony_ci } 6933d722a9Sopenharmony_ci } 7033d722a9Sopenharmony_ci _ => {} 7133d722a9Sopenharmony_ci } 7233d722a9Sopenharmony_ci } 7333d722a9Sopenharmony_ci if let Some(ret) = &efn.ret { 7433d722a9Sopenharmony_ci match ret { 7533d722a9Sopenharmony_ci Type::Ident(ident) => { 7633d722a9Sopenharmony_ci let reason = TrivialReason::FunctionReturn(efn); 7733d722a9Sopenharmony_ci insist_extern_types_are_trivial(ident, reason); 7833d722a9Sopenharmony_ci } 7933d722a9Sopenharmony_ci Type::Ref(ty) => { 8033d722a9Sopenharmony_ci if ty.mutable && !ty.pinned { 8133d722a9Sopenharmony_ci if let Type::Ident(ident) = &ty.inner { 8233d722a9Sopenharmony_ci let reason = TrivialReason::UnpinnedMut(efn); 8333d722a9Sopenharmony_ci insist_extern_types_are_trivial(ident, reason); 8433d722a9Sopenharmony_ci } 8533d722a9Sopenharmony_ci } 8633d722a9Sopenharmony_ci } 8733d722a9Sopenharmony_ci _ => {} 8833d722a9Sopenharmony_ci } 8933d722a9Sopenharmony_ci } 9033d722a9Sopenharmony_ci } 9133d722a9Sopenharmony_ci _ => {} 9233d722a9Sopenharmony_ci } 9333d722a9Sopenharmony_ci } 9433d722a9Sopenharmony_ci 9533d722a9Sopenharmony_ci for ty in all { 9633d722a9Sopenharmony_ci match ty { 9733d722a9Sopenharmony_ci Type::RustBox(ty) => { 9833d722a9Sopenharmony_ci if let Type::Ident(ident) = &ty.inner { 9933d722a9Sopenharmony_ci let reason = TrivialReason::BoxTarget; 10033d722a9Sopenharmony_ci insist_extern_types_are_trivial(ident, reason); 10133d722a9Sopenharmony_ci } 10233d722a9Sopenharmony_ci } 10333d722a9Sopenharmony_ci Type::RustVec(ty) => { 10433d722a9Sopenharmony_ci if let Type::Ident(ident) = &ty.inner { 10533d722a9Sopenharmony_ci let reason = TrivialReason::VecElement; 10633d722a9Sopenharmony_ci insist_extern_types_are_trivial(ident, reason); 10733d722a9Sopenharmony_ci } 10833d722a9Sopenharmony_ci } 10933d722a9Sopenharmony_ci Type::SliceRef(ty) => { 11033d722a9Sopenharmony_ci if let Type::Ident(ident) = &ty.inner { 11133d722a9Sopenharmony_ci let reason = TrivialReason::SliceElement { 11233d722a9Sopenharmony_ci mutable: ty.mutable, 11333d722a9Sopenharmony_ci }; 11433d722a9Sopenharmony_ci insist_extern_types_are_trivial(ident, reason); 11533d722a9Sopenharmony_ci } 11633d722a9Sopenharmony_ci } 11733d722a9Sopenharmony_ci _ => {} 11833d722a9Sopenharmony_ci } 11933d722a9Sopenharmony_ci } 12033d722a9Sopenharmony_ci 12133d722a9Sopenharmony_ci required_trivial 12233d722a9Sopenharmony_ci} 12333d722a9Sopenharmony_ci 12433d722a9Sopenharmony_ci// Context: 12533d722a9Sopenharmony_ci// "type {type} should be trivially move constructible and trivially destructible in C++ to be used as {what} in Rust" 12633d722a9Sopenharmony_ci// "needs a cxx::ExternType impl in order to be used as {what}" 12733d722a9Sopenharmony_cipub fn as_what<'a>(name: &'a Pair, reasons: &'a [TrivialReason]) -> impl Display + 'a { 12833d722a9Sopenharmony_ci struct Description<'a> { 12933d722a9Sopenharmony_ci name: &'a Pair, 13033d722a9Sopenharmony_ci reasons: &'a [TrivialReason<'a>], 13133d722a9Sopenharmony_ci } 13233d722a9Sopenharmony_ci 13333d722a9Sopenharmony_ci impl<'a> Display for Description<'a> { 13433d722a9Sopenharmony_ci fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 13533d722a9Sopenharmony_ci let mut field_of = Set::new(); 13633d722a9Sopenharmony_ci let mut argument_of = Set::new(); 13733d722a9Sopenharmony_ci let mut return_of = Set::new(); 13833d722a9Sopenharmony_ci let mut box_target = false; 13933d722a9Sopenharmony_ci let mut vec_element = false; 14033d722a9Sopenharmony_ci let mut slice_shared_element = false; 14133d722a9Sopenharmony_ci let mut slice_mut_element = false; 14233d722a9Sopenharmony_ci let mut unpinned_mut = Set::new(); 14333d722a9Sopenharmony_ci 14433d722a9Sopenharmony_ci for reason in self.reasons { 14533d722a9Sopenharmony_ci match reason { 14633d722a9Sopenharmony_ci TrivialReason::StructField(strct) => { 14733d722a9Sopenharmony_ci field_of.insert(&strct.name.rust); 14833d722a9Sopenharmony_ci } 14933d722a9Sopenharmony_ci TrivialReason::FunctionArgument(efn) => { 15033d722a9Sopenharmony_ci argument_of.insert(&efn.name.rust); 15133d722a9Sopenharmony_ci } 15233d722a9Sopenharmony_ci TrivialReason::FunctionReturn(efn) => { 15333d722a9Sopenharmony_ci return_of.insert(&efn.name.rust); 15433d722a9Sopenharmony_ci } 15533d722a9Sopenharmony_ci TrivialReason::BoxTarget => box_target = true, 15633d722a9Sopenharmony_ci TrivialReason::VecElement => vec_element = true, 15733d722a9Sopenharmony_ci TrivialReason::SliceElement { mutable } => { 15833d722a9Sopenharmony_ci if *mutable { 15933d722a9Sopenharmony_ci slice_mut_element = true; 16033d722a9Sopenharmony_ci } else { 16133d722a9Sopenharmony_ci slice_shared_element = true; 16233d722a9Sopenharmony_ci } 16333d722a9Sopenharmony_ci } 16433d722a9Sopenharmony_ci TrivialReason::UnpinnedMut(efn) => { 16533d722a9Sopenharmony_ci unpinned_mut.insert(&efn.name.rust); 16633d722a9Sopenharmony_ci } 16733d722a9Sopenharmony_ci } 16833d722a9Sopenharmony_ci } 16933d722a9Sopenharmony_ci 17033d722a9Sopenharmony_ci let mut clauses = Vec::new(); 17133d722a9Sopenharmony_ci if !field_of.is_empty() { 17233d722a9Sopenharmony_ci clauses.push(Clause::Set { 17333d722a9Sopenharmony_ci article: "a", 17433d722a9Sopenharmony_ci desc: "field of", 17533d722a9Sopenharmony_ci set: &field_of, 17633d722a9Sopenharmony_ci }); 17733d722a9Sopenharmony_ci } 17833d722a9Sopenharmony_ci if !argument_of.is_empty() { 17933d722a9Sopenharmony_ci clauses.push(Clause::Set { 18033d722a9Sopenharmony_ci article: "an", 18133d722a9Sopenharmony_ci desc: "argument of", 18233d722a9Sopenharmony_ci set: &argument_of, 18333d722a9Sopenharmony_ci }); 18433d722a9Sopenharmony_ci } 18533d722a9Sopenharmony_ci if !return_of.is_empty() { 18633d722a9Sopenharmony_ci clauses.push(Clause::Set { 18733d722a9Sopenharmony_ci article: "a", 18833d722a9Sopenharmony_ci desc: "return value of", 18933d722a9Sopenharmony_ci set: &return_of, 19033d722a9Sopenharmony_ci }); 19133d722a9Sopenharmony_ci } 19233d722a9Sopenharmony_ci if box_target { 19333d722a9Sopenharmony_ci clauses.push(Clause::Ty1 { 19433d722a9Sopenharmony_ci article: "type", 19533d722a9Sopenharmony_ci desc: "Box", 19633d722a9Sopenharmony_ci param: self.name, 19733d722a9Sopenharmony_ci }); 19833d722a9Sopenharmony_ci } 19933d722a9Sopenharmony_ci if vec_element { 20033d722a9Sopenharmony_ci clauses.push(Clause::Ty1 { 20133d722a9Sopenharmony_ci article: "a", 20233d722a9Sopenharmony_ci desc: "vector element in Vec", 20333d722a9Sopenharmony_ci param: self.name, 20433d722a9Sopenharmony_ci }); 20533d722a9Sopenharmony_ci } 20633d722a9Sopenharmony_ci if slice_shared_element || slice_mut_element { 20733d722a9Sopenharmony_ci clauses.push(Clause::Slice { 20833d722a9Sopenharmony_ci article: "a", 20933d722a9Sopenharmony_ci desc: "slice element in", 21033d722a9Sopenharmony_ci shared: slice_shared_element, 21133d722a9Sopenharmony_ci mutable: slice_mut_element, 21233d722a9Sopenharmony_ci param: self.name, 21333d722a9Sopenharmony_ci }); 21433d722a9Sopenharmony_ci } 21533d722a9Sopenharmony_ci if !unpinned_mut.is_empty() { 21633d722a9Sopenharmony_ci clauses.push(Clause::Set { 21733d722a9Sopenharmony_ci article: "a", 21833d722a9Sopenharmony_ci desc: "non-pinned mutable reference in signature of", 21933d722a9Sopenharmony_ci set: &unpinned_mut, 22033d722a9Sopenharmony_ci }); 22133d722a9Sopenharmony_ci } 22233d722a9Sopenharmony_ci 22333d722a9Sopenharmony_ci for (i, clause) in clauses.iter().enumerate() { 22433d722a9Sopenharmony_ci if i == 0 { 22533d722a9Sopenharmony_ci write!(f, "{} ", clause.article())?; 22633d722a9Sopenharmony_ci } else if i + 1 < clauses.len() { 22733d722a9Sopenharmony_ci write!(f, ", ")?; 22833d722a9Sopenharmony_ci } else { 22933d722a9Sopenharmony_ci write!(f, " or ")?; 23033d722a9Sopenharmony_ci } 23133d722a9Sopenharmony_ci clause.fmt(f)?; 23233d722a9Sopenharmony_ci } 23333d722a9Sopenharmony_ci 23433d722a9Sopenharmony_ci Ok(()) 23533d722a9Sopenharmony_ci } 23633d722a9Sopenharmony_ci } 23733d722a9Sopenharmony_ci 23833d722a9Sopenharmony_ci enum Clause<'a> { 23933d722a9Sopenharmony_ci Set { 24033d722a9Sopenharmony_ci article: &'a str, 24133d722a9Sopenharmony_ci desc: &'a str, 24233d722a9Sopenharmony_ci set: &'a Set<&'a Ident>, 24333d722a9Sopenharmony_ci }, 24433d722a9Sopenharmony_ci Ty1 { 24533d722a9Sopenharmony_ci article: &'a str, 24633d722a9Sopenharmony_ci desc: &'a str, 24733d722a9Sopenharmony_ci param: &'a Pair, 24833d722a9Sopenharmony_ci }, 24933d722a9Sopenharmony_ci Slice { 25033d722a9Sopenharmony_ci article: &'a str, 25133d722a9Sopenharmony_ci desc: &'a str, 25233d722a9Sopenharmony_ci shared: bool, 25333d722a9Sopenharmony_ci mutable: bool, 25433d722a9Sopenharmony_ci param: &'a Pair, 25533d722a9Sopenharmony_ci }, 25633d722a9Sopenharmony_ci } 25733d722a9Sopenharmony_ci 25833d722a9Sopenharmony_ci impl<'a> Clause<'a> { 25933d722a9Sopenharmony_ci fn article(&self) -> &'a str { 26033d722a9Sopenharmony_ci match self { 26133d722a9Sopenharmony_ci Clause::Set { article, .. } 26233d722a9Sopenharmony_ci | Clause::Ty1 { article, .. } 26333d722a9Sopenharmony_ci | Clause::Slice { article, .. } => article, 26433d722a9Sopenharmony_ci } 26533d722a9Sopenharmony_ci } 26633d722a9Sopenharmony_ci 26733d722a9Sopenharmony_ci fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 26833d722a9Sopenharmony_ci match self { 26933d722a9Sopenharmony_ci Clause::Set { 27033d722a9Sopenharmony_ci article: _, 27133d722a9Sopenharmony_ci desc, 27233d722a9Sopenharmony_ci set, 27333d722a9Sopenharmony_ci } => { 27433d722a9Sopenharmony_ci write!(f, "{} ", desc)?; 27533d722a9Sopenharmony_ci for (i, ident) in set.iter().take(3).enumerate() { 27633d722a9Sopenharmony_ci if i > 0 { 27733d722a9Sopenharmony_ci write!(f, ", ")?; 27833d722a9Sopenharmony_ci } 27933d722a9Sopenharmony_ci write!(f, "`{}`", ident)?; 28033d722a9Sopenharmony_ci } 28133d722a9Sopenharmony_ci Ok(()) 28233d722a9Sopenharmony_ci } 28333d722a9Sopenharmony_ci Clause::Ty1 { 28433d722a9Sopenharmony_ci article: _, 28533d722a9Sopenharmony_ci desc, 28633d722a9Sopenharmony_ci param, 28733d722a9Sopenharmony_ci } => write!(f, "{}<{}>", desc, param.rust), 28833d722a9Sopenharmony_ci Clause::Slice { 28933d722a9Sopenharmony_ci article: _, 29033d722a9Sopenharmony_ci desc, 29133d722a9Sopenharmony_ci shared, 29233d722a9Sopenharmony_ci mutable, 29333d722a9Sopenharmony_ci param, 29433d722a9Sopenharmony_ci } => { 29533d722a9Sopenharmony_ci write!(f, "{} ", desc)?; 29633d722a9Sopenharmony_ci if *shared { 29733d722a9Sopenharmony_ci write!(f, "&[{}]", param.rust)?; 29833d722a9Sopenharmony_ci } 29933d722a9Sopenharmony_ci if *shared && *mutable { 30033d722a9Sopenharmony_ci write!(f, " and ")?; 30133d722a9Sopenharmony_ci } 30233d722a9Sopenharmony_ci if *mutable { 30333d722a9Sopenharmony_ci write!(f, "&mut [{}]", param.rust)?; 30433d722a9Sopenharmony_ci } 30533d722a9Sopenharmony_ci Ok(()) 30633d722a9Sopenharmony_ci } 30733d722a9Sopenharmony_ci } 30833d722a9Sopenharmony_ci } 30933d722a9Sopenharmony_ci } 31033d722a9Sopenharmony_ci 31133d722a9Sopenharmony_ci Description { name, reasons } 31233d722a9Sopenharmony_ci} 313