Struct Guid

pub struct Guid<'a> { /* private fields */ }
Expand description

ECMA-335 GUID heap providing indexed access to 128-bit globally unique identifiers.

The Guid struct represents the #GUID metadata heap according to ECMA-335 Section II.24.2.5. It provides safe, zero-copy access to 16-byte GUID values referenced by metadata table entries for assembly identification, type library correlation, and module tracking.

§GUID Heap Organization

§Storage Format

GUIDs are stored as consecutive 16-byte little-endian values:

  • Each GUID occupies exactly 16 bytes
  • No padding or alignment between entries
  • Standard RFC 4122 UUID format within each 16-byte block
  • Sequential storage enables efficient bulk operations

§Indexing Convention

The GUID heap uses 1-based indexing unlike other metadata heaps:

Index | Byte Offset | GUID Content
------|-------------|-------------
1     | 0-15        | First GUID
2     | 16-31       | Second GUID
3     | 32-47       | Third GUID

This convention aligns with ECMA-335 requirements and metadata table references.

§GUID Types and Usage

§Assembly Identity GUIDs

Uniquely identify assemblies across application domains:

  • Enable version-independent assembly correlation
  • Support strong naming and security policies
  • Facilitate debugging and profiling scenarios

§Type Library GUIDs

Support COM interoperability:

  • Map .NET types to COM interfaces
  • Enable marshalling between managed/unmanaged code
  • Provide backward compatibility with legacy systems

§Module GUIDs

Distinguish modules within multi-module assemblies:

  • Support incremental compilation workflows
  • Enable fine-grained dependency tracking
  • Facilitate debugging symbol correlation

§Examples

§Creating and Accessing GUIDs

use dotscope::metadata::streams::Guid;

// Sample GUID heap with two entries
#[rustfmt::skip]
let heap_data = [
    // GUID 1: d437908e-65e6-487c-9735-7bdff699bea5
    0x8e, 0x90, 0x37, 0xd4, 0xe6, 0x65, 0x7c, 0x48,
    0x97, 0x35, 0x7b, 0xdf, 0xf6, 0x99, 0xbe, 0xa5,
    // GUID 2: All zeros (null GUID)
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];

let guid_heap = Guid::from(&heap_data)?;

// Access GUIDs using 1-based indexing (as per ECMA-335)
let assembly_guid = guid_heap.get(1)?;
let module_guid = guid_heap.get(2)?;

let null_guid = uguid::guid!("00000000-0000-0000-0000-000000000000");
assert_ne!(assembly_guid, null_guid);
assert_eq!(module_guid, null_guid);

§Assembly Identity Verification

use dotscope::metadata::streams::Guid;

let heap_data = [0xAB; 16]; // Non-null GUID
let guid_heap = Guid::from(&heap_data)?;
let assembly_guid = guid_heap.get(1)?;

let null_guid = uguid::guid!("00000000-0000-0000-0000-000000000000");
// Check if assembly has unique identity
if assembly_guid != null_guid {
    println!("Assembly ID: {}", assembly_guid);
    // Use for caching, comparison, or security checks
}

§Iterating Over All GUIDs

use dotscope::metadata::streams::Guid;

let heap_data = [0xFF; 32]; // Two GUIDs with pattern data
let guid_heap = Guid::from(&heap_data)?;

for result in &guid_heap {
    let (index, guid) = result?;
    println!("GUID {}: {}", index, guid);
}

§Error Handling

Comprehensive error handling for various failure scenarios:

  • Insufficient data: Heap smaller than minimum GUID size (16 bytes)
  • Out of bounds: Invalid index or incomplete GUID data
  • Invalid indexing: Index 0 or negative indices rejected
  • Alignment issues: Proper 16-byte boundary validation

§ECMA-335 Compliance

This implementation fully supports ECMA-335 requirements:

  • Correct 1-based indexing convention
  • Proper 16-byte GUID storage alignment
  • Little-endian byte order handling
  • Standard RFC 4122 UUID format support

§See Also

Implementations§

§

impl<'a> Guid<'a>

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

Creates a new Guid heap accessor from raw metadata bytes.

Validates that the provided data contains sufficient bytes to represent at least one complete 16-byte GUID. The GUID heap stores sequential 128-bit globally unique identifiers referenced by metadata table entries.

§Parameters
  • data - Raw bytes containing the complete #GUID heap data
§Returns

A Guid instance providing safe access to the heap contents, or an error if the data format is invalid.

§Errors

Returns crate::Error in the following cases:

  • Insufficient data: Less than 16 bytes provided (minimum for one GUID)
  • Invalid alignment: Data length not divisible by 16 (partial GUID)
  • Empty heap: No GUID data available for processing
§Examples
§Valid GUID Heap
use dotscope::metadata::streams::Guid;

