use std::sync::{Arc, OnceLock};
use crate::metadata::{
marshalling::{MarshallingInfo, NativeType},
signatures::{SignatureField, TypeSignature},
tables::{Field, FieldAttributes, FieldRc},
token::Token,
typesystem::{CilFlavor, CilPrimitive, CilTypeRc},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FieldLayout {
Auto,
Sequential,
Explicit(u32),
}
#[derive(Debug, Clone)]
pub enum FieldMarshalling {
None,
LPStr,
LPWStr,
BStr,
FixedArray(u32),
Custom(MarshallingInfo),
}
#[derive(Debug, Clone)]
pub enum FieldConstant {
Bool(bool),
I1(i8),
U1(u8),
I2(i16),
U2(u16),
I4(i32),
U4(u32),
I8(i64),
U8(u64),
R4(f32),
R8(f64),
String(String),
Null,
}
pub struct FieldBuilder {
rid: u32,
name: String,
field_type: Option<CilTypeRc>,
flags: u32,
layout: FieldLayout,
marshalling: FieldMarshalling,
constant: Option<FieldConstant>,
rva: Option<u32>, }
impl FieldBuilder {
pub fn new(name: &str, field_type: CilTypeRc) -> Self {
Self {
rid: 1,
name: name.to_string(),
field_type: Some(field_type),
flags: FieldAttributes::PUBLIC,
layout: FieldLayout::Auto,
marshalling: FieldMarshalling::None,
constant: None,
rva: None,
}
}
pub fn with_rid(mut self, rid: u32) -> Self {
self.rid = rid;
self
}
pub fn with_access_private(mut self) -> Self {
self.flags = (self.flags & !FieldAttributes::FIELD_ACCESS_MASK) | FieldAttributes::PRIVATE;
self
}
pub fn with_access_public(mut self) -> Self {
self.flags = (self.flags & !FieldAttributes::FIELD_ACCESS_MASK) | FieldAttributes::PUBLIC;
self
}
pub fn with_access_family(mut self) -> Self {
self.flags = (self.flags & !FieldAttributes::FIELD_ACCESS_MASK) | FieldAttributes::FAMILY;
self
}
pub fn with_access_assembly(mut self) -> Self {
self.flags = (self.flags & !FieldAttributes::FIELD_ACCESS_MASK) | FieldAttributes::ASSEMBLY;
self
}
pub fn with_flags(mut self, flags: u32) -> Self {
self.flags = flags;
self
}
pub fn with_static(mut self) -> Self {
self.flags |= FieldAttributes::STATIC;
self
}
pub fn with_initonly(mut self) -> Self {
self.flags |= FieldAttributes::INIT_ONLY;
self
}
pub fn with_literal(mut self) -> Self {
self.flags |= FieldAttributes::LITERAL;
self
}
pub fn with_layout(mut self, layout: FieldLayout) -> Self {
self.layout = layout;
self
}
pub fn with_marshalling(mut self, marshalling: FieldMarshalling) -> Self {
self.marshalling = marshalling;
self
}
pub fn with_constant(mut self, constant: FieldConstant) -> Self {
self.constant = Some(constant);
self.flags |= FieldAttributes::HAS_DEFAULT | FieldAttributes::LITERAL;
self
}
pub fn with_rva(mut self, rva: u32) -> Self {
self.rva = Some(rva);
self.flags |= FieldAttributes::HAS_FIELD_RVA;
self
}
pub fn private_field(name: &str, field_type: CilTypeRc) -> Self {
Self::new(name, field_type).with_access_private()
}
pub fn public_static_field(name: &str, field_type: CilTypeRc) -> Self {
Self::new(name, field_type)
.with_access_public()
.with_static()
}
pub fn readonly_field(name: &str, field_type: CilTypeRc) -> Self {
Self::new(name, field_type).with_initonly()
}
pub fn const_field(name: &str, field_type: CilTypeRc, value: FieldConstant) -> Self {
Self::new(name, field_type)
.with_access_public()
.with_static()
.with_constant(value)
}
pub fn explicit_layout_field(name: &str, field_type: CilTypeRc, offset: u32) -> Self {
Self::new(name, field_type).with_layout(FieldLayout::Explicit(offset))
}
pub fn pinvoke_field(name: &str, field_type: CilTypeRc, marshalling: FieldMarshalling) -> Self {
Self::new(name, field_type).with_marshalling(marshalling)
}
pub fn backing_field(property_name: &str, field_type: CilTypeRc) -> Self {
Self::private_field(&format!("<{property_name}>k__BackingField"), field_type)
.with_flags(FieldAttributes::COMPILER_CONTROLLED)
}
pub fn simple_i4_field(name: &str) -> Self {
let i4_type = Arc::new(crate::metadata::typesystem::CilType::new(
Token::new(0x02000001),
"System".to_string(),
"Int32".to_string(),
None,
None,
0,
Arc::new(boxcar::Vec::new()),
Arc::new(boxcar::Vec::new()),
Some(CilFlavor::I4),
));
Self::new(name, i4_type)
}
pub fn simple_string_field(name: &str) -> Self {
let string_type = Arc::new(crate::metadata::typesystem::CilType::new(
Token::new(0x02000002),
"System".to_string(),
"String".to_string(),
None,
None,
0,
Arc::new(boxcar::Vec::new()),
Arc::new(boxcar::Vec::new()),
Some(CilFlavor::String),
));
Self::new(name, string_type)
}
pub fn simple_boolean_field(name: &str) -> Self {
let bool_type = Arc::new(crate::metadata::typesystem::CilType::new(
Token::new(0x02000003),
"System".to_string(),
"Boolean".to_string(),
None,
None,
0,
Arc::new(boxcar::Vec::new()),
Arc::new(boxcar::Vec::new()),
Some(CilFlavor::Boolean),
));
Self::new(name, bool_type)
}
pub fn simple_r4_field(name: &str) -> Self {
let r4_type = Arc::new(crate::metadata::typesystem::CilType::new(
Token::new(0x02000004),
"System".to_string(),
"Single".to_string(),
None,
None,
0,
Arc::new(boxcar::Vec::new()),
Arc::new(boxcar::Vec::new()),
Some(CilFlavor::R4),
));
Self::new(name, r4_type)
}
pub fn simple_object_field(name: &str) -> Self {
let object_type = Arc::new(crate::metadata::typesystem::CilType::new(
Token::new(0x02000005),
"System".to_string(),
"Object".to_string(),
None,
None,
0,
Arc::new(boxcar::Vec::new()),
Arc::new(boxcar::Vec::new()),
Some(CilFlavor::Object),
));
Self::new(name, object_type)
}
pub fn build(self) -> FieldRc {
let offset = self.compute_offset();
let marshal_info = self.create_marshalling_info();
let signature = if let Some(ref field_type) = self.field_type {
match field_type.flavor() {
CilFlavor::I4 => SignatureField {
modifiers: Vec::new(),
base: TypeSignature::I4,
},
CilFlavor::String => SignatureField {
modifiers: Vec::new(),
base: TypeSignature::String,
},
CilFlavor::Boolean => SignatureField {
modifiers: Vec::new(),
base: TypeSignature::Boolean,
},
CilFlavor::R4 => SignatureField {
modifiers: Vec::new(),
base: TypeSignature::R4,
},
CilFlavor::Object => SignatureField {
modifiers: Vec::new(),
base: TypeSignature::Object,
},
_ => SignatureField {
modifiers: Vec::new(),
base: TypeSignature::I4, },
}
} else {
SignatureField {
modifiers: Vec::new(),
base: TypeSignature::I4, }
};
let field = Field {
rid: self.rid,
token: Token::new(0x04000000 + self.rid),
offset: self.rid as usize,
flags: self.flags,
name: self.name,
signature,
default: OnceLock::new(),
rva: OnceLock::new(),
layout: OnceLock::new(),
marshal: OnceLock::new(),
custom_attributes: Arc::new(boxcar::Vec::new()),
declaring_type: OnceLock::new(),
};
let field_rc = Arc::new(field);
if self.constant.is_some() {
let primitive = CilPrimitive {
kind: crate::metadata::typesystem::CilPrimitiveKind::I4,
data: crate::metadata::typesystem::CilPrimitiveData::I4(42),
};
let _ = field_rc.default.set(primitive);
}
if let Some(rva_val) = self.rva {
let _ = field_rc.rva.set(rva_val);
}
if let Some(offset_val) = offset {
let _ = field_rc.layout.set(offset_val);
}
if let Some(marshal) = marshal_info {
let _ = field_rc.marshal.set(marshal);
}
field_rc
}
fn compute_offset(&self) -> Option<u32> {
match self.layout {
FieldLayout::Explicit(offset) => Some(offset),
_ => None,
}
}
fn create_marshalling_info(&self) -> Option<MarshallingInfo> {
match &self.marshalling {
FieldMarshalling::None => None,
FieldMarshalling::LPStr => Some(MarshallingInfo {
primary_type: NativeType::LPStr {
size_param_index: None,
},
additional_types: Vec::new(),
}),
FieldMarshalling::LPWStr => Some(MarshallingInfo {
primary_type: NativeType::LPWStr {
size_param_index: None,
},
additional_types: Vec::new(),
}),
FieldMarshalling::BStr => Some(MarshallingInfo {
primary_type: NativeType::BStr,
additional_types: Vec::new(),
}),
FieldMarshalling::FixedArray(size) => Some(MarshallingInfo {
primary_type: NativeType::FixedArray {
size: *size,
element_type: None,
},
additional_types: Vec::new(),
}),
FieldMarshalling::Custom(info) => Some(info.clone()),
}
}
}
impl Default for FieldBuilder {
fn default() -> Self {
let default_type = Arc::new(crate::metadata::typesystem::CilType::new(
Token::new(0x02000001),
"System".to_string(),
"Int32".to_string(),
None,
None,
0,
Arc::new(boxcar::Vec::new()),
Arc::new(boxcar::Vec::new()),
Some(CilFlavor::I4),
));
Self::new("DefaultField", default_type)
}
}
pub struct FieldLayoutBuilder {
fields: Vec<FieldBuilder>,
layout_kind: u32, packing_size: Option<u16>,
class_size: Option<u32>,
}
impl FieldLayoutBuilder {
pub fn new() -> Self {
Self {
fields: Vec::new(),
layout_kind: 0, packing_size: None,
class_size: None,
}
}
pub fn with_auto_layout(mut self) -> Self {
self.layout_kind = 0;
self
}
pub fn with_sequential_layout(mut self) -> Self {
self.layout_kind = 1;
self
}
pub fn with_explicit_layout(mut self) -> Self {
self.layout_kind = 2;
self
}
pub fn with_packing_size(mut self, size: u16) -> Self {
self.packing_size = Some(size);
self
}
pub fn with_class_size(mut self, size: u32) -> Self {
self.class_size = Some(size);
self
}
pub fn add_field(mut self, field: FieldBuilder) -> Self {
self.fields.push(field);
self
}
pub fn build(self) -> Vec<FieldRc> {
self.fields.into_iter().map(|f| f.build()).collect()
}
}
impl Default for FieldLayoutBuilder {
fn default() -> Self {
Self::new()
}
}