use std::sync::Arc;
use crate::{
metadata::{
signatures::parse_method_spec_signature,
streams::Blob,
tables::{CodedIndex, CodedIndexType, MethodSpec, MethodSpecRc, TableInfoRef, TableRow},
token::Token,
typesystem::{CilTypeReference, TypeRegistry, TypeResolver},
},
Result,
};
#[derive(Clone, Debug)]
pub struct MethodSpecRaw {
pub rid: u32,
pub token: Token,
pub offset: usize,
pub method: CodedIndex,
pub instantiation: u32,
}
impl MethodSpecRaw {
pub fn to_owned_and_apply<F>(
&self,
get_ref: F,
blob: &Blob,
types: &Arc<TypeRegistry>,
) -> Result<MethodSpecRc>
where
F: Fn(&CodedIndex) -> CilTypeReference,
{
let method = get_ref(&self.method);
if matches!(method, CilTypeReference::None) {
return Err(malformed_error!(
"Failed to resolve method token - {}",
self.method.token.value()
));
}
let instantiation = parse_method_spec_signature(blob.get(self.instantiation as usize)?)?;
let generic_args = Arc::new(boxcar::Vec::with_capacity(instantiation.generic_args.len()));
let mut resolver = TypeResolver::new(types.clone()).with_parent(self.token);
for type_sig in &instantiation.generic_args {
let resolved_type = resolver.resolve(type_sig)?;
generic_args.push(resolved_type.into());
}
let method_spec = Arc::new(MethodSpec {
rid: self.rid,
token: self.token,
offset: self.offset,
method: method.clone(),
instantiation,
custom_attributes: Arc::new(boxcar::Vec::new()),
generic_args,
});
match &method {
CilTypeReference::MethodDef(method_ref) => {
if let Some(method_def) = method_ref.upgrade() {
method_def.generic_args.push(method_spec.clone());
} else {
return Err(malformed_error!(
"Failed to resolve method - {}",
self.method.token.value()
));
}
}
CilTypeReference::MemberRef(member_ref) => {
match &member_ref.declaredby {
CilTypeReference::TypeRef(ciltype)
| CilTypeReference::TypeDef(ciltype)
| CilTypeReference::TypeSpec(ciltype) => {
if let Some(args) = ciltype.generic_args() {
args.push(method_spec.clone());
}
}
CilTypeReference::MethodDef(target_method) => {
if let Some(target_method) = target_method.upgrade() {
target_method.generic_args.push(method_spec.clone());
}
}
CilTypeReference::ModuleRef(_module) => {
}
_ => {
return Err(malformed_error!("Invalid memberref type reference"));
}
}
}
_ => {
return Err(malformed_error!("Invalid method type reference"));
}
}
Ok(method_spec)
}
}
impl TableRow for MethodSpecRaw {
#[rustfmt::skip]
fn row_size(sizes: &TableInfoRef) -> u32 {
u32::from(
sizes.coded_index_bytes(CodedIndexType::MethodDefOrRef) +
sizes.blob_bytes()
)
}
}