windows_metadata/reader/
type_index.rs1use super::*;
2
3pub struct TypeIndex {
4 files: Vec<File>,
5 types: HashMap<String, HashMap<String, Vec<(usize, usize)>>>,
6 nested: HashMap<(usize, usize), Vec<usize>>,
7}
8
9impl TypeIndex {
10 pub fn read<P: AsRef<std::path::Path>>(path: P) -> Option<Self> {
11 Some(Self::new(vec![File::read(path)?]))
12 }
13
14 pub fn new(files: Vec<File>) -> Self {
15 let mut types: HashMap<String, HashMap<String, Vec<(usize, usize)>>> = HashMap::new();
16 let mut nested: HashMap<(usize, usize), Vec<usize>> = HashMap::new();
17
18 for (file_pos, file) in files.iter().enumerate() {
19 for def_pos in file.TypeDef() {
20 let namespace = file.str(def_pos, TypeDef::TABLE, 2);
21
22 if namespace.is_empty() {
23 continue;
25 }
26
27 let name = file.str(def_pos, TypeDef::TABLE, 1);
28
29 types
30 .entry(namespace.to_string())
31 .or_default()
32 .entry(trim_tick(name).to_string())
33 .or_default()
34 .push((file_pos, def_pos));
35 }
36
37 for map in file.NestedClass() {
38 let inner = file.usize(map, NestedClass::TABLE, 0) - 1;
39 let outer = file.usize(map, NestedClass::TABLE, 1) - 1;
40 nested.entry((file_pos, outer)).or_default().push(inner);
41 }
42 }
43
44 Self {
45 files,
46 types,
47 nested,
48 }
49 }
50
51 pub(crate) fn files(&self, pos: usize) -> &File {
52 &self.files[pos]
53 }
54
55 pub fn iter(&self) -> impl Iterator<Item = (&str, &str, TypeDef<'_>)> + '_ {
56 self.types
57 .iter()
58 .flat_map(|(namespace, types)| {
59 types
60 .iter()
61 .map(move |(name, types)| (namespace.as_str(), name.as_str(), types))
62 })
63 .flat_map(|(namespace, name, types)| types.iter().map(move |ty| (namespace, name, ty)))
64 .map(|(namespace, name, (file, pos))| {
65 (namespace, name, TypeDef(Row::new(self, *file, *pos)))
66 })
67 }
68
69 pub fn types(&self) -> impl Iterator<Item = TypeDef<'_>> + '_ {
70 self.types
71 .values()
72 .flat_map(|types| types.values())
73 .flatten()
74 .map(|(file, pos)| TypeDef(Row::new(self, *file, *pos)))
75 }
76
77 pub fn get(&self, namespace: &str, name: &str) -> impl Iterator<Item = TypeDef<'_>> + '_ {
78 self.types
79 .get(namespace)
80 .and_then(|types| types.get(name))
81 .into_iter()
82 .flatten()
83 .map(|(file, pos)| TypeDef(Row::new(self, *file, *pos)))
84 }
85
86 pub fn contains(&self, namespace: &str, name: &str) -> bool {
87 self.types
88 .get(namespace)
89 .and_then(|types| types.get(name))
90 .is_some()
91 }
92
93 #[track_caller]
94 pub fn expect(&self, namespace: &str, name: &str) -> TypeDef<'_> {
95 let mut iter = self.get(namespace, name);
96
97 if let Some(def) = iter.next() {
98 if iter.next().is_none() {
99 def
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 pub fn nested(&self, ty: TypeDef) -> impl Iterator<Item = TypeDef<'_>> + '_ {
109 self.nested
110 .get(&(ty.0.file, ty.0.pos))
111 .into_iter()
112 .flatten()
113 .cloned()
114 .map(move |pos| {
115 TypeDef(Row {
116 index: self,
117 file: ty.0.file,
118 pos,
119 })
120 })
121 }
122}