Skip to main content

FieldMarshalBuilder

Struct FieldMarshalBuilder 

pub struct FieldMarshalBuilder { /* private fields */ }
Expand description

Builder for creating FieldMarshal metadata entries.

FieldMarshalBuilder provides a fluent API for creating FieldMarshal table entries with validation and automatic blob management. Field marshaling defines the conversion rules between managed and native types for fields and parameters during interop scenarios including P/Invoke calls, COM interop, and platform invoke operations.

§Marshaling Model

.NET marshaling follows a structured pattern:

  • Parent Entity: The field or parameter that requires marshaling
  • Native Type: How the managed type appears in native code
  • Conversion Rules: Automatic conversion behavior during calls
  • Memory Management: Responsibility for allocation and cleanup

§Coded Index Types

Field marshaling uses the HasFieldMarshal coded index to specify targets:

  • Field: Marshaling for struct fields and class fields
  • Param: Marshaling for method parameters and return values

§Marshaling Scenarios and Types

Different native types serve various interop scenarios:

  • Primitive Types: Direct mapping for integers, floats, and booleans
  • String Types: Character encoding and memory management (ANSI, Unicode)
  • Array Types: Element type specification and size management
  • Pointer Types: Memory layout and dereferencing behavior
  • Interface Types: COM interface marshaling and reference counting
  • Custom Types: User-defined marshaling with custom marshalers

§Marshaling Descriptors

Marshaling information is stored as binary descriptors in the blob heap:

  • Simple Types: Single byte indicating native type (e.g., NATIVE_TYPE_I4)
  • Complex Types: Multi-byte descriptors with parameters (arrays, strings)
  • Custom Marshalers: Full type name and initialization parameters
  • Array Descriptors: Element type, dimensions, and size specifications

§Examples

let mut assembly = CilAssembly::new(view);

// Marshal a parameter as a null-terminated Unicode string
let param_ref = CodedIndex::new(TableId::Param, 1, CodedIndexType::HasFieldMarshal); // String parameter
let unicode_string_descriptor = vec![NATIVE_TYPE::LPWSTR]; // Simple descriptor

let string_marshal = FieldMarshalBuilder::new()
    .parent(param_ref)
    .native_type(&unicode_string_descriptor)
    .build(&mut assembly)?;

// Marshal a field as a fixed-size ANSI character array
let field_ref = CodedIndex::new(TableId::Field, 1, CodedIndexType::HasFieldMarshal); // Character array field
let fixed_array_descriptor = vec![
    NATIVE_TYPE::ARRAY,
    0x04, // Array element type (I1 - signed byte)
    0x20, 0x00, 0x00, 0x00, // Array size (32 elements, little-endian)
];

let array_marshal = FieldMarshalBuilder::new()
    .parent(field_ref)
    .native_type(&fixed_array_descriptor)
    .build(&mut assembly)?;

// Marshal a parameter as a COM interface pointer
let interface_param = CodedIndex::new(TableId::Param, 2, CodedIndexType::HasFieldMarshal); // Interface parameter
let interface_descriptor = vec![NATIVE_TYPE::INTERFACE]; // COM interface

let interface_marshal = FieldMarshalBuilder::new()
    .parent(interface_param)
    .native_type(&interface_descriptor)
    .build(&mut assembly)?;

// Marshal a return value as a platform-dependent integer
let return_param = CodedIndex::new(TableId::Param, 0, CodedIndexType::HasFieldMarshal); // Return value (sequence 0)
let platform_int_descriptor = vec![NATIVE_TYPE::INT]; // Platform IntPtr

let return_marshal = FieldMarshalBuilder::new()
    .parent(return_param)
    .native_type(&platform_int_descriptor)
    .build(&mut assembly)?;

Implementations§

§

impl FieldMarshalBuilder

pub fn new() -> Self

Creates a new FieldMarshalBuilder.

§Returns

A new crate::metadata::tables::fieldmarshal::FieldMarshalBuilder instance ready for configuration.

pub fn parent(self, parent: CodedIndex) -> Self

Sets the parent field or parameter that requires marshaling.

The parent must be a valid HasFieldMarshal coded index that references either a field definition or parameter definition. This establishes which entity will have marshaling behavior applied during interop operations.

Valid parent types include:

  • Field - Marshaling for struct fields in P/Invoke scenarios
  • Param - Marshaling for method parameters and return values

Marshaling scope considerations:

  • Field marshaling: Applied when the containing struct crosses managed/native boundary
  • Parameter marshaling: Applied during each method call that crosses boundaries
  • Return marshaling: Applied to return values from native methods
  • Array marshaling: Applied to array elements and overall array structure
