1use super::*;
2
3#[derive(Copy, Clone)]
4pub struct Row<'a> {
5 pub index: &'a Index,
6 pub file: usize,
7 pub pos: usize,
8}
9
10impl std::fmt::Debug for Row<'_> {
11 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
12 f.debug_struct("Row")
13 .field("file", &self.file)
14 .field("pos", &self.pos)
15 .finish()
16 }
17}
18
19impl std::hash::Hash for Row<'_> {
20 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
21 self.file.hash(state);
22 self.pos.hash(state);
23 }
24}
25
26impl PartialEq for Row<'_> {
27 fn eq(&self, other: &Self) -> bool {
28 (self.file, self.pos) == (other.file, other.pos)
29 }
30}
31
32impl Eq for Row<'_> {}
33
34impl Ord for Row<'_> {
35 fn cmp(&self, other: &Self) -> Ordering {
36 (self.file, self.pos).cmp(&(other.file, other.pos))
37 }
38}
39
40impl PartialOrd for Row<'_> {
41 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
42 Some(self.cmp(other))
43 }
44}
45
46impl<'a> Row<'a> {
47 pub(crate) fn new(index: &'a Index, file: usize, pos: usize) -> Self {
48 Self { index, file, pos }
49 }
50}
51
52pub trait AsRow<'a>: Copy {
53 const TABLE: usize;
54 fn to_row(&self) -> Row<'a>;
55 fn from_row(row: Row<'a>) -> Self;
56
57 fn index(&self) -> &'a Index {
58 let row = self.to_row();
59 row.index
60 }
61
62 fn file(&self) -> &'a File {
63 let row = self.to_row();
64 row.index.files(row.file)
65 }
66
67 fn pos(&self) -> usize {
68 self.to_row().pos
69 }
70
71 fn usize(&self, column: usize) -> usize {
72 self.file().usize(self.pos(), Self::TABLE, column)
73 }
74
75 fn str(&self, column: usize) -> &'a str {
76 self.file().str(self.pos(), Self::TABLE, column)
77 }
78
79 fn row<R: AsRow<'a>>(&self, column: usize) -> R {
80 let row = self.to_row();
81 R::from_row(Row::new(row.index, row.file, self.usize(column) - 1))
82 }
83
84 fn decode<T: Decode<'a>>(&self, column: usize) -> T {
85 let row = self.to_row();
86 T::decode(row.index, row.file, self.usize(column))
87 }
88
89 fn blob(&self, column: usize) -> Blob<'a> {
90 let row = self.to_row();
91 Blob::new(
92 row.index,
93 row.file,
94 self.file().blob(self.pos(), Self::TABLE, column),
95 )
96 }
97
98 fn list<R: AsRow<'a>>(&self, column: usize) -> RowIterator<'a, R> {
99 let row = self.to_row();
100 RowIterator::new(
101 row.index,
102 row.file,
103 self.file().list(self.pos(), Self::TABLE, column, R::TABLE),
104 )
105 }
106
107 fn equal_range<L: AsRow<'a>>(&self, column: usize, value: usize) -> RowIterator<'a, L> {
108 let row = self.to_row();
109
110 RowIterator::new(
111 row.index,
112 row.file,
113 self.file().equal_range(L::TABLE, column, value),
114 )
115 }
116
117 fn parent_row<P: AsRow<'a>>(&self, column: usize) -> P {
118 let row = self.to_row();
119
120 P::from_row(Row::new(
121 row.index,
122 row.file,
123 self.file().parent(self.pos(), P::TABLE, column),
124 ))
125 }
126}
127
128pub struct RowIterator<'a, R: AsRow<'a>> {
129 index: &'a Index,
130 file: usize,
131 rows: std::ops::Range<usize>,
132 phantom: std::marker::PhantomData<R>,
133}
134
135impl<'a, R: AsRow<'a>> RowIterator<'a, R> {
136 pub(crate) fn new(index: &'a Index, file: usize, rows: std::ops::Range<usize>) -> Self {
137 Self {
138 index,
139 file,
140 rows,
141 phantom: std::marker::PhantomData,
142 }
143 }
144}
145
146impl<'a, R: AsRow<'a>> Iterator for RowIterator<'a, R> {
147 type Item = R;
148
149 fn next(&mut self) -> Option<Self::Item> {
150 self.rows
151 .next()
152 .map(|row| R::from_row(Row::new(self.index, self.file, row)))
153 }
154}
155
156impl<'a, R: AsRow<'a>> ExactSizeIterator for RowIterator<'a, R> {
157 fn len(&self) -> usize {
158 self.rows.len()
159 }
160}
161
162pub trait HasAttributes<'a> {
163 fn attributes(&self) -> RowIterator<'a, Attribute<'a>>;
164 fn find_attribute(&self, name: &str) -> Option<Attribute<'a>>;
165 fn has_attribute(&self, name: &str) -> bool;
166 fn arches(&self) -> i32;
167}
168
169impl<'a, R: AsRow<'a> + Into<HasAttribute<'a>>> HasAttributes<'a> for R {
170 fn attributes(&self) -> RowIterator<'a, Attribute<'a>> {
171 self.equal_range(0, Into::<HasAttribute>::into(*self).encode())
172 }
173
174 fn find_attribute(&self, name: &str) -> Option<Attribute<'a>> {
175 self.attributes()
176 .find(|attribute| attribute.ctor().parent().name() == name)
177 }
178
179 fn has_attribute(&self, name: &str) -> bool {
180 self.find_attribute(name).is_some()
181 }
182
183 fn arches(&self) -> i32 {
184 let mut arches = 0;
185
186 if let Some(attribute) = self.find_attribute("SupportedArchitectureAttribute") {
187 arches = match attribute.value().first() {
188 Some((_, Value::I32(v))) => *v,
189 Some((_, Value::EnumValue(_, inner))) => {
190 if let Value::I32(v) = inner.as_ref() {
191 *v
192 } else {
193 0
194 }
195 }
196 _ => 0,
197 };
198 }
199
200 arches
201 }
202}