use std::fmt::Debug;
use crate::dotnet::entries::{EntryCollection, EntryView, MaybeUninitEntries};
use crate::dotnet::{
entries::{values::*, EntList},
metadata::Metadata,
};
use crate::error::HaoError;
use crate::{error::Result, io::EntryReader};
use super::resolver::PathAssemblyResolver;
use super::resolver::{AssemblyLoadResult, AssemblyResolver};
#[derive(Debug, Clone, Default)]
pub struct Module {
pub(crate) modules: EntList<ModuleDef>,
pub(crate) type_refs: EntList<TypeRef>,
pub(crate) type_defs: EntList<TypeDef>,
pub(crate) fields: EntList<Field>,
pub(crate) methods: EntList<Method>,
pub(crate) params: EntList<Param>,
pub(crate) module_ref: EntList<ModuleRef>,
pub(crate) type_specs: EntList<TypeSpec>,
pub(crate) assembly_ref: EntList<AssemblyRef>,
}
impl Module {
pub fn from_path(path: impl AsRef<std::path::Path>) -> Result<Self> {
let mut exec_path = path.as_ref().to_owned();
let asm = {
let data = std::fs::read(&exec_path).map_err(HaoError::IoError)?;
let md = Metadata::parse(&data)?;
Self::from_metadata(&md)?
};
exec_path.pop();
let mut resolver: PathAssemblyResolver = PathAssemblyResolver::new(&exec_path);
asm.load_dependancies(&mut resolver)?;
Ok(asm)
}
pub fn from_path_no_resolve(path: impl AsRef<std::path::Path>) -> Result<Self> {
let data = std::fs::read(path.as_ref()).map_err(HaoError::IoError)?;
let md = Metadata::parse(&data)?;
let asm = Self::from_metadata(&md)?;
Ok(asm)
}
pub fn from_metadata(metadada: &Metadata) -> Result<Self> {
let entries = {
let locations = &metadada
.metadata_streams
.tables_stream
.header
.table_locations;
let maybe_entries = MaybeUninitEntries::from_rows(locations);
let reader = EntryReader::from_metadata(&metadada.metadata_streams, &maybe_entries);
maybe_entries.init_rows(locations, &reader)?;
maybe_entries
};
for if_impl in entries.interface_impls {
let inner = if_impl.into_inner();
let InterfaceImpl { class, interface } = inner.assume_init_value();
class.value_mut().interface_impl.push(interface);
}
Ok(Self {
modules: entries.modules,
type_refs: entries.type_refs,
type_defs: entries.type_defs,
fields: entries.fields,
methods: entries.methods,
params: entries.params,
module_ref: entries.module_ref,
type_specs: entries.type_specs,
assembly_ref: entries.assembly_ref,
})
}
pub fn load_dependancies(&self, resolver: &mut impl AssemblyResolver) -> Result<()> {
for asm in self.assembly_ref.iter() {
let mut asm: std::cell::RefMut<AssemblyRef> = asm.value_mut();
if asm.refrenced_assembly.is_some() {
continue;
}
asm.refrenced_assembly = match resolver.load(&asm.name)? {
AssemblyLoadResult::Ignore => None,
AssemblyLoadResult::Loaded(asm) => Some(asm),
};
}
Ok(())
}
#[inline(always)]
pub fn module(&self) -> EntryView<ModuleDef> {
EntryView(&self.modules[0])
}
#[inline(always)]
pub fn type_refs(&self) -> EntryCollection<TypeRef> {
EntryCollection::new(&self.type_refs)
}
#[inline(always)]
pub fn types(&self) -> EntryCollection<TypeDef> {
EntryCollection::new(&self.type_defs)
}
#[inline(always)]
pub fn all_fields(&self) -> EntryCollection<Field> {
EntryCollection::new(&self.fields)
}
#[inline(always)]
pub fn all_methods(&self) -> EntryCollection<Method> {
EntryCollection::new(&self.methods)
}
#[inline(always)]
pub fn all_params(&self) -> EntryCollection<Param> {
EntryCollection::new(&self.params)
}
#[inline(always)]
pub fn all_type_specs(&self) -> EntryCollection<TypeSpec> {
EntryCollection::new(&self.type_specs)
}
#[inline(always)]
pub fn module_ref(&self) -> EntryCollection<ModuleRef> {
EntryCollection::new(&self.module_ref)
}
#[inline(always)]
pub fn assembly_ref(&self) -> EntryCollection<AssemblyRef> {
EntryCollection::new(&self.assembly_ref)
}
}