use std::sync::Arc;
use crate::{
metadata::{
method::MethodMap,
tables::{
CodedIndex, CodedIndexType, MemberRefMap, MethodImpl, MethodImplRc, TableId,
TableInfoRef, TableRow,
},
token::Token,
typesystem::{CilTypeReference, TypeRegistry},
},
Result,
};
#[derive(Clone, Debug)]
pub struct MethodImplRaw {
pub rid: u32,
pub token: Token,
pub offset: usize,
pub class: u32,
pub method_body: CodedIndex,
pub method_declaration: CodedIndex,
}
impl MethodImplRaw {
pub fn apply(
&self,
types: &TypeRegistry,
memberrefs: &MemberRefMap,
methods: &MethodMap,
) -> Result<()> {
let interface_implementation = match self.method_body.tag {
TableId::MethodDef => match methods.get(&self.method_body.token) {
Some(parent) => CilTypeReference::MethodDef(parent.value().clone().into()),
None => {
return Err(malformed_error!(
"Failed to resolve methoddef method_body token - {}",
self.method_body.token.value()
))
}
},
TableId::MemberRef => match memberrefs.get(&self.method_body.token) {
Some(parent) => CilTypeReference::MemberRef(parent.value().clone()),
None => {
return Err(malformed_error!(
"Failed to resolve memberref method_body token - {}",
self.method_body.token.value()
))
}
},
_ => {
return Err(malformed_error!(
"Invalid method_body token - {}",
self.method_body.token.value()
))
}
};
match types.get(&Token::new(self.class | 0x0200_0000)) {
Some(cil_type) => {
cil_type.overwrites.push(interface_implementation.clone());
match self.method_declaration.tag {
TableId::MethodDef => match methods.get(&self.method_declaration.token) {
Some(parent) => {
if let CilTypeReference::MethodDef(method_ref) =
&interface_implementation
{
parent.value().interface_impls.push(method_ref.clone());
}
}
None => {
return Err(malformed_error!(
"Failed to resolve methoddef method_declaration token - {}",
self.method_declaration.token.value()
))
}
},
TableId::MemberRef => match memberrefs.get(&self.method_declaration.token) {
Some(_parent) => {
}
None => {
return Err(malformed_error!(
"Failed to resolve memberref method_declaration token - {}",
self.method_declaration.token.value()
))
}
},
_ => {
return Err(malformed_error!(
"Invalid method_declaration token - {}",
self.method_declaration.token.value()
))
}
}
Ok(())
}
None => Err(malformed_error!(
"Failed to resolve class type token - {}",
self.class | 0x0200_0000
)),
}
}
pub fn to_owned<F>(&self, get_ref: F, types: &TypeRegistry) -> Result<MethodImplRc>
where
F: Fn(&CodedIndex) -> CilTypeReference,
{
Ok(Arc::new(MethodImpl {
rid: self.rid,
token: self.token,
offset: self.offset,
class: match types.get(&Token::new(self.class | 0x0200_0000)) {
Some(cil_type) => cil_type.clone(),
None => {
return Err(malformed_error!(
"Failed to resolve class type token - {}",
self.class | 0x0200_0000
))
}
},
method_body: {
let result = get_ref(&self.method_body);
if matches!(result, CilTypeReference::None) {
return Err(malformed_error!(
"Failed to resolve method_body token - {}",
self.method_body.token.value()
));
}
result
},
method_declaration: {
let result = get_ref(&self.method_declaration);
if matches!(result, CilTypeReference::None) {
return Err(malformed_error!(
"Failed to resolve method_declaration token - {}",
self.method_declaration.token.value()
));
}
result
},
}))
}
}
impl TableRow for MethodImplRaw {
#[rustfmt::skip]
fn row_size(sizes: &TableInfoRef) -> u32 {
u32::from(
sizes.table_index_bytes(TableId::TypeDef) +
sizes.coded_index_bytes(CodedIndexType::MethodDefOrRef) +
sizes.coded_index_bytes(CodedIndexType::MethodDefOrRef)
)
}
}