use crate::{
metadata::{
method::MethodMap,
tables::{
ImportScopeMap, LocalConstantMap, LocalScope, LocalScopeRc, LocalVariableMap,
MetadataTable, TableId, TableInfoRef, TableRow,
},
token::Token,
},
Result,
};
use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct LocalScopeRaw {
pub rid: u32,
pub token: Token,
pub offset: usize,
pub method: u32,
pub import_scope: u32,
pub variable_list: u32,
pub constant_list: u32,
pub start_offset: u32,
pub length: u32,
}
impl LocalScopeRaw {
pub fn to_owned(
&self,
methods: &MethodMap,
import_scopes: &ImportScopeMap,
variables: &LocalVariableMap,
constants: &LocalConstantMap,
scope_table: &MetadataTable<LocalScopeRaw>,
) -> Result<LocalScopeRc> {
let method_token = Token::new(0x0600_0000 + self.method);
let method = methods
.get(&method_token)
.ok_or_else(|| malformed_error!("Invalid method index {} in LocalScope", self.method))?
.value()
.clone();
let import_scope = if self.import_scope == 0 {
None
} else {
let import_token = Token::new(0x3500_0000 + self.import_scope);
Some(
import_scopes
.get(&import_token)
.ok_or_else(|| {
malformed_error!(
"Invalid import scope index {} in LocalScope",
self.import_scope
)
})?
.value()
.clone(),
)
};
let variables = if self.variable_list == 0 {
Arc::new(boxcar::Vec::new())
} else {
let start = self.variable_list;
#[allow(clippy::cast_possible_truncation)]
let end = if let Some(next_scope) = scope_table.get(self.rid + 1) {
if next_scope.variable_list != 0 {
next_scope.variable_list
} else {
variables.len() as u32 + 1
}
} else {
variables.len() as u32 + 1
};
let list = Arc::new(boxcar::Vec::new());
for i in start..end {
let var_token = Token::new(0x3300_0000 + i);
if let Some(var_entry) = variables.get(&var_token) {
list.push(var_entry.value().clone());
}
}
list
};
let constants = if self.constant_list == 0 {
Arc::new(boxcar::Vec::new())
} else {
let start = self.constant_list;
#[allow(clippy::cast_possible_truncation)]
let end = if let Some(next_scope) = scope_table.get(self.rid + 1) {
if next_scope.constant_list != 0 {
next_scope.constant_list
} else {
constants.len() as u32 + 1
}
} else {
constants.len() as u32 + 1
};
let list = Arc::new(boxcar::Vec::new());
for i in start..end {
let const_token = Token::new(0x3400_0000 + i);
if let Some(const_entry) = constants.get(&const_token) {
list.push(const_entry.value().clone());
}
}
list
};
let local_scope = LocalScope {
rid: self.rid,
token: self.token,
offset: self.offset,
method,
import_scope,
variables,
constants,
start_offset: self.start_offset,
length: self.length,
};
Ok(Arc::new(local_scope))
}
}
impl TableRow for LocalScopeRaw {
#[rustfmt::skip]
fn row_size(sizes: &TableInfoRef) -> u32 {
u32::from(
sizes.table_index_bytes(TableId::MethodDef) +
sizes.table_index_bytes(TableId::ImportScope) +
sizes.table_index_bytes(TableId::LocalVariable) +
sizes.table_index_bytes(TableId::LocalConstant) +
4 +
4
)
}
}