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 && let Type::Ident(inner) = &slice.inner
34 && slice.mutable
35 && is_extern_type_alias(inner)
36 {
37 reasons.insert(&inner.rust, UnpinReason::Slice(slice));
38 }
39 }
40
41 for api in apis {
42 if let Api::CxxFunction(efn) | Api::RustFunction(efn) = api
43 && let Some(receiver) = efn.receiver()
44 && receiver.mutable
45 && !receiver.pinned
46 && is_extern_type_alias(&receiver.ty)
47 {
48 reasons.insert(&receiver.ty.rust, UnpinReason::Receiver(receiver));
49 }
50 }
51
52 for (ty, _cfg) in all {
53 if let Type::Ref(ty) = ty
54 && let Type::Ident(inner) = &ty.inner
55 && ty.mutable
56 && !ty.pinned
57 && is_extern_type_alias(inner)
58 {
59 reasons.insert(&inner.rust, UnpinReason::Ref(ty));
60 }
61 }
62
63 reasons
64}