Skip to main content

windows_metadata/reader/
item_index.rs

1use super::*;
2
3#[derive(Debug)]
4pub enum Item<'a> {
5    Type(TypeDef<'a>),
6    Fn(MethodDef<'a>),
7    Const(Field<'a>),
8}
9
10type HashType<'a> = HashMap<&'a str, HashMap<&'a str, Vec<Item<'a>>>>;
11
12pub struct ItemIndex<'a>(HashType<'a>);
13
14impl<'a> core::ops::Deref for ItemIndex<'a> {
15    type Target = HashType<'a>;
16
17    fn deref(&self) -> &HashType<'a> {
18        &self.0
19    }
20}
21
22impl<'a> ItemIndex<'a> {
23    pub fn new(index: &'a TypeIndex) -> Self {
24        let mut members: HashType = HashMap::new();
25
26        for (namespace, name, ty) in index.iter() {
27            let apis = !ty.flags().contains(TypeAttributes::WindowsRuntime)
28                && ty.category() == TypeCategory::Class
29                && name == "Apis";
30
31            if apis {
32                for method in ty.methods() {
33                    insert(&mut members, namespace, method.name(), Item::Fn(method));
34                }
35                for field in ty.fields() {
36                    insert(&mut members, namespace, field.name(), Item::Const(field));
37                }
38            } else {
39                insert(&mut members, namespace, name, Item::Type(ty));
40            }
41
42            // TODO: get rid of unscoped enums and encode them simply as constants in the first place
43            if !ty.flags().contains(TypeAttributes::WindowsRuntime) {
44                match ty.category() {
45                    TypeCategory::Enum if !ty.has_attribute("ScopedEnumAttribute") => {
46                        for field in ty.fields() {
47                            if field.flags().contains(FieldAttributes::Literal) {
48                                insert(&mut members, namespace, field.name(), Item::Const(field));
49                            }
50                        }
51                    }
52                    _ => {}
53                }
54            }
55        }
56
57        Self(members)
58    }
59
60    pub fn iter(&self) -> impl Iterator<Item = (&str, &str, &Item<'_>)> + '_ {
61        self.0
62            .iter()
63            .flat_map(|(namespace, items)| {
64                items
65                    .iter()
66                    .map(move |(name, items)| (namespace, name, items))
67            })
68            .flat_map(|(namespace, name, items)| {
69                items.iter().map(move |item| (*namespace, *name, item))
70            })
71    }
72
73    pub fn items(&self) -> impl Iterator<Item = &Item<'_>> + '_ {
74        self.0.values().flat_map(|items| items.values()).flatten()
75    }
76
77    pub fn namespace_items(&self, namespace: &str) -> impl Iterator<Item = (&str, &Item<'_>)> + '_ {
78        self.0
79            .get(namespace)
80            .into_iter()
81            .flatten()
82            .flat_map(|(name, items)| items.iter().map(move |item| (*name, item)))
83    }
84
85    pub fn get(&self, namespace: &str, name: &str) -> impl Iterator<Item = &Item<'_>> + '_ {
86        self.0
87            .get(namespace)
88            .and_then(|items| items.get(name))
89            .into_iter()
90            .flatten()
91    }
92
93    #[track_caller]
94    pub fn expect(&self, namespace: &str, name: &str) -> &Item<'_> {
95        let mut iter = self.get(namespace, name);
96
97        if let Some(item) = iter.next() {
98            if iter.next().is_none() {
99                item
100            } else {
101                panic!("more than one type found: {namespace}.{name}");
102            }
103        } else {
104            panic!("type not found: {namespace}.{name}")
105        }
106    }
107}
108
109fn insert<'a>(members: &mut HashType<'a>, namespace: &'a str, name: &'a str, member: Item<'a>) {
110    members
111        .entry(namespace)
112        .or_default()
113        .entry(name)
114        .or_default()
115        .push(member);
116}