summaryrefslogtreecommitdiffstats
path: root/vendor/windows-metadata/src/row.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:25:56 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:25:56 +0000
commit018c4950b9406055dec02ef0fb52f132e2bb1e2c (patch)
treea835ebdf2088ef88fa681f8fad45f09922c1ae9a /vendor/windows-metadata/src/row.rs
parentAdding debian version 1.75.0+dfsg1-5. (diff)
downloadrustc-018c4950b9406055dec02ef0fb52f132e2bb1e2c.tar.xz
rustc-018c4950b9406055dec02ef0fb52f132e2bb1e2c.zip
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/windows-metadata/src/row.rs')
-rw-r--r--vendor/windows-metadata/src/row.rs164
1 files changed, 119 insertions, 45 deletions
diff --git a/vendor/windows-metadata/src/row.rs b/vendor/windows-metadata/src/row.rs
index 4e0c30593..4b99f5685 100644
--- a/vendor/windows-metadata/src/row.rs
+++ b/vendor/windows-metadata/src/row.rs
@@ -1,16 +1,18 @@
-#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)]
+use super::*;
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd)]
pub struct Row {
- pub row: usize,
- pub file: usize,
+ pub file: &'static File,
+ pub index: usize,
}
impl Row {
- pub fn new(row: usize, file: usize) -> Self {
- Self { row, file }
+ pub fn new(file: &'static File, index: usize) -> Self {
+ Self { file, index }
}
fn next(&self) -> Self {
- Self { row: self.row + 1, file: self.file }
+ Self { file: self.file, index: self.index + 1 }
}
}
@@ -19,27 +21,117 @@ pub trait AsRow: Copy {
fn to_row(&self) -> Row;
fn from_row(row: Row) -> Self;
- fn file(&self) -> usize {
+ fn file(&self) -> &'static File {
self.to_row().file
}
+ fn reader(&self) -> &'static Reader {
+ // Safety: At this point the File is already pointing to a valid Reader.
+ unsafe { &*self.file().reader }
+ }
+
fn index(&self) -> usize {
- self.to_row().row
+ self.to_row().index
}
fn next(&self) -> Self {
Self::from_row(self.to_row().next())
}
+
+ fn usize(&self, column: usize) -> usize {
+ self.file().usize(self.index(), Self::TABLE, column)
+ }
+
+ fn str(&self, column: usize) -> &'static str {
+ let file = self.file();
+ let offset = file.strings + self.usize(column);
+ let bytes = &file.bytes[offset..];
+ let nul_pos = bytes.iter().position(|&c| c == 0).expect("expected null-terminated C-string");
+ std::str::from_utf8(&bytes[..nul_pos]).expect("expected valid utf-8 C-string")
+ }
+
+ fn row(&self, column: usize) -> Row {
+ Row::new(self.file(), self.usize(column) - 1)
+ }
+
+ fn decode<T: Decode>(&self, column: usize) -> T {
+ T::decode(self.file(), self.usize(column))
+ }
+
+ fn blob(&self, column: usize) -> Blob {
+ let file = self.file();
+ let offset = file.blobs + self.usize(column);
+ let initial_byte = file.bytes[offset];
+
+ let (blob_size, blob_size_bytes) = match initial_byte >> 5 {
+ 0..=3 => (initial_byte & 0x7f, 1),
+ 4..=5 => (initial_byte & 0x3f, 2),
+ 6 => (initial_byte & 0x1f, 4),
+ rest => unimplemented!("{rest:?}"),
+ };
+
+ let mut blob_size = blob_size as usize;
+
+ for byte in &file.bytes[offset + 1..offset + blob_size_bytes] {
+ blob_size = blob_size.checked_shl(8).unwrap_or(0) + (*byte as usize);
+ }
+
+ let offset = offset + blob_size_bytes;
+ Blob::new(file, &file.bytes[offset..offset + blob_size])
+ }
+
+ fn list<R: AsRow>(&self, column: usize) -> RowIterator<R> {
+ let file = self.file();
+ let first = self.usize(column) - 1;
+ let next = self.next();
+ let last = if next.index() < file.tables[Self::TABLE].len { next.usize(column) - 1 } else { file.tables[R::TABLE].len };
+ RowIterator::new(file, first..last)
+ }
+
+ fn equal_range<L: AsRow>(&self, column: usize, value: usize) -> RowIterator<L> {
+ let file = self.file();
+ let mut first = 0;
+ let mut last = file.tables[L::TABLE].len;
+ let mut count = last;
+
+ loop {
+ if count == 0 {
+ last = first;
+ break;
+ }
+
+ let count2 = count / 2;
+ let middle = first + count2;
+ let middle_value = file.usize(middle, L::TABLE, column);
+
+ match middle_value.cmp(&value) {
+ Ordering::Less => {
+ first = middle + 1;
+ count -= count2 + 1;
+ }
+ Ordering::Greater => count = count2,
+ Ordering::Equal => {
+ let first2 = file.lower_bound_of(L::TABLE, first, middle, column, value);
+ first += count;
+ last = file.upper_bound_of(L::TABLE, middle + 1, first, column, value);
+ first = first2;
+ break;
+ }
+ }
+ }
+
+ RowIterator::new(file, first..last)
+ }
}
pub struct RowIterator<R: AsRow> {
- file: usize,
+ file: &'static File,
rows: std::ops::Range<usize>,
phantom: std::marker::PhantomData<R>,
}
impl<R: AsRow> RowIterator<R> {
- pub fn new(file: usize, rows: std::ops::Range<usize>) -> Self {
+ pub fn new(file: &'static File, rows: std::ops::Range<usize>) -> Self {
Self { file, rows, phantom: std::marker::PhantomData }
}
}
@@ -48,44 +140,26 @@ impl<R: AsRow> Iterator for RowIterator<R> {
type Item = R;
fn next(&mut self) -> Option<Self::Item> {
- self.rows.next().map(|row| R::from_row(Row::new(row, self.file)))
+ self.rows.next().map(|row| R::from_row(Row::new(self.file, row)))
}
}
-macro_rules! tables {
- ($(($name:ident, $table:literal))+) => {
- $(
- #[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)]
- pub struct $name(pub(crate) Row);
- impl AsRow for $name {
- const TABLE: usize = $table;
- fn to_row(&self) -> Row {
- self.0
- }
- fn from_row(row: Row) -> Self {
- $name(row)
- }
- }
- )*
-};
+pub trait HasAttributes {
+ fn attributes(&self) -> RowIterator<Attribute>;
+ fn find_attribute(&self, name: &str) -> Option<Attribute>;
+ fn has_attribute(&self, name: &str) -> bool;
}
-tables! {
- (Attribute, 1)
- (ClassLayout, 16)
- (Constant, 0)
- (Field, 2)
- (GenericParam, 3)
- (ImplMap, 11)
- (InterfaceImpl, 4)
- (MemberRef, 5)
- (MethodDef, 6)
- (Module, 14)
- (ModuleRef, 12)
- (AssemblyRef, 15)
- (Param, 7)
- (TypeDef, 8)
- (TypeRef, 9)
- (TypeSpec, 10)
- (NestedClass, 13)
+impl<R: AsRow + Into<HasAttribute>> HasAttributes for R {
+ fn attributes(&self) -> RowIterator<Attribute> {
+ self.equal_range(0, Into::<HasAttribute>::into(*self).encode())
+ }
+
+ fn find_attribute(&self, name: &str) -> Option<Attribute> {
+ self.attributes().find(|attribute| attribute.name() == name)
+ }
+
+ fn has_attribute(&self, name: &str) -> bool {
+ self.find_attribute(name).is_some()
+ }
}