Struct TablesHeader
pub struct TablesHeader<'a> {
pub major_version: u8,
pub minor_version: u8,
pub valid: u64,
pub sorted: u64,
pub info: TableInfoRef,
/* private fields */
}Expand description
ECMA-335 compliant metadata tables header providing efficient access to .NET assembly metadata.
The crate::metadata::streams::tablesheader::TablesHeader struct represents the compressed metadata tables stream (#~) header
and provides type-safe, memory-efficient access to all metadata tables within a .NET assembly.
This is the primary interface for reflection, analysis, and runtime operations on .NET metadata.
§Architecture and Design
crate::metadata::streams::tablesheader::TablesHeader implements a zero-copy, reference-based design that maximizes performance
while maintaining memory safety through Rust’s lifetime system:
- Zero allocation: All table data remains in the original assembly buffer
- Lazy parsing: Table rows are parsed only when accessed
- Type safety: Generic type parameters prevent incorrect table access
- Lifetime safety: Rust borrow checker prevents dangling references
- ECMA-335 compliance: Full specification adherence for all table formats
§Metadata Tables Overview
The metadata tables system contains 45 different table types defined by ECMA-335, each serving specific purposes in the .NET type system:
§Core Tables (Always Present)
- Module: Assembly module identification and versioning
- TypeDef: Type definitions declared in this assembly
- MethodDef: Method definitions and IL code references
- Field: Field definitions and attributes
§Reference Tables (External Dependencies)
- TypeRef: References to types in other assemblies
- MemberRef: References to methods/fields in external types
- AssemblyRef: External assembly dependencies
- ModuleRef: Multi-module assembly references
§Relationship Tables (Type System Structure)
- InterfaceImpl: Interface implementation relationships
- NestedClass: Nested type parent-child relationships
- GenericParam: Generic type and method parameters
- GenericParamConstraint: Generic parameter constraints
§Attribute and Metadata Tables
- CustomAttribute: Custom attribute applications
- Constant: Compile-time constant values
- DeclSecurity: Declarative security permissions
- FieldMarshal: Native interop marshalling specifications
§Thread Safety and Concurrency
crate::metadata::streams::tablesheader::TablesHeader provides comprehensive thread safety for concurrent metadata access:
- Immutable data: All table data read-only after construction
- Independent access: Multiple threads can access different tables safely
- Parallel iteration: Safe concurrent processing of table rows
- No synchronization: Zero contention between concurrent operations
§Examples
§Basic Table Access and Type Analysis
use dotscope::metadata::{streams::TablesHeader, tables::{TableId, TypeDefRaw, MethodDefRaw}};
let tables = TablesHeader::from(tables_data)?;
// Safe table presence checking
if tables.has_table(TableId::TypeDef) {
let typedef_table = tables.table::<TypeDefRaw>(TableId::TypeDef).unwrap();
println!("Assembly defines {} types", typedef_table.row_count());
// Analyze type characteristics
for (index, type_def) in typedef_table.iter().enumerate().take(10) {
let is_public = type_def.flags & 0x00000007 == 0x00000001;
let is_sealed = type_def.flags & 0x00000100 != 0;
let is_abstract = type_def.flags & 0x00000080 != 0;
println!("Type {}: public={}, sealed={}, abstract={}",
index, is_public, is_sealed, is_abstract);
}
}§Cross-Table Relationship Analysis
use dotscope::metadata::{streams::TablesHeader, tables::{TableId, TypeDefRaw, FieldRaw, MethodDefRaw}};
let tables = TablesHeader::from(tables_data)?;
// Analyze complete type structure with members
if let (Some(typedef_table), Some(field_table), Some(method_table)) = (
tables.table::<TypeDefRaw>(TableId::TypeDef),
tables.table::<FieldRaw>(TableId::Field),
tables.table::<MethodDefRaw>(TableId::MethodDef)
) {
for (type_idx, type_def) in typedef_table.iter().enumerate().take(5) {
// Calculate member ranges for this type
let next_type = typedef_table.get((type_idx + 1) as u32);
let field_start = type_def.field_list.saturating_sub(1);
let field_end = next_type.as_ref()
.map(|t| t.field_list.saturating_sub(1))
.unwrap_or(field_table.row_count());
let method_start = type_def.method_list.saturating_sub(1);
let method_end = next_type.as_ref()
.map(|t| t.method_list.saturating_sub(1))
.unwrap_or(method_table.row_count());
println!("Type {}: {} fields, {} methods",
type_idx,
field_end.saturating_sub(field_start),
method_end.saturating_sub(method_start));
}
}§High-Performance Parallel Processing
use dotscope::metadata::{streams::TablesHeader, tables::{TableId, CustomAttributeRaw}};
use rayon::prelude::*;
use std::collections::HashMap;
let tables = TablesHeader::from(tables_data)?;
// Parallel analysis of custom attributes
if let Some(ca_table) = tables.table::<CustomAttributeRaw>(TableId::CustomAttribute) {
// Process attributes in parallel for large assemblies
let attribute_analysis: HashMap<u32, u32> = ca_table.par_iter()
.map(|attr| {
// Extract parent table type from coded index
// Note: Actual implementation would use proper CodedIndex methods
let parent_table = 1u32; // Simplified for documentation
(parent_table, 1u32)
})
.collect::<Vec<_>>()
.into_iter()
.fold(HashMap::new(), |mut acc, (table, count)| {
*acc.entry(table).or_insert(0) += count;
acc
});
println!("Custom attribute distribution:");
for (table_id, count) in attribute_analysis {
println!(" Table {}: {} attributes", table_id, count);
}
}§Memory-Efficient Large Table Processing
use dotscope::metadata::{streams::TablesHeader, tables::{TableId, MemberRefRaw}};
let tables = TablesHeader::from(tables_data)?;
// Process large tables without loading all data into memory
if let Some(memberref_table) = tables.table::<MemberRefRaw>(TableId::MemberRef) {
const CHUNK_SIZE: u32 = 1000;
let total_rows = memberref_table.row_count();
println!("Processing {} member references in {} chunks",
total_rows, (total_rows + CHUNK_SIZE - 1) / CHUNK_SIZE);
let mut external_method_refs = 0;
let mut external_field_refs = 0;
// Process in chunks to manage memory usage
for chunk_start in (0..total_rows).step_by(CHUNK_SIZE as usize) {
let chunk_end = (chunk_start + CHUNK_SIZE).min(total_rows);
for i in chunk_start..chunk_end {
if let Some(member_ref) = memberref_table.get(i) {
// Analyze member reference type and parent
// Note: Actual implementation would use proper CodedIndex methods
let is_method = true; // Simplified: check signature
let is_external = true; // Simplified: check class reference
if is_external {
if is_method {
external_method_refs += 1;
} else {
external_field_refs += 1;
}
}
}
}
}
println!("External references: {} methods, {} fields",
external_method_refs, external_field_refs);
}§Complete Assembly Introspection
use dotscope::metadata::{streams::TablesHeader, tables::TableId};
let tables = TablesHeader::from(tables_data)?;
println!("Assembly Metadata Analysis");
println!("=========================");
println!("Total tables: {}", tables.table_count());
println!();
// Analyze present tables and their characteristics
let summaries = tables.table_summary();
for summary in summaries {
match summary.table_id {
TableId::TypeDef => println!("✓ {} type definitions", summary.row_count),
TableId::MethodDef => println!("✓ {} method definitions", summary.row_count),
TableId::Field => println!("✓ {} field definitions", summary.row_count),
TableId::Assembly => println!("✓ Assembly metadata present"),
TableId::AssemblyRef => println!("✓ {} assembly references", summary.row_count),
TableId::CustomAttribute => println!("✓ {} custom attributes", summary.row_count),
TableId::GenericParam => println!("✓ {} generic parameters (generics used)", summary.row_count),
TableId::DeclSecurity => println!("✓ {} security declarations", summary.row_count),
TableId::ManifestResource => println!("✓ {} embedded resources", summary.row_count),
_ => println!("✓ {:?}: {} rows", summary.table_id, summary.row_count),
}
}
// Feature detection
println!();
println!("Assembly Features:");
if tables.has_table(TableId::GenericParam) {
println!(" ✓ Uses generic types/methods");
}
if tables.has_table(TableId::Event) {
println!(" ✓ Defines events");
}
if tables.has_table(TableId::Property) {
println!(" ✓ Defines properties");
}
if tables.has_table(TableId::DeclSecurity) {
println!(" ✓ Has security declarations");
}
if tables.has_table(TableId::ImplMap) {
println!(" ✓ Uses P/Invoke");
}§Security Considerations
§Input Validation
- ECMA-335 compliance: Strict adherence to specification format requirements
- Bounds checking: All table and row access validated against buffer boundaries
- Index validation: Cross-table references verified for correctness
- Size limits: Reasonable limits prevent resource exhaustion attacks
§Memory Safety
- Lifetime enforcement: Rust borrow checker prevents use-after-free vulnerabilities
- Type safety: Generic parameters prevent incorrect table type access
- Bounds verification: All array and slice access is bounds-checked
- Controlled unsafe: Minimal unsafe code with careful pointer management
§ECMA-335 Compliance
This implementation fully complies with ECMA-335 Partition II specifications:
- Section II.24.2.6: Metadata tables stream format and binary layout
- Section II.22: Complete metadata table definitions and relationships
- Compression format: Proper variable-width encoding for table indices
- Heap integration: Correct interpretation of string, blob, and GUID heap references
§See Also
crate::metadata::tables::MetadataTable: Individual table access and iterationcrate::metadata::tables::TableId: Enumeration of all supported table typescrate::metadata::streams: Overview of all metadata stream types- ECMA-335 II.24.2.6: Tables header specification
§Efficient Table Access Examples
§Basic Table Access
use dotscope::metadata::{streams::TablesHeader, tables::{TableId, TypeDefRaw, MethodDefRaw, FieldRaw}};
// Check if a table is present before accessing it
if tables_header.has_table(TableId::TypeDef) {
// Get efficient access to the TypeDef table
if let Some(typedef_table) = tables_header.table::<TypeDefRaw>(TableId::TypeDef) {
println!("TypeDef table has {} rows", typedef_table.row_count());
// Access individual rows by index (0-based)
if let Some(first_type) = typedef_table.get(0) {
println!("First type: flags={}, name_idx={}, namespace_idx={}",
first_type.flags, first_type.type_name, first_type.type_namespace);
}
}
}§Iterating Over Table Rows
use dotscope::metadata::{streams::TablesHeader, tables::{TableId, MethodDefRaw}};
// Iterate over all methods in the assembly
if let Some(method_table) = tables_header.table::<MethodDefRaw>(TableId::MethodDef) {
for (index, method) in method_table.iter().enumerate() {
println!("Method {}: RVA={:#x}, impl_flags={}, flags={}, name_idx={}",
index, method.rva, method.impl_flags, method.flags, method.name);
// Break after first 10 for demonstration
if index >= 9 { break; }
}
}§Parallel Processing with Rayon
use dotscope::metadata::{streams::TablesHeader, tables::{TableId, FieldRaw}};
use rayon::prelude::*;
// Process field metadata in parallel
if let Some(field_table) = tables_header.table::<FieldRaw>(TableId::Field) {
let field_count = field_table.par_iter()
.filter(|field| field.flags & 0x0010 != 0) // FieldAttributes.Static
.count();
println!("Found {} static fields", field_count);
}§Cross-Table Analysis
use dotscope::metadata::{streams::TablesHeader, tables::{TableId, TypeDefRaw, MethodDefRaw}};
// Analyze types and their methods together
if let (Some(typedef_table), Some(method_table)) = (
tables_header.table::<TypeDefRaw>(TableId::TypeDef),
tables_header.table::<MethodDefRaw>(TableId::MethodDef)
) {
for (type_idx, type_def) in typedef_table.iter().enumerate().take(5) {
println!("Type {}: methods {}-{}",
type_idx, type_def.method_list,
type_def.method_list.saturating_add(10)); // Simplified example
// In real usage, you'd calculate the actual method range
// by looking at the next type's method_list or using table bounds
}
}§Working with Table Summaries
use dotscope::metadata::streams::TablesHeader;
// Get overview of all present tables
let summaries = tables_header.table_summary();
for summary in summaries {
println!("Table {:?}: {} rows", summary.table_id, summary.row_count);
}
// Check for specific tables by ID
if tables_header.has_table_by_id(0x02) { // TypeDef table ID
println!("TypeDef table is present");
}
println!("Total metadata tables: {}", tables_header.table_count());§Memory-Efficient Pattern
use dotscope::metadata::{streams::TablesHeader, tables::{TableId, CustomAttributeRaw}};
// Process large tables without loading all data at once
if let Some(ca_table) = tables_header.table::<CustomAttributeRaw>(TableId::CustomAttribute) {
println!("Processing {} custom attributes", ca_table.row_count());
// Process in chunks to manage memory usage
const CHUNK_SIZE: u32 = 100;
let total_rows = ca_table.row_count();
for chunk_start in (0..total_rows).step_by(CHUNK_SIZE as usize) {
let chunk_end = (chunk_start + CHUNK_SIZE).min(total_rows);
for i in chunk_start..chunk_end {
if let Some(attr) = ca_table.get(i) {
// Process individual custom attribute
// attr.parent, attr.type_def, attr.value are available
// without copying the entire table into memory
}
}
// Optional: yield control or log progress
println!("Processed chunk {}-{}", chunk_start, chunk_end);
}
}§Performance Notes
- All table access uses reference-based parsing - no data is duplicated in memory
- Row access via
get()and iteration is lazy - rows are parsed only when requested - Parallel iteration with
par_iter()can significantly speed up processing of large tables - The lifetime parameter
'aensures memory safety by tying table references to the original data
§Reference
- ‘https://ecma-international.org/wp-content/uploads/ECMA-335_6th_edition_june_2012.pdf’ - II.24.2.6 && II.22
Fields§
§major_version: u8Major version of the metadata table schema, must be 2 per ECMA-335.
This field indicates the major version of the metadata table format. According to ECMA-335 Section II.24.2.6, this value must be 2 for all compliant .NET assemblies. Different major versions would indicate incompatible changes to the table format.
minor_version: u8Minor version of the metadata table schema, must be 0 per ECMA-335.
This field indicates the minor version of the metadata table format. The ECMA-335 specification requires this value to be 0. Minor version changes would indicate backward-compatible additions to the table format.
valid: u64Bit vector indicating which of the 64 possible metadata tables are present.
Each bit corresponds to a specific table ID (0-63) as defined in ECMA-335. A set bit (1) indicates the corresponding table is present and contains data. The number of set bits determines how many row count entries follow in the header.
§Table ID Mapping
- Bit 0: Module table
- Bit 1: TypeRef table
- Bit 2: TypeDef table
- Bit 4: Field table
- Bit 6: MethodDef table
- … (see ECMA-335 II.22 for complete mapping)
sorted: u64Bit vector indicating which metadata tables are sorted.
For each present table (indicated by valid), the corresponding bit in sorted
indicates whether that table’s rows are sorted according to ECMA-335 requirements.
Some tables must be sorted for binary search operations, while others may be
unsorted for faster insertion during metadata generation.
info: TableInfoRefShared table information containing row counts and heap index sizes.
This reference-counted structure provides efficient access to table metadata
including row counts for each present table and the size encoding for heap
indices (strings, blobs, GUIDs). The Arc allows multiple table instances
to share this information without duplication.
Implementations§
§impl<'a> TablesHeader<'a>
impl<'a> TablesHeader<'a>
pub fn from(data: &'a [u8]) -> Result<TablesHeader<'a>>
pub fn from(data: &'a [u8]) -> Result<TablesHeader<'a>>
Parse and construct a metadata tables header from binary data.
Creates a crate::metadata::streams::tablesheader::TablesHeader by parsing the compressed metadata tables stream (#~)
according to ECMA-335 Section II.24.2.6. This method performs comprehensive
validation of the stream format and constructs efficient access structures for
all present metadata tables.
§Binary Format Parsed
The method parses the following header structure:
Offset | Size | Field | Description
-------|------|--------------------|-----------------------------------------
0 | 4 | Reserved | Must be 0x00000000
4 | 1 | MajorVersion | Schema major version (must be 2)
5 | 1 | MinorVersion | Schema minor version (must be 0)
6 | 1 | HeapSizes | String/Blob/GUID heap index sizes
7 | 1 | Reserved | Must be 0x01
8 | 8 | Valid | Bit vector of present tables
16 | 8 | Sorted | Bit vector of sorted tables
24 | 4*N | Rows[] | Row counts for each present table
24+4*N | Var | TableData[] | Binary table data§Validation Performed
The method enforces ECMA-335 compliance through comprehensive validation:
- Minimum size: Data must contain complete header (≥24 bytes)
- Version checking: Major version must be 2, minor version must be 0
- Table presence: At least one table must be present (valid ≠ 0)
- Format integrity: Row count array and table data must be accessible
- Table structure: Each present table validated for proper format
§Construction Process
- Header parsing: Extract version, heap sizes, and table bit vectors
- Row count extraction: Read row counts for all present tables
- Table initialization: Parse each present table’s binary data
- Reference setup: Establish efficient access structures
- Validation: Verify all tables conform to ECMA-335 format
§Arguments
data- Complete binary data of the compressed metadata tables stream
§Returns
Ok(TablesHeader)- Successfully parsed and validated tables headerErr(Error)- Parsing failed due to format violations or insufficient data
§Errors
Returns crate::Error in the following cases:
crate::Error::OutOfBounds: Data too short for complete header (< 24 bytes)- Malformed data: No valid tables present (all bits in
validare 0) - Version error: Unsupported major/minor version combination
- Format error: Invalid table data or corrupted stream structure
- Table error: Individual table parsing failures due to malformed data
§Examples
§Basic Tables Header Construction
use dotscope::metadata::streams::TablesHeader;
// Read compressed metadata tables stream from assembly
let tables_stream_data = &[/* binary data from #~ stream */];
let tables = TablesHeader::from(tables_stream_data)?;
// Verify successful construction
println!("Parsed metadata with {} tables", tables.table_count());
println!("Schema version: {}.{}", tables.major_version, tables.minor_version);
// Check for common tables
use dotscope::metadata::tables::TableId;
if tables.has_table(TableId::TypeDef) {
println!("Assembly defines {} types", tables.table_row_count(TableId::TypeDef));
}
if tables.has_table(TableId::MethodDef) {
println!("Assembly defines {} methods", tables.table_row_count(TableId::MethodDef));
}§Error Handling and Validation
use dotscope::metadata::streams::TablesHeader;
// Error: Data too short
let too_short = [0u8; 20]; // Only 20 bytes, need at least 24
assert!(TablesHeader::from(&too_short).is_err());
// Error: No valid tables
let no_tables = [
0x00, 0x00, 0x00, 0x00, // Reserved
0x02, 0x00, // Version 2.0
0x01, 0x01, // HeapSizes, Reserved
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Valid = 0 (no tables)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Sorted
];
assert!(TablesHeader::from(&no_tables).is_err());§Large Assembly Processing
use dotscope::metadata::streams::TablesHeader;
// Process large assembly with many tables
let large_assembly_data = &[/* large assembly #~ stream data */];
let start_time = std::time::Instant::now();
let tables = TablesHeader::from(large_assembly_data)?;
let parse_time = start_time.elapsed();
println!("Parsed {} tables in {:?}", tables.table_count(), parse_time);
// Analyze assembly size and complexity
let summaries = tables.table_summary();
let total_rows: u32 = summaries.iter().map(|s| s.row_count).sum();
println!("Assembly complexity:");
println!(" Total metadata rows: {}", total_rows);
println!(" Average rows per table: {:.1}",
total_rows as f64 / tables.table_count() as f64);
// Identify the most complex tables
let mut large_tables: Vec<_> = summaries.iter()
.filter(|s| s.row_count > 1000)
.collect();
large_tables.sort_by_key(|s| std::cmp::Reverse(s.row_count));
println!("Largest tables:");
for summary in large_tables.iter().take(3) {
println!(" {:?}: {} rows", summary.table_id, summary.row_count);
}§Assembly Feature Detection
use dotscope::metadata::{streams::TablesHeader, tables::TableId};
let assembly_data = &[/* assembly #~ stream data */];
let tables = TablesHeader::from(assembly_data)?;
println!("Assembly Feature Analysis:");
println!("=========================");
// Detect .NET framework features
if tables.has_table(TableId::GenericParam) {
let generic_count = tables.table_row_count(TableId::GenericParam);
println!("✓ Uses generics ({} parameters)", generic_count);
}
if tables.has_table(TableId::Event) {
let event_count = tables.table_row_count(TableId::Event);
println!("✓ Defines events ({} events)", event_count);
}
if tables.has_table(TableId::Property) {
let prop_count = tables.table_row_count(TableId::Property);
println!("✓ Defines properties ({} properties)", prop_count);
}
if tables.has_table(TableId::DeclSecurity) {
let security_count = tables.table_row_count(TableId::DeclSecurity);
println!("✓ Has security declarations ({} declarations)", security_count);
}
if tables.has_table(TableId::ImplMap) {
let pinvoke_count = tables.table_row_count(TableId::ImplMap);
println!("✓ Uses P/Invoke ({} mappings)", pinvoke_count);
}
if tables.has_table(TableId::ManifestResource) {
let resource_count = tables.table_row_count(TableId::ManifestResource);
println!("✓ Embeds resources ({} resources)", resource_count);
}§Thread Safety
Construction is thread-safe when called with different data sources.
The resulting crate::metadata::streams::tablesheader::TablesHeader instance is immutable and safe for concurrent
access across multiple threads.
§ECMA-335 Compliance
This method implements full ECMA-335 Partition II compliance:
- Section II.24.2.6: Metadata tables stream header format
- Section II.22: Individual table format specifications
- Compression format: Variable-width index encoding based on heap sizes
- Table relationships: Proper handling of cross-table references
§See Also
TablesHeader::table: Access individual metadata tables after constructionTablesHeader::table_summary: Get overview of all present tablescrate::metadata::tables::TableInfo: Table metadata and row count information- ECMA-335 II.24.2.6: Tables header specification
pub fn table_count(&self) -> u32
pub fn table_count(&self) -> u32
Get the table count
pub fn table<T: RowDefinition<'a>>(
&self,
table_id: TableId,
) -> Option<&'a MetadataTable<'a, T>>
pub fn table<T: RowDefinition<'a>>( &self, table_id: TableId, ) -> Option<&'a MetadataTable<'a, T>>
Get a specific table for efficient access
This method provides type-safe access to metadata tables without copying data. The returned table reference allows efficient iteration and random access to rows.
§Arguments
table_id- The type of table to lookup
§Returns
Some(&MetadataTable<T>)- Reference to the table if presentNone- If the table is not present in this assembly
§Example
use dotscope::metadata::{streams::TablesHeader, tables::{TableId, TypeDefRaw}};
// Safe access with type checking
if let Some(typedef_table) = tables.table::<TypeDefRaw>(TableId::TypeDef) {
// Efficient access to all type definitions
for type_def in typedef_table.iter().take(5) {
println!("Type: flags={:#x}, name_idx={}, namespace_idx={}",
type_def.flags, type_def.type_name, type_def.type_namespace);
}
// Random access to specific rows
if let Some(first_type) = typedef_table.get(0) {
println!("First type name index: {}", first_type.type_name);
}
}§Safety Note
The generic type parameter T must match the table type for table_id.
Using the wrong type will result in undefined behavior due to the internal cast.
Always use the corresponding *Raw types:
TableId::TypeDef→TypeDefRawTableId::MethodDef→MethodDefRawTableId::Field→FieldRaw- etc.
pub fn has_table(&self, table_id: TableId) -> bool
pub fn has_table(&self, table_id: TableId) -> bool
Check if a specific table is present
Use this method to safely check for table presence before accessing it. This avoids potential panics when working with assemblies that may not contain all possible metadata tables.
§Arguments
table_id- The table ID to check for presence
§Example
use dotscope::metadata::{streams::TablesHeader, tables::{TableId, EventRaw}};
// Safe pattern: check before access
if tables.has_table(TableId::Event) {
if let Some(event_table) = tables.table::<EventRaw>(TableId::Event) {
println!("Assembly has {} events", event_table.row_count());
}
} else {
println!("No events defined in this assembly");
}pub fn has_table_by_id(&self, table_id: u8) -> bool
pub fn has_table_by_id(&self, table_id: u8) -> bool
Check if a table is present by its numeric ID
This method provides a way to check for table presence using the raw numeric table identifiers (0-63) as defined in the ECMA-335 specification.
§Arguments
table_id- The numeric table ID (0-63) to check for presence
§Returns
true- If the table is presentfalse- If the table is not present ortable_id> 63
§Example
use dotscope::metadata::streams::TablesHeader;
// Check for specific tables by their numeric IDs
if tables.has_table_by_id(0x02) { // TypeDef
println!("TypeDef table present");
}
if tables.has_table_by_id(0x06) { // MethodDef
println!("MethodDef table present");
}
if tables.has_table_by_id(0x04) { // Field
println!("Field table present");
}pub fn present_tables(&self) -> impl Iterator<Item = TableId> + '_
pub fn present_tables(&self) -> impl Iterator<Item = TableId> + '_
Get an iterator over all present tables
This method returns an iterator that yields TableId values for all tables
that are present in this assembly’s metadata. Useful for discovering what
metadata is available without having to check each table individually.
§Example
use dotscope::metadata::streams::TablesHeader;
println!("Present metadata tables:");
for table_id in tables.present_tables() {
let row_count = tables.table_row_count(table_id);
println!(" {:?}: {} rows", table_id, row_count);
}pub fn table_row_count(&self, table_id: TableId) -> u32
pub fn table_row_count(&self, table_id: TableId) -> u32
Get the row count for a specific table
Returns the number of rows in the specified table. This information is available even if you don’t access the table data itself.
§Arguments
table_id- The table to get the row count for
§Returns
- Row count (0 if table is not present)
§Example
use dotscope::metadata::{streams::TablesHeader, tables::TableId};
let type_count = tables.table_row_count(TableId::TypeDef);
let method_count = tables.table_row_count(TableId::MethodDef);
let field_count = tables.table_row_count(TableId::Field);
println!("Assembly contains:");
println!(" {} types", type_count);
println!(" {} methods", method_count);
println!(" {} fields", field_count);pub fn table_summary(&self) -> Vec<TableSummary>
pub fn table_summary(&self) -> Vec<TableSummary>
Get a summary of all present tables with their row counts
Auto Trait Implementations§
impl<'a> Freeze for TablesHeader<'a>
impl<'a> RefUnwindSafe for TablesHeader<'a>
impl<'a> Send for TablesHeader<'a>
impl<'a> Sync for TablesHeader<'a>
impl<'a> Unpin for TablesHeader<'a>
impl<'a> UnwindSafe for TablesHeader<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more