// Single GUID heap (minimum valid size)
let single_guid = [0xAB; 16];
let guid_heap = Guid::from(&single_guid)?;
assert_eq!(guid_heap.get(1)?.to_bytes(), single_guid);

// Multiple GUID heap
let multiple_guids = [0xFF; 48]; // Three GUIDs
let guid_heap = Guid::from(&multiple_guids)?;
assert!(guid_heap.get(1).is_ok());
assert!(guid_heap.get(3).is_ok());
§Invalid GUID Heap
use dotscope::metadata::streams::Guid;

// Too small for even one GUID
let too_small = [0u8; 10];
assert!(Guid::from(&too_small).is_err());

// Empty data
let empty_data = &[];
assert!(Guid::from(empty_data).is_err());
§Assembly Identity Use Case
use dotscope::metadata::streams::Guid;

// Real assembly GUID from PE metadata
#[rustfmt::skip]
let assembly_heap = [
    0x8e, 0x90, 0x37, 0xd4, 0xe6, 0x65, 0x7c, 0x48,
    0x97, 0x35, 0x7b, 0xdf, 0xf6, 0x99, 0xbe, 0xa5,
];

let guid_heap = Guid::from(&assembly_heap)?;
let assembly_id = guid_heap.get(1)?;

// Use for assembly identification or caching
println!("Assembly GUID: {}", assembly_id);
§Performance
  • Zero-copy: No data is copied or allocated during construction
  • O(1) validation: Only checks minimum size requirement
  • Lazy parsing: GUID entries parsed only when accessed
  • Memory efficient: Direct reference to source data
§GUID Heap Validation

This method performs minimal validation for performance:

  • Ensures minimum 16-byte size for at least one GUID
  • Does not validate GUID content or format
  • Individual GUID access via get provides bounds checking
§See Also
  • get: Access individual GUIDs by 1-based index
  • iter: Iterate over all GUIDs in the heap
  • ECMA-335 II.24.2.5: GUID heap specification

pub fn get(&self, index: usize) -> Result<Guid>

Retrieves a GUID from the heap by its 1-based index.

Returns a constructed GUID from the 16-byte data stored at the specified index. The index typically comes from metadata table entries that reference specific GUIDs for assembly identity, type library correlation, or module identification.

§Parameters
  • index - 1-based GUID index within the heap (from metadata table references)
§Returns

A uguid::Guid constructed from the 16-byte data at the specified index, or an error if the index is invalid or the data is insufficient.

§Errors

Returns crate::Error in the following cases:

  • Invalid index: Index 0 (GUIDs use 1-based indexing per ECMA-335)
  • Out of bounds: Index exceeds available GUID count
  • Incomplete data: Insufficient bytes for complete 16-byte GUID
  • Integer overflow: Index calculations exceed platform limits
§Examples
§Basic GUID Access
use dotscope::metadata::streams::Guid;

#[rustfmt::skip]
let heap_data = [
    // GUID 1: d437908e-65e6-487c-9735-7bdff699bea5
    0x8e, 0x90, 0x37, 0xd4, 0xe6, 0x65, 0x7c, 0x48,
    0x97, 0x35, 0x7b, 0xdf, 0xf6, 0x99, 0xbe, 0xa5,
    // GUID 2: All zeros (null GUID)
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];

let guid_heap = Guid::from(&heap_data)?;

// Access first GUID (1-based indexing)
let first_guid = guid_heap.get(1)?;
let null_guid = uguid::guid!("00000000-0000-0000-0000-000000000000");
assert_ne!(first_guid, null_guid);

// Access second GUID
let second_guid = guid_heap.get(2)?;
assert_eq!(second_guid, null_guid);
§Assembly Identity Example
use dotscope::metadata::streams::Guid;

// Assembly table references GUID index 1
let assembly_guid_index = 1;
let heap_data = [0xAB; 16]; // Sample assembly GUID

let guid_heap = Guid::from(&heap_data)?;
let assembly_guid = guid_heap.get(assembly_guid_index)?;

let null_guid = uguid::guid!("00000000-0000-0000-0000-000000000000");
// Use for assembly comparison or caching
if assembly_guid != null_guid {
    println!("Assembly identifier: {}", assembly_guid);
}
§Error Handling
use dotscope::metadata::streams::Guid;

let heap_data = [0xFF; 16]; // Single GUID heap
let guid_heap = Guid::from(&heap_data)?;

// Valid access
assert!(guid_heap.get(1).is_ok());

// Invalid index 0 (1-based indexing required)
assert!(guid_heap.get(0).is_err());

// Out of bounds access
assert!(guid_heap.get(2).is_err());
§Performance
  • O(1) access: Direct offset calculation and validation
  • Zero-copy construction: GUID built from direct data reference
  • Bounds checking: Full validation with minimal overhead
  • Cache friendly: Sequential data access pattern
