wowlab_engine_domain/rotation/buffer/
descriptor_table.rs1use wowlab_types::sim::FastMap;
2
3use super::{DescriptorId, FieldDescriptor};
4
5#[derive(Debug)]
7pub struct DescriptorTable {
8 descriptors: Vec<&'static FieldDescriptor>,
9 index: FastMap<&'static str, FastMap<&'static str, DescriptorId>>,
10}
11
12#[derive(Debug)]
14pub struct DescriptorIter<'a> {
15 inner: std::iter::Enumerate<std::slice::Iter<'a, &'static FieldDescriptor>>,
16}
17
18impl<'a> Iterator for DescriptorIter<'a> {
19 type Item = (DescriptorId, &'a FieldDescriptor);
20
21 fn next(&mut self) -> Option<Self::Item> {
22 let (index, descriptor) = self.inner.next()?;
23 let id = u16::try_from(index).ok()?;
24
25 Some((DescriptorId::new(id), *descriptor))
26 }
27
28 fn size_hint(&self) -> (usize, Option<usize>) {
29 self.inner.size_hint()
30 }
31}
32
33impl ExactSizeIterator for DescriptorIter<'_> {}
34impl std::iter::FusedIterator for DescriptorIter<'_> {}
35
36impl DescriptorTable {
37 #[must_use]
43 pub fn build() -> Self {
44 let descriptors: Vec<&'static FieldDescriptor> =
45 inventory::iter::<FieldDescriptor>.into_iter().collect();
46 let mut index: FastMap<&'static str, FastMap<&'static str, DescriptorId>> =
47 FastMap::default();
48
49 for (i, d) in descriptors.iter().enumerate() {
50 let id = DescriptorId::new(
51 u16::try_from(i).expect("descriptor count exceeds u16 identifier space"),
52 );
53
54 index.entry(d.domain).or_default().insert(d.name, id);
55 }
56
57 Self { descriptors, index }
58 }
59
60 #[must_use]
62 pub fn len(&self) -> usize {
63 self.descriptors.len()
64 }
65
66 #[must_use]
68 pub fn is_empty(&self) -> bool {
69 self.descriptors.is_empty()
70 }
71
72 #[must_use]
74 pub fn iter(&self) -> DescriptorIter<'_> {
75 DescriptorIter {
76 inner: self.descriptors.iter().enumerate(),
77 }
78 }
79
80 pub(crate) fn lookup(
81 &self,
82 domain: &str,
83 name: &str,
84 ) -> Option<(DescriptorId, &FieldDescriptor)> {
85 let &id = self.index.get(domain)?.get(name)?;
86
87 Some((id, self.descriptors[id.as_usize()]))
89 }
90
91 pub(crate) fn get(&self, id: DescriptorId) -> Option<&FieldDescriptor> {
92 self.descriptors.get(id.as_usize()).copied()
93 }
94
95 #[cfg(test)]
96 pub(crate) fn domain<'a>(
97 &'a self,
98 domain: &'a str,
99 ) -> impl Iterator<Item = (DescriptorId, &'a FieldDescriptor)> + 'a {
100 self.descriptors
101 .iter()
102 .enumerate()
103 .filter(move |(_, d)| d.domain == domain)
104 .filter_map(|(index, descriptor)| {
105 u16::try_from(index)
106 .ok()
107 .map(|id| (DescriptorId::new(id), *descriptor))
108 })
109 }
110}
111
112impl<'a> IntoIterator for &'a DescriptorTable {
113 type Item = (DescriptorId, &'a FieldDescriptor);
114 type IntoIter = DescriptorIter<'a>;
115
116 fn into_iter(self) -> Self::IntoIter {
117 self.iter()
118 }
119}