From 1b4639977549c1f54c23caa70b8c81c772352b1e Mon Sep 17 00:00:00 2001 From: Kenny Kerr Date: Wed, 11 Sep 2024 14:36:43 -0500 Subject: [PATCH] Improvements to `windows-metadata` (#3268) --- crates/libs/bindgen/src/metadata.rs | 77 +++++------ crates/libs/bindgen/src/rust/cfg.rs | 6 +- crates/libs/metadata/src/blob.rs | 56 ++++---- crates/libs/metadata/src/column.rs | 11 -- crates/libs/metadata/src/file.rs | 205 ++++++++++++++++++++++++++-- crates/libs/metadata/src/lib.rs | 62 +-------- crates/libs/metadata/src/reader.rs | 19 ++- crates/libs/metadata/src/row.rs | 96 ++----------- crates/libs/metadata/src/table.rs | 47 ------- crates/libs/metadata/src/tables.rs | 63 +++++---- 10 files changed, 320 insertions(+), 322 deletions(-) delete mode 100644 crates/libs/metadata/src/column.rs delete mode 100644 crates/libs/metadata/src/table.rs diff --git a/crates/libs/bindgen/src/metadata.rs b/crates/libs/bindgen/src/metadata.rs index b22d0d16a3..c49fa61e89 100644 --- a/crates/libs/bindgen/src/metadata.rs +++ b/crates/libs/bindgen/src/metadata.rs @@ -266,48 +266,43 @@ pub fn type_def_generics(def: TypeDef) -> Vec { // TODO: namespace should not be required - it's a hack to accomodate Win32 metadata // TODO: this is very Rust-specific and Win32-metadata specific with all of its translation. Replace with literal signature parser that just returns slice of types. pub fn method_def_signature(namespace: &str, row: MethodDef, generics: &[Type]) -> Signature { - let reader = row.reader(); - let mut blob = row.blob(4); - let call_flags = MethodCallAttributes(blob.read_usize() as u8); - let _param_count = blob.read_usize(); - let mut return_type = reader.type_from_blob(&mut blob, None, generics); - - let mut params: Vec = row - .params() - .filter_map(|param| { + let signature = row.signature(generics); + + let mut return_type = signature.return_type.0; + + if let Some(param) = signature.return_type.1 { + if param.has_attribute("ConstAttribute") { + return_type = return_type.clone().to_const_type(); + } + } + + let mut params: Vec = signature + .params + .into_iter() + .map(|(mut ty, param)| { let param_is_const = param.has_attribute("ConstAttribute"); - if param.sequence() == 0 { - if param_is_const { - return_type = return_type.clone().to_const_type(); - } - None - } else { - let is_output = param.flags().contains(ParamAttributes::Out); - let mut ty = reader.type_from_blob(&mut blob, None, generics); - - if let Some(name) = param_or_enum(param) { - let def = reader - .get_type_def(namespace, &name) - .next() - .expect("Enum not found"); - ty = Type::PrimitiveOrEnum( - Box::new(ty), - Box::new(Type::TypeDef(def, Vec::new())), - ); - } + let is_output = param.flags().contains(ParamAttributes::Out); - if param_is_const || !is_output { - ty = ty.to_const_type(); - } - if !is_output { - ty = ty.to_const_ptr(); - } - let kind = param_kind(param); - Some(SignatureParam { - def: param, - ty, - kind, - }) + if let Some(name) = param_or_enum(param) { + let def = row + .reader() + .get_type_def(namespace, &name) + .next() + .expect("Enum not found"); + ty = Type::PrimitiveOrEnum(Box::new(ty), Box::new(Type::TypeDef(def, Vec::new()))); + } + + if param_is_const || !is_output { + ty = ty.to_const_type(); + } + if !is_output { + ty = ty.to_const_ptr(); + } + let kind = param_kind(param); + SignatureParam { + def: param, + ty, + kind, } }) .collect(); @@ -395,7 +390,7 @@ pub fn method_def_signature(namespace: &str, row: MethodDef, generics: &[Type]) def: row, params, return_type, - call_flags, + call_flags: signature.call_flags, } } diff --git a/crates/libs/bindgen/src/rust/cfg.rs b/crates/libs/bindgen/src/rust/cfg.rs index 40e94795da..8ab7afc90c 100644 --- a/crates/libs/bindgen/src/rust/cfg.rs +++ b/crates/libs/bindgen/src/rust/cfg.rs @@ -157,12 +157,12 @@ pub fn signature_cfg(writer: &Writer, method: metadata::MethodDef) -> Cfg { cfg_add_attributes(&mut cfg, method); cfg } -fn signature_cfg_combine(writer: &Writer, signature: &metadata::MethodDefSig, cfg: &mut Cfg) { - type_cfg_combine(writer, &signature.return_type, cfg); +fn signature_cfg_combine(writer: &Writer, signature: &windows_metadata::Signature, cfg: &mut Cfg) { + type_cfg_combine(writer, &signature.return_type.0, cfg); signature .params .iter() - .for_each(|param| type_cfg_combine(writer, param, cfg)); + .for_each(|param| type_cfg_combine(writer, ¶m.0, cfg)); } fn cfg_add_attributes>(cfg: &mut Cfg, row: R) { diff --git a/crates/libs/metadata/src/blob.rs b/crates/libs/metadata/src/blob.rs index 204151bac7..9c2f66e2dc 100644 --- a/crates/libs/metadata/src/blob.rs +++ b/crates/libs/metadata/src/blob.rs @@ -1,8 +1,8 @@ use super::*; pub struct Blob { - pub file: &'static File, - pub slice: &'static [u8], + file: &'static File, + slice: &'static [u8], } impl std::ops::Deref for Blob { @@ -14,11 +14,11 @@ impl std::ops::Deref for Blob { } impl Blob { - pub fn new(file: &'static File, slice: &'static [u8]) -> Self { + pub(crate) fn new(file: &'static File, slice: &'static [u8]) -> Self { Self { file, slice } } - pub fn peek_usize(&self) -> (usize, usize) { + fn peek(&self) -> (usize, usize) { if self[0] & 0x80 == 0 { (self[0] as usize, 1) } else if self[0] & 0xC0 == 0x80 { @@ -34,14 +34,12 @@ impl Blob { } } - pub fn read_usize(&mut self) -> usize { - let (value, offset) = self.peek_usize(); - self.offset(offset); - value + pub fn decode(&mut self) -> D { + D::decode(self.file, self.read_usize()) } - pub fn read_expected(&mut self, expected: usize) -> bool { - let (value, offset) = self.peek_usize(); + pub(crate) fn try_read(&mut self, expected: usize) -> bool { + let (value, offset) = self.peek(); if value == expected { self.offset(offset); true @@ -50,10 +48,10 @@ impl Blob { } } - pub fn read_modifiers(&mut self) -> Vec { + pub(crate) fn read_modifiers(&mut self) -> Vec { let mut mods = vec![]; loop { - let (value, offset) = self.peek_usize(); + let (value, offset) = self.peek(); if value != ELEMENT_TYPE_CMOD_OPT as usize && value != ELEMENT_TYPE_CMOD_REQD as usize { break; } else { @@ -64,14 +62,20 @@ impl Blob { mods } - pub fn read_str(&mut self) -> &'static str { + pub fn read_usize(&mut self) -> usize { + let (value, offset) = self.peek(); + self.offset(offset); + value + } + + pub(crate) fn read_str(&mut self) -> &'static str { let len = self.read_usize(); let value = unsafe { std::str::from_utf8_unchecked(&self.slice[..len]) }; self.offset(len); value } - pub fn read_string(self) -> String { + pub(crate) fn read_utf16(self) -> String { let slice = self.slice; if slice.as_ptr().align_offset(std::mem::align_of::()) > 0 { let slice = slice @@ -88,7 +92,7 @@ impl Blob { } } - pub fn read_bool(&mut self) -> bool { + pub(crate) fn read_bool(&mut self) -> bool { // A bool is specified as "a single byte with value 0 (false) or 1 (true)". match self.read_u8() { 0 => false, @@ -97,67 +101,67 @@ impl Blob { } } - pub fn read_i8(&mut self) -> i8 { + pub(crate) fn read_i8(&mut self) -> i8 { let value = i8::from_le_bytes(self[..1].try_into().unwrap()); self.offset(1); value } - pub fn read_u8(&mut self) -> u8 { + pub(crate) fn read_u8(&mut self) -> u8 { let value = u8::from_le_bytes(self[..1].try_into().unwrap()); self.offset(1); value } - pub fn read_i16(&mut self) -> i16 { + pub(crate) fn read_i16(&mut self) -> i16 { let value = i16::from_le_bytes(self[..2].try_into().unwrap()); self.offset(2); value } - pub fn read_u16(&mut self) -> u16 { + pub(crate) fn read_u16(&mut self) -> u16 { let value = u16::from_le_bytes(self[..2].try_into().unwrap()); self.offset(2); value } - pub fn read_i32(&mut self) -> i32 { + pub(crate) fn read_i32(&mut self) -> i32 { let value = i32::from_le_bytes(self[..4].try_into().unwrap()); self.offset(4); value } - pub fn read_u32(&mut self) -> u32 { + pub(crate) fn read_u32(&mut self) -> u32 { let value = u32::from_le_bytes(self[..4].try_into().unwrap()); self.offset(4); value } - pub fn read_i64(&mut self) -> i64 { + pub(crate) fn read_i64(&mut self) -> i64 { let value = i64::from_le_bytes(self[..8].try_into().unwrap()); self.offset(8); value } - pub fn read_u64(&mut self) -> u64 { + pub(crate) fn read_u64(&mut self) -> u64 { let value = u64::from_le_bytes(self[..8].try_into().unwrap()); self.offset(8); value } - pub fn read_f32(&mut self) -> f32 { + pub(crate) fn read_f32(&mut self) -> f32 { let value = f32::from_le_bytes(self[..4].try_into().unwrap()); self.offset(4); value } - pub fn read_f64(&mut self) -> f64 { + pub(crate) fn read_f64(&mut self) -> f64 { let value = f64::from_le_bytes(self[..8].try_into().unwrap()); self.offset(8); value } - pub fn read_integer(&mut self, ty: Type) -> Value { + pub(crate) fn read_integer(&mut self, ty: Type) -> Value { match ty { Type::I8 => Value::I8(self.read_i8()), Type::U8 => Value::U8(self.read_u8()), diff --git a/crates/libs/metadata/src/column.rs b/crates/libs/metadata/src/column.rs deleted file mode 100644 index 9a678daa89..0000000000 --- a/crates/libs/metadata/src/column.rs +++ /dev/null @@ -1,11 +0,0 @@ -#[derive(Default)] -pub struct Column { - pub offset: usize, - pub width: usize, -} - -impl Column { - pub fn new(offset: usize, width: usize) -> Self { - Self { offset, width } - } -} diff --git a/crates/libs/metadata/src/file.rs b/crates/libs/metadata/src/file.rs index 869a1297d9..6d59009367 100644 --- a/crates/libs/metadata/src/file.rs +++ b/crates/libs/metadata/src/file.rs @@ -1,11 +1,11 @@ use super::*; pub struct File { - pub reader: *const Reader, - pub bytes: Vec, - pub strings: usize, - pub blobs: usize, - pub tables: [Table; 17], + pub(crate) reader: *const Reader, + bytes: Vec, + strings: usize, + blobs: usize, + tables: [Table; 17], } impl std::fmt::Debug for File { @@ -523,7 +523,7 @@ impl File { Some(result) } - pub fn usize(&self, row: usize, table: usize, column: usize) -> usize { + pub(crate) fn usize(&self, row: usize, table: usize, column: usize) -> usize { let table = &self.tables[table]; let column = &table.columns[column]; let offset = table.offset + row * table.width + column.offset; @@ -535,7 +535,92 @@ impl File { } } - pub fn lower_bound_of( + pub(crate) fn str(&'static self, row: usize, table: usize, column: usize) -> &'static str { + let offset = self.strings + self.usize(row, table, column); + let bytes = &self.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") + } + + pub(crate) fn blob(&'static self, row: usize, table: usize, column: usize) -> Blob { + let offset = self.blobs + self.usize(row, table, column); + let initial_byte = self.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 &self.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(self, &self.bytes[offset..offset + blob_size]) + } + + pub(crate) fn list( + &'static self, + row: usize, + table: usize, + column: usize, + ) -> RowIterator { + let first = self.usize(row, table, column) - 1; + let next = row + 1; + let last = if next < self.tables[table].len { + self.usize(next, table, column) - 1 + } else { + self.tables[R::TABLE].len + }; + RowIterator::new(self, first..last) + } + + pub(crate) fn equal_range( + &'static self, + column: usize, + value: usize, + ) -> RowIterator { + let mut first = 0; + let mut last = self.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 = self.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 = self.lower_bound_of(L::TABLE, first, middle, column, value); + first += count; + last = self.upper_bound_of(L::TABLE, middle + 1, first, column, value); + first = first2; + break; + } + } + } + + RowIterator::new(self, first..last) + } + + fn lower_bound_of( &self, table: usize, mut first: usize, @@ -557,7 +642,7 @@ impl File { first } - pub fn upper_bound_of( + fn upper_bound_of( &self, table: usize, mut first: usize, @@ -579,7 +664,7 @@ impl File { first } - pub fn table(&'static self) -> RowIterator { + pub(crate) fn table(&'static self) -> RowIterator { RowIterator::new(self, 0..self.tables[R::TABLE].len) } } @@ -656,3 +741,105 @@ impl View for [u8] { } } } + +#[derive(Default)] +struct Table { + offset: usize, + len: usize, + width: usize, + columns: [Column; 6], +} + +impl Table { + fn index_width(&self) -> usize { + if self.len < (1 << 16) { + 2 + } else { + 4 + } + } + + fn set_columns(&mut self, a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) { + self.width = a + b + c + d + e + f; + self.columns[0] = Column::new(0, a); + if b != 0 { + self.columns[1] = Column::new(a, b); + } + if c != 0 { + self.columns[2] = Column::new(a + b, c); + } + if d != 0 { + self.columns[3] = Column::new(a + b + c, d); + } + if e != 0 { + self.columns[4] = Column::new(a + b + c + d, e); + } + if f != 0 { + self.columns[5] = Column::new(a + b + c + d + e, f); + } + } + + fn set_data(&mut self, offset: &mut usize) { + if self.len != 0 { + let next = *offset + self.len * self.width; + self.offset = *offset; + *offset = next; + } + } +} + +#[derive(Default)] +struct Column { + offset: usize, + width: usize, +} + +impl Column { + fn new(offset: usize, width: usize) -> Self { + Self { offset, width } + } +} + +#[repr(C)] +#[derive(Default)] +struct METADATA_HEADER { + signature: u32, + major_version: u16, + minor_version: u16, + reserved: u32, + length: u32, + version: [u8; 20], + flags: u16, + streams: u16, +} + +const METADATA_SIGNATURE: u32 = 0x424A_5342; + +// A coded index (see codes.rs) is a table index that may refer to different tables. The size of the column in memory +// must therefore be large enough to hold an index for a row in the largest possible table. This function determines +// this size for the given winmd file. +fn coded_index_size(tables: &[usize]) -> usize { + fn small(row_count: usize, bits: u8) -> bool { + (row_count as u64) < (1u64 << (16 - bits)) + } + + fn bits_needed(value: usize) -> u8 { + let mut value = value - 1; + let mut bits: u8 = 1; + while { + value >>= 1; + value != 0 + } { + bits += 1; + } + bits + } + + let bits_needed = bits_needed(tables.len()); + + if tables.iter().all(|table| small(*table, bits_needed)) { + 2 + } else { + 4 + } +} diff --git a/crates/libs/metadata/src/lib.rs b/crates/libs/metadata/src/lib.rs index 618fec534a..c581a8116e 100644 --- a/crates/libs/metadata/src/lib.rs +++ b/crates/libs/metadata/src/lib.rs @@ -8,74 +8,26 @@ mod attributes; mod bindings; mod blob; mod codes; -mod column; mod file; mod filter; mod reader; mod row; -mod table; mod tables; mod r#type; mod type_name; pub use attributes::*; -pub use bindings::*; -pub use blob::*; +use bindings::*; +use blob::*; pub use codes::*; -use column::*; pub use file::*; use filter::*; pub use r#type::*; pub use reader::*; pub use row::*; -use table::*; pub use tables::*; pub use type_name::*; -#[repr(C)] -#[derive(Default)] -pub struct METADATA_HEADER { - pub signature: u32, - pub major_version: u16, - pub minor_version: u16, - pub reserved: u32, - pub length: u32, - pub version: [u8; 20], - pub flags: u16, - pub streams: u16, -} - -pub const METADATA_SIGNATURE: u32 = 0x424A_5342; - -// A coded index (see codes.rs) is a table index that may refer to different tables. The size of the column in memory -// must therefore be large enough to hold an index for a row in the largest possible table. This function determines -// this size for the given winmd file. -pub fn coded_index_size(tables: &[usize]) -> usize { - fn small(row_count: usize, bits: u8) -> bool { - (row_count as u64) < (1u64 << (16 - bits)) - } - - fn bits_needed(value: usize) -> u8 { - let mut value = value - 1; - let mut bits: u8 = 1; - while { - value >>= 1; - value != 0 - } { - bits += 1; - } - bits - } - - let bits_needed = bits_needed(tables.len()); - - if tables.iter().all(|table| small(*table, bits_needed)) { - 2 - } else { - 4 - } -} - #[derive(Debug)] pub enum Value { Bool(bool), @@ -95,17 +47,17 @@ pub enum Value { } #[derive(Debug)] -pub struct MethodDefSig { +pub struct Signature { pub call_flags: MethodCallAttributes, - pub return_type: Type, - pub params: Vec, + pub return_type: (Type, Option), + pub params: Vec<(Type, Param)>, } -impl MethodDefSig { +impl Signature { pub fn size(&self) -> usize { self.params .iter() - .fold(0, |sum, param| sum + std::cmp::max(4, param.size())) + .fold(0, |sum, param| sum + std::cmp::max(4, param.0.size())) } } diff --git a/crates/libs/metadata/src/reader.rs b/crates/libs/metadata/src/reader.rs index 7f21fc0c74..b0d595f228 100644 --- a/crates/libs/metadata/src/reader.rs +++ b/crates/libs/metadata/src/reader.rs @@ -10,7 +10,6 @@ pub enum Item { } pub struct Reader { - // TODO: get rid of inner Vec - that's just a hack to support multi-arch structs in Win32 metadata. items: BTreeMap<&'static str, BTreeMap<&'static str, Vec>>, nested: HashMap>, @@ -315,17 +314,17 @@ impl Reader { // Used by WinRT to indicate an output parameter, but there are other ways to determine this direction so here // it is only used to distinguish between slices and heap-allocated arrays. - let is_ref = blob.read_expected(ELEMENT_TYPE_BYREF as usize); + let is_ref = blob.try_read(ELEMENT_TYPE_BYREF as usize); - if blob.read_expected(ELEMENT_TYPE_VOID as usize) { + if blob.try_read(ELEMENT_TYPE_VOID as usize) { return Type::Void; } - let is_array = blob.read_expected(ELEMENT_TYPE_SZARRAY as usize); // Used by WinRT to indicate an array + let is_array = blob.try_read(ELEMENT_TYPE_SZARRAY as usize); // Used by WinRT to indicate an array let mut pointers = 0; - while blob.read_expected(ELEMENT_TYPE_PTR as usize) { + while blob.try_read(ELEMENT_TYPE_PTR as usize) { pointers += 1; } @@ -359,11 +358,9 @@ impl Reader { } match code as u8 { - ELEMENT_TYPE_VALUETYPE | ELEMENT_TYPE_CLASS => self.type_from_ref( - TypeDefOrRef::decode(blob.file, blob.read_usize()), - enclosing, - generics, - ), + ELEMENT_TYPE_VALUETYPE | ELEMENT_TYPE_CLASS => { + self.type_from_ref(blob.decode(), enclosing, generics) + } ELEMENT_TYPE_VAR => generics .get(blob.read_usize()) .unwrap_or(&Type::Void) @@ -378,7 +375,7 @@ impl Reader { ELEMENT_TYPE_GENERICINST => { blob.read_usize(); // ELEMENT_TYPE_VALUETYPE or ELEMENT_TYPE_CLASS - let type_name = TypeDefOrRef::decode(blob.file, blob.read_usize()).type_name(); + let type_name = blob.decode::().type_name(); let def = self .get_type_def(type_name.namespace(), type_name.name()) .next() diff --git a/crates/libs/metadata/src/row.rs b/crates/libs/metadata/src/row.rs index 7e329b8b0a..80fd247860 100644 --- a/crates/libs/metadata/src/row.rs +++ b/crates/libs/metadata/src/row.rs @@ -2,21 +2,14 @@ use super::*; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd)] pub struct Row { - pub file: &'static File, - pub index: usize, + file: &'static File, + index: usize, } impl Row { - pub fn new(file: &'static File, index: usize) -> Self { + pub(crate) fn new(file: &'static File, index: usize) -> Self { Self { file, index } } - - fn next(&self) -> Self { - Self { - file: self.file, - index: self.index + 1, - } - } } pub trait AsRow: Copy { @@ -37,23 +30,12 @@ pub trait AsRow: Copy { 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") + self.file().str(self.index(), Self::TABLE, column) } fn row(&self, column: usize) -> Row { @@ -65,72 +47,11 @@ pub trait AsRow: Copy { } 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]) + self.file().blob(self.index(), Self::TABLE, column) } fn list(&self, column: usize) -> RowIterator { - 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(&self, column: usize, value: usize) -> RowIterator { - 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) + self.file().list(self.index(), Self::TABLE, column) } } @@ -141,7 +62,7 @@ pub struct RowIterator { } impl RowIterator { - pub fn new(file: &'static File, rows: std::ops::Range) -> Self { + pub(crate) fn new(file: &'static File, rows: std::ops::Range) -> Self { Self { file, rows, @@ -168,7 +89,8 @@ pub trait HasAttributes { impl> HasAttributes for R { fn attributes(&self) -> RowIterator { - self.equal_range(0, Into::::into(*self).encode()) + self.file() + .equal_range(0, Into::::into(*self).encode()) } fn find_attribute(&self, name: &str) -> Option { diff --git a/crates/libs/metadata/src/table.rs b/crates/libs/metadata/src/table.rs deleted file mode 100644 index fd34b50b41..0000000000 --- a/crates/libs/metadata/src/table.rs +++ /dev/null @@ -1,47 +0,0 @@ -use super::*; - -#[derive(Default)] -pub struct Table { - pub offset: usize, - pub len: usize, - pub width: usize, - pub columns: [Column; 6], -} - -impl Table { - pub fn index_width(&self) -> usize { - if self.len < (1 << 16) { - 2 - } else { - 4 - } - } - - pub fn set_columns(&mut self, a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) { - self.width = a + b + c + d + e + f; - self.columns[0] = Column::new(0, a); - if b != 0 { - self.columns[1] = Column::new(a, b); - } - if c != 0 { - self.columns[2] = Column::new(a + b, c); - } - if d != 0 { - self.columns[3] = Column::new(a + b + c, d); - } - if e != 0 { - self.columns[4] = Column::new(a + b + c + d, e); - } - if f != 0 { - self.columns[5] = Column::new(a + b + c + d + e, f); - } - } - - pub fn set_data(&mut self, offset: &mut usize) { - if self.len != 0 { - let next = *offset + self.len * self.width; - self.offset = *offset; - *offset = next; - } - } -} diff --git a/crates/libs/metadata/src/tables.rs b/crates/libs/metadata/src/tables.rs index b218d69e3f..c4a0a4bff2 100644 --- a/crates/libs/metadata/src/tables.rs +++ b/crates/libs/metadata/src/tables.rs @@ -125,8 +125,8 @@ impl Attribute { args.push((name, arg)); } - debug_assert_eq!(sig.slice.len(), 0); - debug_assert_eq!(values.slice.len(), 0); + debug_assert_eq!(sig.len(), 0); + debug_assert_eq!(values.len(), 0); args } @@ -157,7 +157,7 @@ impl Constant { Type::U64 => Value::U64(blob.read_u64()), Type::F32 => Value::F32(blob.read_f32()), Type::F64 => Value::F64(blob.read_f64()), - Type::String => Value::String(blob.read_string()), + Type::String => Value::String(blob.read_utf16()), rest => unimplemented!("{rest:?}"), } } @@ -173,7 +173,8 @@ impl Field { } pub fn constant(&self) -> Option { - self.equal_range(1, HasConstant::Field(*self).encode()) + self.file() + .equal_range(1, HasConstant::Field(*self).encode()) .next() } @@ -229,22 +230,6 @@ impl MemberRef { pub fn name(&self) -> &'static str { self.str(1) } - - pub fn signature(&self) -> MethodDefSig { - let reader = self.reader(); - let mut blob = self.blob(2); - let call_flags = MethodCallAttributes(blob.read_usize() as u8); - let params = blob.read_usize(); - let return_type = reader.type_from_blob(&mut blob, None, &[]); - - MethodDefSig { - call_flags, - return_type, - params: (0..params) - .map(|_| reader.type_from_blob(&mut blob, None, &[])) - .collect(), - } - } } impl MethodDef { @@ -265,7 +250,8 @@ impl MethodDef { } pub fn impl_map(&self) -> Option { - self.equal_range(1, MemberForwarded::MethodDef(*self).encode()) + self.file() + .equal_range(1, MemberForwarded::MethodDef(*self).encode()) .next() } @@ -273,19 +259,30 @@ impl MethodDef { self.impl_map().map_or("", |map| map.scope().name()) } - pub fn signature(&self, generics: &[Type]) -> MethodDefSig { + pub fn signature(&self, generics: &[Type]) -> Signature { let reader = self.reader(); let mut blob = self.blob(4); let call_flags = MethodCallAttributes(blob.read_usize() as u8); - let params = blob.read_usize(); + let _param_count = blob.read_usize(); let return_type = reader.type_from_blob(&mut blob, None, generics); + let mut return_param = None; + + let params = self + .params() + .filter_map(|param| { + if param.sequence() == 0 { + return_param = Some(param); + None + } else { + Some((reader.type_from_blob(&mut blob, None, generics), param)) + } + }) + .collect(); - MethodDefSig { + Signature { call_flags, - return_type, - params: (0..params) - .map(|_| reader.type_from_blob(&mut blob, None, generics)) - .collect(), + return_type: (return_type, return_param), + params, } } } @@ -356,21 +353,23 @@ impl TypeDef { } pub fn generics(&self) -> RowIterator { - self.equal_range(2, TypeOrMethodDef::TypeDef(*self).encode()) + self.file() + .equal_range(2, TypeOrMethodDef::TypeDef(*self).encode()) } pub fn interface_impls(&self) -> RowIterator { - self.equal_range(0, self.index() + 1) + self.file().equal_range(0, self.index() + 1) } pub fn enclosing_type(&self) -> Option { - self.equal_range::(0, self.index() + 1) + self.file() + .equal_range::(0, self.index() + 1) .next() .map(|row| TypeDef(row.row(1))) } pub fn class_layout(&self) -> Option { - self.equal_range(2, self.index() + 1).next() + self.file().equal_range(2, self.index() + 1).next() } pub fn underlying_type(&self) -> Type {