1use crate::syntax::cfg::ComputedCfg;
2use crate::syntax::map::{OrderedMap, UnorderedMap};
3use crate::syntax::set::UnorderedSet;
4use crate::syntax::{Api, Enum, NamedType, Receiver, Ref, SliceRef, Struct, Type, TypeAlias};
5use proc_macro2::Ident;
6
7#[cfg_attr(not(proc_macro), expect(dead_code))]
8pub(crate) enum UnpinReason<'a> {
9 Receiver(&'a Receiver),
10 Ref(&'a Ref),
11 Slice(&'a SliceRef),
12}
13
14pub(crate) fn required_unpin_reasons<'a>(
15 apis: &'a [Api],
16 all: &OrderedMap<&'a Type, ComputedCfg>,
17 structs: &UnorderedMap<&'a Ident, &'a Struct>,
18 enums: &UnorderedMap<&'a Ident, &'a Enum>,
19 cxx: &UnorderedSet<&'a Ident>,
20 aliases: &UnorderedMap<&'a Ident, &'a TypeAlias>,
21) -> UnorderedMap<&'a Ident, UnpinReason<'a>> {
22 let mut reasons = UnorderedMap::new();
23
24 let is_extern_type_alias = |ty: &NamedType| -> bool {
25 cxx.contains(&ty.rust)
26 && !structs.contains_key(&ty.rust)
27 && !enums.contains_key(&ty.rust)
28 && aliases.contains_key(&ty.rust)
29 };
30
31 for (ty, _cfgs) in all {
32 if let Type::SliceRef(slice) = ty {
33 if let Type::Ident(inner) = &slice.inner {
34 if slice.mutable && is_extern_type_alias(inner) {
35 reasons.insert(&inner.rust, UnpinReason::Slice(slice));
36 }
37 }
38 }
39 }
40
41 for api in apis {
42 if let Api::CxxFunction(efn) | Api::RustFunction(efn) = api {
43 if let Some(receiver) = efn.receiver() {
44 if receiver.mutable && !receiver.pinned && is_extern_type_alias(&receiver.ty) {
45 reasons.insert(&receiver.ty.rust, UnpinReason::Receiver(receiver));
46 }
47 }
48 }
49 }
50
51 for (ty, _cfg) in all {
52 if let Type::Ref(ty) = ty {
53 if let Type::Ident(inner) = &ty.inner {
54 if ty.mutable && !ty.pinned && is_extern_type_alias(inner) {
55 reasons.insert(&inner.rust, UnpinReason::Ref(ty));
56 }
57 }
58 }
59 }
60
61 reasons
62}