mod containers;
pub mod signature;
pub mod values;
pub mod well_known;
use std::cell::{Ref, RefCell, RefMut};
use super::md::streams::tables_stream::metadata::TableLocations;
use crate::{
dotnet::md::streams::tables_stream::{TableLocation, TablesStreamReader},
error::Result,
io::{EntryReader, ReadData},
};
pub use containers::*;
use values::*;
#[derive(Copy, Clone, Debug)]
pub struct RowRange<T> {
pub start: T,
pub end: Option<T>,
}
impl<T> RowRange<T> {
pub fn new(start: T, end: Option<T>) -> Self {
Self { start, end }
}
}
pub trait ReadEntry<T>: Sized {
type RawRow;
fn from_row(
&self,
index: usize,
row: &Self::RawRow,
next_row: Option<&Self::RawRow>,
) -> Result<T>;
}
pub trait GetEntryField<T> {
type EntryFieldValue: Clone;
fn get_entry_field(&self, identifier: T) -> Result<Self::EntryFieldValue>;
}
#[derive(Debug)]
pub struct EntryView<'a, T>(pub(crate) &'a Ptr<T>);
impl<'a, T> EntryView<'a, T> {
pub fn into_entry(&self) -> Entry<T> {
Entry(self.0.clone())
}
pub fn value(&self) -> Ref<RowEntry<T>> {
self.0.value()
}
pub fn value_mut(&self) -> RefMut<T> {
self.0.value_mut()
}
pub fn try_value(&self) -> Option<Ref<RowEntry<T>>> {
self.0.try_value()
}
pub fn try_value_mut(&self) -> Option<RefMut<T>> {
self.0.try_value_mut()
}
pub fn map<E, F: FnOnce(Ref<RowEntry<T>>) -> E>(&self, func: F) -> E {
func(self.value())
}
}
#[derive(Debug, Clone)]
pub struct Entry<T>(pub(crate) Ptr<T>);
impl<'a, T> Entry<T> {
#[inline(always)]
pub fn value(&self) -> Ref<RowEntry<T>> {
self.0.value()
}
#[inline(always)]
pub fn value_mut(&self) -> RefMut<T> {
self.0.value_mut()
}
#[inline(always)]
pub fn try_value(&self) -> Option<Ref<RowEntry<T>>> {
self.0.try_value()
}
#[inline(always)]
pub fn try_value_mut(&self) -> Option<RefMut<T>> {
self.0.try_value_mut()
}
#[inline(always)]
pub fn map<E, F: FnOnce(Ref<RowEntry<T>>) -> E>(&self, func: F) -> E {
func(self.value())
}
}
pub struct EntryCollection<'a, T> {
rows: &'a [Ptr<T>],
position: usize,
}
impl<'a, T> EntryCollection<'a, T> {
pub(crate) fn new(rows: &'a [Ptr<T>]) -> Self {
Self { rows, position: 0 }
}
#[inline(always)]
pub fn values(&self) -> EntryIteratorValue<'a, T> {
EntryIteratorValue::new(&self.rows[self.position..])
}
#[inline(always)]
pub fn values_mut(&self) -> EntryIteratorValueMut<'a, T> {
EntryIteratorValueMut::new(&self.rows[self.position..])
}
#[inline(always)]
pub fn get_index(&self, index: usize) -> Option<Entry<T>> {
self.rows.get(index).map(|v| Entry(v.clone()))
}
#[inline(always)]
pub fn find(&self, func: impl Fn(EntryView<'a, T>) -> bool) -> Option<Entry<T>> {
self.rows
.iter()
.find(|e| func(EntryView(e)))
.map(|e| Entry(e.clone()))
}
}
impl<'a, T> Iterator for EntryCollection<'a, T> {
type Item = EntryView<'a, T>;
fn next(&mut self) -> Option<Self::Item> {
let value = self.rows.get(self.position);
value.map(|v| {
self.position += 1;
EntryView(v)
})
}
}
pub struct EntryIteratorValue<'a, T> {
rows: &'a [Ptr<T>],
position: usize,
}
impl<'a, T> EntryIteratorValue<'a, T> {
pub(crate) fn new(rows: &'a [Ptr<T>]) -> Self {
Self { rows, position: 0 }
}
}
impl<'a, T> Iterator for EntryIteratorValue<'a, T> {
type Item = Ref<'a, RowEntry<T>>;
fn next(&mut self) -> Option<Self::Item> {
let value = self.rows.get(self.position);
value.map(|v| {
self.position += 1;
v.value()
})
}
}
pub struct EntryIteratorValueMut<'a, T> {
rows: &'a [Ptr<T>],
position: usize,
}
impl<'a, T> EntryIteratorValueMut<'a, T> {
pub(crate) fn new(rows: &'a [Ptr<T>]) -> Self {
Self { rows, position: 0 }
}
}
impl<'a, T> Iterator for EntryIteratorValueMut<'a, T> {
type Item = RefMut<'a, T>;
fn next(&mut self) -> Option<Self::Item> {
let value = self.rows.get(self.position);
value.map(|v| {
self.position += 1;
v.value_mut()
})
}
}
pub(crate) struct MaybeUninitEntries {
pub modules: EntList<ModuleDef>,
pub type_refs: EntList<TypeRef>,
pub type_defs: EntList<TypeDef>,
pub fields: EntList<Field>,
pub methods: EntList<Method>,
pub params: EntList<Param>,
pub interface_impls: Vec<RefCell<MaybeUnsetEntry<InterfaceImpl>>>,
pub module_ref: EntList<ModuleRef>,
pub type_specs: EntList<TypeSpec>,
pub assembly_ref: EntList<AssemblyRef>,
}
impl MaybeUninitEntries {
pub fn from_rows(locations: &TableLocations) -> Self {
fn init_ent_list<T>(size: TableLocation) -> EntList<T> {
let mut v = EntList::with_capacity(size.rows.0 as usize);
for _ in 0..v.capacity() {
v.push(Ptr::new_unset());
}
v
}
fn init_metadata_list<T>(size: TableLocation) -> Vec<RefCell<MaybeUnsetEntry<T>>> {
let mut v = Vec::with_capacity(size.rows.0 as usize);
for _ in 0..v.capacity() {
v.push(RefCell::new(MaybeUnsetEntry::new_unset()));
}
v
}
Self {
modules: init_ent_list(locations.module),
type_refs: init_ent_list(locations.type_ref),
type_defs: init_ent_list(locations.type_def),
fields: init_ent_list(locations.field),
methods: init_ent_list(locations.method),
params: init_ent_list(locations.param),
interface_impls: init_metadata_list(locations.interface_impl),
module_ref: init_ent_list(locations.module_ref),
type_specs: init_ent_list(locations.type_spec),
assembly_ref: init_ent_list(locations.assembly_ref),
}
}
pub fn init_rows(&self, locations: &TableLocations, reader: &EntryReader) -> Result<()> {
fn write_ent<V>(entry: &Ptr<V>, value: V, index: usize) {
let row = (index + 1) as u32; entry.set_value(row, value);
}
fn write_metadata<V>(entry: &RefCell<MaybeUnsetEntry<V>>, value: V, index: usize) {
let row = (index + 1) as u32; entry.borrow_mut().set_value(row, value);
}
fn init_ent_list<'a, T, V>(
uninit_rows: &Vec<T>,
location: &TableLocation,
reader: &EntryReader<'a>,
write_value: fn(entry: &T, V, usize),
) -> Result<()>
where
EntryReader<'a>: ReadEntry<V>,
TablesStreamReader<'a>: ReadData<<EntryReader<'a> as ReadEntry<V>>::RawRow>,
{
let mut row_iter = reader
.streams
.tables_stream
.row_iter(*location)?
.enumerate()
.peekable();
while let Some((index, row)) = row_iter.next() {
let row: <EntryReader as ReadEntry<V>>::RawRow = row?;
let next = match row_iter.peek() {
Some((_, Ok(v))) => Some(v),
_ => None,
};
let val = reader.from_row(index, &row, next)?;
let entry = &uninit_rows[index];
write_value(entry, val, index);
}
Ok(())
}
init_ent_list(&self.modules, &locations.module, reader, write_ent)?;
init_ent_list(&self.type_refs, &locations.type_ref, reader, write_ent)?;
init_ent_list(&self.type_defs, &locations.type_def, reader, write_ent)?;
init_ent_list(&self.fields, &locations.field, reader, write_ent)?;
init_ent_list(&self.methods, &locations.method, reader, write_ent)?;
init_ent_list(&self.params, &locations.param, reader, write_ent)?;
init_ent_list(
&self.interface_impls,
&locations.interface_impl,
reader,
write_metadata,
)?;
init_ent_list(&self.module_ref, &locations.module_ref, reader, write_ent)?;
init_ent_list(&self.type_specs, &locations.type_spec, reader, write_ent)?;
init_ent_list(
&self.assembly_ref,
&locations.assembly_ref,
reader,
write_ent,
)?;
Ok(())
}
}