§Index Calculation

The byte offset for a GUID is calculated as (index - 1) * 16:

IndexByte RangeDescription
10-15First GUID
216-31Second GUID
N(N-1)16 to N16-1Nth GUID
§GUID Format

Each 16-byte GUID follows RFC 4122 UUID format stored in little-endian byte order as specified by ECMA-335.

§See Also

pub fn iter(&self) -> GuidIterator<'_>

Returns an iterator over all GUIDs in the heap.

Provides sequential access to every GUID stored in the heap, yielding both the 1-based index and constructed GUID for each entry. This is useful for comprehensive analysis, validation, or enumeration of all assembly and module identifiers.

§Returns

Returns a crate::metadata::streams::guid::GuidIterator that yields Result<(usize, uguid::Guid)> tuples containing:

  • Index: 1-based position of the GUID within the heap
  • GUID: Constructed 128-bit globally unique identifier
§Iteration Behavior
  • Sequential access: GUIDs returned in storage order (index 1, 2, 3, …)
  • 1-based indexing: Consistent with ECMA-335 specification and get() method
  • Complete iteration: Processes all valid GUIDs until heap end
  • Error handling: Returns errors for malformed or incomplete GUID data
§Examples
§Basic Iteration
use dotscope::metadata::streams::Guid;

#[rustfmt::skip]
let heap_data = [
    // GUID 1: Sample assembly identifier
    0x8e, 0x90, 0x37, 0xd4, 0xe6, 0x65, 0x7c, 0x48,
    0x97, 0x35, 0x7b, 0xdf, 0xf6, 0x99, 0xbe, 0xa5,
    // GUID 2: Null GUID
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];

let guid_heap = Guid::from(&heap_data)?;
let null_guid = uguid::guid!("00000000-0000-0000-0000-000000000000");

for result in guid_heap.iter() {
    let (index, guid) = result?;
    println!("GUID {}: {}", index, guid);
     
    if guid != null_guid {
        println!("  Non-null identifier found");
    }
}
§Assembly and Module Enumeration
use dotscope::metadata::streams::Guid;

let heap_data = [0xAB; 48]; // Three identical GUIDs for demonstration
let guid_heap = Guid::from(&heap_data)?;

let mut assembly_guids = Vec::new();
let mut module_guids = Vec::new();

for result in guid_heap.iter() {
    let (index, guid) = result?;
     
    if index == 1 {
        assembly_guids.push(guid);
    } else {
        module_guids.push(guid);
    }
}

println!("Found {} assembly GUIDs, {} module GUIDs",
         assembly_guids.len(), module_guids.len());
§Error Handling During Iteration
use dotscope::metadata::streams::Guid;

let heap_data = [0xFF; 32]; // Two complete GUIDs
let guid_heap = Guid::from(&heap_data)?;

for result in guid_heap.iter() {
    match result {
        Ok((index, guid)) => {
            println!("Valid GUID at index {}: {}", index, guid);
        }
        Err(e) => {
            eprintln!("GUID parsing error: {}", e);
            break; // Stop on first error
        }
    }
}
§Collecting Non-Null GUIDs
use dotscope::metadata::streams::Guid;

let heap_data = [0x00; 32]; // Two null GUIDs
let guid_heap = Guid::from(&heap_data)?;
let null_guid = uguid::guid!("00000000-0000-0000-0000-000000000000");

let mut non_null_guids = Vec::new();
for result in guid_heap.iter() {
    let (index, guid) = result?;
    if guid != null_guid {
        non_null_guids.push((index, guid));
    }
}

println!("Found {} non-null GUIDs", non_null_guids.len());
§Error Recovery

If a malformed GUID is encountered (e.g., due to heap truncation), the iterator returns an error and terminates. This design ensures data integrity while allowing partial processing of valid entries.

§Use Cases
  • Assembly enumeration: Identify all assemblies in a multi-module application
  • GUID validation: Verify heap integrity and detect corruption
  • Debugging support: Display all identifiers for diagnostic purposes
  • Metadata analysis: Extract identity information for processing
§See Also

Trait Implementations§

§

impl<'a> IntoIterator for &'a Guid<'a>

§

type Item = Result<(usize, Guid), Error>

The type of the elements being iterated over.
§

type IntoIter = GuidIterator<'a>

Which kind of iterator are we turning this into?
§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more

Auto Trait Implementations§

§

impl<'a> Freeze for Guid<'a>

§

impl<'a> RefUnwindSafe for Guid<'a>

§

impl<'a> Send for Guid<'a>

§

impl<'a> Sync for Guid<'a>

§

impl<'a> Unpin for Guid<'a>

§

impl<'a> UnwindSafe for Guid<'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.