§Arguments
  • parent - A HasFieldMarshal coded index pointing to the target field or parameter
§Returns

Self for method chaining.

pub fn native_type(self, native_type: &[u8]) -> Self

Sets the native type marshaling descriptor.

The native type descriptor defines how the managed type should be represented and converted in native code. This binary descriptor is stored in the blob heap and follows .NET’s marshaling specification format.

Descriptor format varies by complexity:

  • Simple types: Single byte (e.g., [NATIVE_TYPE::I4] for 32-bit integer)
  • String types: May include encoding and length parameters
  • Array types: Include element type, dimensions, and size information
  • Custom types: Include full type names and initialization parameters

Common descriptor patterns:

  • Primitive: [NATIVE_TYPE::I4] - 32-bit signed integer
  • Unicode String: [NATIVE_TYPE_LPWSTR] - Null-terminated wide string
  • ANSI String: [NATIVE_TYPE_LPSTR] - Null-terminated ANSI string
  • Fixed Array: [NATIVE_TYPE_BYVALARRAY, element_type, size...] - In-place array
  • Interface: [NATIVE_TYPE_INTERFACE] - COM interface pointer
§Arguments
  • native_type - The binary marshaling descriptor specifying conversion behavior
§Returns

Self for method chaining.

pub fn simple_native_type(self, type_id: u8) -> Self

Sets a simple native type marshaling descriptor.

This is a convenience method for common marshaling scenarios that require only a single native type identifier without additional parameters.

§Arguments
  • type_id - The native type identifier from the NativeType constants
§Returns

Self for method chaining.

pub fn unicode_string(self) -> Self

Sets Unicode string marshaling (LPWSTR).

This convenience method configures marshaling for Unicode string parameters and fields, using null-terminated wide character representation.

§Returns

Self for method chaining.

pub fn ansi_string(self) -> Self

Sets ANSI string marshaling (LPSTR).

This convenience method configures marshaling for ANSI string parameters and fields, using null-terminated single-byte character representation.

§Returns

Self for method chaining.

pub fn fixed_array(self, element_type: u8, size: u32) -> Self

Sets fixed-size array marshaling.

This convenience method configures marshaling for fixed-size arrays with specified element type and count. The array is marshaled in-place within the containing structure.

§Arguments
  • element_type - The native type of array elements
  • size - The number of elements in the array
§Returns

Self for method chaining.

pub fn com_interface(self) -> Self

Sets COM interface marshaling.

This convenience method configures marshaling for COM interface pointers, enabling proper reference counting and interface negotiation.

§Returns

Self for method chaining.

pub fn native_type_spec(self, native_type: NativeType) -> Self

Sets marshaling using a high-level NativeType specification.

This method provides a type-safe way to configure marshaling using the structured NativeType enum rather than raw binary descriptors. It automatically encodes the native type specification to the correct binary format.

§Arguments
  • native_type - The native type specification to marshal to
§Returns

Self for method chaining.

§Note

If encoding fails, the error is stored and will be returned when build() is called.

§Examples
use dotscope::metadata::marshalling::NativeType;
use dotscope::metadata::tables::FieldMarshalBuilder;

// Unicode string with size parameter
let marshal = FieldMarshalBuilder::new()
    .parent(param_ref)
    .native_type_spec(NativeType::LPWStr { size_param_index: Some(2) })
    .build(&mut assembly)?;

// Array of 32-bit integers
let array_marshal = FieldMarshalBuilder::new()
    .parent(field_ref)
    .native_type_spec(NativeType::Array {
        element_type: Box::new(NativeType::I4),
        num_param: Some(1),
        num_element: Some(10),
    })
    .build(&mut assembly)?;

pub fn marshalling_info(self, info: &MarshallingInfo) -> Self

Sets marshaling using a complete marshalling descriptor.

This method allows specifying complex marshalling scenarios with primary and additional types. This is useful for advanced marshalling cases that require multiple type specifications.

§Arguments
  • info - The complete marshalling descriptor with primary and additional types
§Returns

Self for method chaining.

§Note

If encoding fails, the error is stored and will be returned when build() is called.

§Examples
use dotscope::metadata::marshalling::{NativeType, MarshallingInfo};
use dotscope::metadata::tables::FieldMarshalBuilder;

let complex_info = MarshallingInfo {
    primary_type: NativeType::CustomMarshaler {
        guid: "12345678-1234-5678-9ABC-DEF012345678".to_string(),
        native_type_name: "NativeArray".to_string(),
        cookie: "size=dynamic".to_string(),
        type_reference: "MyAssembly.ArrayMarshaler".to_string(),
    },
    additional_types: vec![NativeType::I4], // Element type hint
};

