1use super::*;
2
3#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd)]
4pub struct Row {
5 file: &'static File,
6 index: usize,
7}
8
9impl Row {
10 pub(crate) fn new(file: &'static File, index: usize) -> Self {
11 Self { file, index }
12 }
13}
14
15pub trait AsRow: Copy {
16 const TABLE: usize;
17 fn to_row(&self) -> Row;
18 fn from_row(row: Row) -> Self;
19
20 fn file(&self) -> &'static File {
21 self.to_row().file
22 }
23
24 fn reader(&self) -> &'static Reader {
25 // Safety: At this point the File is already pointing to a valid Reader.
26 unsafe { &*self.file().reader }
27 }
28
29 fn index(&self) -> usize {
30 self.to_row().index
31 }
32
33 fn usize(&self, column: usize) -> usize {
34 self.file().usize(self.index(), Self::TABLE, column)
35 }
36
37 fn str(&self, column: usize) -> &'static str {
38 self.file().str(self.index(), Self::TABLE, column)
39 }
40
41 fn row(&self, column: usize) -> Row {
42 Row::new(self.file(), self.usize(column) - 1)
43 }
44
45 fn decode<T: Decode>(&self, column: usize) -> T {
46 T::decode(self.file(), self.usize(column))
47 }
48
49 fn blob(&self, column: usize) -> Blob {
50 self.file().blob(self.index(), Self::TABLE, column)
51 }
52
53 fn list<R: AsRow>(&self, column: usize) -> RowIterator<R> {
54 self.file().list(self.index(), Self::TABLE, column)
55 }
56}
57
58pub struct RowIterator<R: AsRow> {
59 file: &'static File,
60 rows: std::ops::Range<usize>,
61 phantom: std::marker::PhantomData<R>,
62}
63
64impl<R: AsRow> RowIterator<R> {
65 pub(crate) fn new(file: &'static File, rows: std::ops::Range<usize>) -> Self {
66 Self {
67 file,
68 rows,
69 phantom: std::marker::PhantomData,
70 }
71 }
72}
73
74impl<R: AsRow> Iterator for RowIterator<R> {
75 type Item = R;
76
77 fn next(&mut self) -> Option<Self::Item> {
78 self.rows
79 .next()
80 .map(|row: usize| R::from_row(Row::new(self.file, index:row)))
81 }
82}
83
84pub trait HasAttributes {
85 fn attributes(&self) -> RowIterator<Attribute>;
86 fn find_attribute(&self, name: &str) -> Option<Attribute>;
87 fn has_attribute(&self, name: &str) -> bool;
88 fn guid_attribute(&self) -> Option<GUID>;
89 fn arches(&self) -> i32;
90}
91
92impl<R: AsRow + Into<HasAttribute>> HasAttributes for R {
93 fn attributes(&self) -> RowIterator<Attribute> {
94 self.file()
95 .equal_range(0, Into::<HasAttribute>::into(*self).encode())
96 }
97
98 fn find_attribute(&self, name: &str) -> Option<Attribute> {
99 self.attributes().find(|attribute| attribute.name() == name)
100 }
101
102 fn has_attribute(&self, name: &str) -> bool {
103 self.find_attribute(name).is_some()
104 }
105
106 fn guid_attribute(&self) -> Option<GUID> {
107 self.find_attribute("GuidAttribute").map(|attribute| {
108 fn unwrap_u32(value: &Value) -> u32 {
109 match value {
110 Value::U32(value) => *value,
111 _ => panic!(),
112 }
113 }
114 fn unwrap_u16(value: &Value) -> u16 {
115 match value {
116 Value::U16(value) => *value,
117 rest => panic!("{rest:?}"),
118 }
119 }
120 fn unwrap_u8(value: &Value) -> u8 {
121 match value {
122 Value::U8(value) => *value,
123 rest => panic!("{rest:?}"),
124 }
125 }
126
127 let args = attribute.args();
128
129 GUID(
130 unwrap_u32(&args[0].1),
131 unwrap_u16(&args[1].1),
132 unwrap_u16(&args[2].1),
133 unwrap_u8(&args[3].1),
134 unwrap_u8(&args[4].1),
135 unwrap_u8(&args[5].1),
136 unwrap_u8(&args[6].1),
137 unwrap_u8(&args[7].1),
138 unwrap_u8(&args[8].1),
139 unwrap_u8(&args[9].1),
140 unwrap_u8(&args[10].1),
141 )
142 })
143 }
144
145 fn arches(&self) -> i32 {
146 let mut arches = 0;
147
148 if let Some(attribute) = self.find_attribute("SupportedArchitectureAttribute") {
149 if let Some((_, Value::I32(value))) = attribute.args().first() {
150 arches = *value;
151 }
152 }
153
154 arches
155 }
156}
157