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

The TablesHeader structure represents the header in the ‘#’ stream. ‘#’ which contains all the metadata used for reflection and execution of the CIL binary.

This structure provides efficient access to metadata tables, allowing reference-based parsing and traversal of .NET assemblies without loading the entire metadata into memory at once.

§Efficient Table Access Examples

§Basic Table Access

use dotscope::metadata::streams::{TablesHeader, 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, 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, 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, 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, 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 'a ensures memory safety by tying table references to the original data

§Reference

Fields§

§major_version: u8

Major version of table schemeta, shall be 2

§minor_version: u8

Minor version of table schemata, shall be 0

§valid: u64

Bit vector of present tables, let n be the number of bits that are 1.

§sorted: u64

Bit vector of sorted tables

§info: TableInfoRef

Information about specific tables, e.g their row count, and their reference index sizes

Implementations§

§

impl<'a> TablesHeader<'a>

pub fn from(data: &'a [u8]) -> Result<TablesHeader<'a>>

Create a TablesHeader object from a sequence of bytes

§Arguments
  • ‘data’ - The byte slice from which this object shall be created
§Errors

Returns an error if the data is too short or if no valid table rows are found

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>>

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 present
  • None - If the table is not present in this assembly
§Example
use dotscope::metadata::streams::{TablesHeader, 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::TypeDefTypeDefRaw
  • TableId::MethodDefMethodDefRaw
  • TableId::FieldFieldRaw
  • etc.

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, 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

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 present
  • false - If the table is not present or table_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> + '_

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

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, 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>

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> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.