let marshal = FieldMarshalBuilder::new()
    .parent(param_ref)
    .marshalling_info(complex_info)
    .build(&mut assembly)?;

pub fn pointer(self, ref_type: Option<NativeType>) -> Self

Sets marshaling for a pointer to a specific native type.

This convenience method configures marshaling for pointer types with optional target type specification.

§Arguments
  • ref_type - Optional type that the pointer references
§Returns

Self for method chaining.

pub fn variable_array( self, element_type: NativeType, size_param: Option<u32>, element_count: Option<u32>, ) -> Self

Sets marshaling for a variable-length array.

This convenience method configures marshaling for arrays with runtime size determination through parameter references.

§Arguments
  • element_type - The type of array elements
  • size_param - Optional parameter index for array size
  • element_count - Optional fixed element count
§Returns

Self for method chaining.

pub fn fixed_array_typed( self, element_type: Option<NativeType>, size: u32, ) -> Self

Sets marshaling for a fixed-size array.

This convenience method configures marshaling for arrays with compile-time known size embedded directly in structures.

§Arguments
  • element_type - Optional type of array elements
  • size - Number of elements in the array
§Returns

Self for method chaining.

pub fn native_struct( self, packing_size: Option<u8>, class_size: Option<u32>, ) -> Self

Sets marshaling for a native structure.

This convenience method configures marshaling for native structures with optional packing and size specifications.

§Arguments
  • packing_size - Optional structure packing alignment in bytes
  • class_size - Optional total structure size in bytes
§Returns

Self for method chaining.

pub fn safe_array( self, variant_type: u16, user_defined_name: Option<String>, ) -> Self

Sets marshaling for a COM safe array.

This convenience method configures marshaling for COM safe arrays with variant type specification for element types.

§Arguments
  • variant_type - VARIANT type constant for array elements
  • user_defined_name - Optional user-defined type name
§Returns

Self for method chaining.

pub fn custom_marshaler( self, guid: &str, native_type_name: &str, cookie: &str, type_reference: &str, ) -> Self

Sets marshaling for a custom marshaler.

This convenience method configures marshaling using a user-defined custom marshaler with GUID identification and initialization parameters.

§Arguments
  • guid - GUID identifying the custom marshaler
  • native_type_name - Native type name for the marshaler
  • cookie - Cookie string passed to the marshaler for initialization
  • type_reference - Full type name of the custom marshaler class
§Returns

Self for method chaining.

pub fn build(self, assembly: &mut CilAssembly) -> Result<ChangeRefRc>

Builds the field marshal entry and adds it to the assembly.

This method validates all required fields are set, adds the marshaling descriptor to the blob heap, creates the raw field marshal structure, and adds it to the FieldMarshal table with proper token generation.

§Arguments
  • assembly - The assembly being modified
§Returns

A crate::metadata::token::Token representing the newly created field marshal entry, or an error if validation fails or required fields are missing.

§Errors
  • Returns error if encoding failed during native_type_spec or marshalling_info
  • Returns error if parent is not set
  • Returns error if native_type is not set or empty
  • Returns error if parent is not a valid HasFieldMarshal coded index
  • Returns error if blob operations fail
  • Returns error if table operations fail

Trait Implementations§

§

impl Default for FieldMarshalBuilder

§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

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> AsAny for T
where T: Any,

Source§

fn as_any(&self) -> &(dyn Any + 'static)

Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Source§

fn type_name(&self) -> &'static str

Gets the type name of self
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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> Downcast for T
where T: AsAny + ?Sized,

Source§

fn is<T>(&self) -> bool
where T: AsAny,

Returns true if the boxed type is the same as T. Read more
Source§

fn downcast_ref<T>(&self) -> Option<&T>
where T: AsAny,

Forward to the method defined on the type Any.
Source§

fn downcast_mut<T>(&mut self) -> Option<&mut T>
where T: AsAny,

Forward to the method defined on the type Any.
Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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, A> IntoAst<A> for T
where T: Into<A>, A: Ast,

Source§

fn into_ast(self, _a: &A) -> A

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<F, T> IntoSample<T> for F
where T: FromSample<F>,

Source§

fn into_sample(self) -> T

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> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<R, P> ReadPrimitive<R> for P
where R: Read + ReadEndian<P>, P: Default,

Source§

fn read_from_little_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_little_endian().
Source§

fn read_from_big_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_big_endian().
Source§

fn read_from_native_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_native_endian().
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

Source§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
Source§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
Source§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
Source§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
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.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more