use super::{
engine::DedupFuncType,
AsContext,
Extern,
Func,
Global,
Index,
Memory,
StoreContext,
Stored,
Table,
};
use alloc::{
collections::{btree_map, BTreeMap},
string::{String, ToString},
vec::Vec,
};
use core::{iter::FusedIterator, ops::Deref};
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct InstanceIdx(u32);
impl Index for InstanceIdx {
fn into_usize(self) -> usize {
self.0 as usize
}
fn from_usize(value: usize) -> Self {
let value = value.try_into().unwrap_or_else(|error| {
panic!("index {value} is out of bounds as instance index: {error}")
});
Self(value)
}
}
#[derive(Debug)]
pub struct InstanceEntity {
initialized: bool,
func_types: Vec<DedupFuncType>,
tables: Vec<Table>,
funcs: Vec<Func>,
memories: Vec<Memory>,
globals: Vec<Global>,
exports: BTreeMap<String, Extern>,
}
impl InstanceEntity {
pub(crate) fn uninitialized() -> InstanceEntity {
Self {
initialized: false,
func_types: Vec::new(),
tables: Vec::new(),
funcs: Vec::new(),
memories: Vec::new(),
globals: Vec::new(),
exports: BTreeMap::new(),
}
}
pub(crate) fn build() -> InstanceEntityBuilder {
InstanceEntityBuilder {
instance: Self {
initialized: false,
func_types: Vec::default(),
tables: Vec::default(),
funcs: Vec::default(),
memories: Vec::default(),
globals: Vec::default(),
exports: BTreeMap::default(),
},
}
}
pub(crate) fn is_initialized(&self) -> bool {
self.initialized
}
pub(crate) fn get_memory(&self, index: u32) -> Option<Memory> {
self.memories.get(index as usize).copied()
}
pub(crate) fn get_table(&self, index: u32) -> Option<Table> {
self.tables.get(index as usize).copied()
}
pub(crate) fn get_global(&self, index: u32) -> Option<Global> {
self.globals.get(index as usize).copied()
}
pub(crate) fn get_func(&self, index: u32) -> Option<Func> {
self.funcs.get(index as usize).copied()
}
pub(crate) fn get_signature(&self, index: u32) -> Option<DedupFuncType> {
self.func_types.get(index as usize).copied()
}
pub(crate) fn get_export(&self, name: &str) -> Option<Extern> {
self.exports.get(name).copied()
}
pub fn exports(&self) -> ExportsIter {
ExportsIter::new(self.exports.iter())
}
}
#[derive(Debug)]
pub struct ExportsIter<'a> {
iter: btree_map::Iter<'a, String, Extern>,
}
impl<'a> ExportsIter<'a> {
fn new(iter: btree_map::Iter<'a, String, Extern>) -> Self {
Self { iter }
}
fn convert_item((name, export): (&'a String, &'a Extern)) -> (&'a str, &'a Extern) {
(name.as_str(), export)
}
}
impl<'a> Iterator for ExportsIter<'a> {
type Item = (&'a str, &'a Extern);
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(Self::convert_item)
}
}
impl DoubleEndedIterator for ExportsIter<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back().map(Self::convert_item)
}
}
impl ExactSizeIterator for ExportsIter<'_> {
fn len(&self) -> usize {
self.iter.len()
}
}
impl FusedIterator for ExportsIter<'_> {}
#[derive(Debug)]
pub struct InstanceEntityBuilder {
instance: InstanceEntity,
}
impl InstanceEntityBuilder {
pub(crate) fn push_memory(&mut self, memory: Memory) {
self.instance.memories.push(memory);
}
pub(crate) fn push_table(&mut self, table: Table) {
self.instance.tables.push(table);
}
pub(crate) fn push_global(&mut self, global: Global) {
self.instance.globals.push(global);
}
pub(crate) fn push_func(&mut self, func: Func) {
self.instance.funcs.push(func);
}
pub(crate) fn push_func_type(&mut self, func_type: DedupFuncType) {
self.instance.func_types.push(func_type);
}
pub(crate) fn push_export(&mut self, name: &str, new_value: Extern) {
if let Some(old_value) = self.instance.exports.get(name) {
panic!(
"tried to register {:?} for name {} but name is already used by {:?}",
new_value, name, old_value,
)
}
self.instance.exports.insert(name.to_string(), new_value);
}
pub(crate) fn finish(mut self) -> InstanceEntity {
self.instance.initialized = true;
self.instance
}
}
impl Deref for InstanceEntityBuilder {
type Target = InstanceEntity;
fn deref(&self) -> &Self::Target {
&self.instance
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(transparent)]
pub struct Instance(Stored<InstanceIdx>);
impl Instance {
pub(super) fn from_inner(stored: Stored<InstanceIdx>) -> Self {
Self(stored)
}
pub(super) fn into_inner(self) -> Stored<InstanceIdx> {
self.0
}
pub(crate) fn get_memory(&self, store: impl AsContext, index: u32) -> Option<Memory> {
store
.as_context()
.store
.resolve_instance(*self)
.get_memory(index)
}
pub(crate) fn get_table(&self, store: impl AsContext, index: u32) -> Option<Table> {
store
.as_context()
.store
.resolve_instance(*self)
.get_table(index)
}
pub(crate) fn get_global(&self, store: impl AsContext, index: u32) -> Option<Global> {
store
.as_context()
.store
.resolve_instance(*self)
.get_global(index)
}
pub(crate) fn get_func(&self, store: impl AsContext, index: u32) -> Option<Func> {
store
.as_context()
.store
.resolve_instance(*self)
.get_func(index)
}
pub(crate) fn get_signature(&self, store: impl AsContext, index: u32) -> Option<DedupFuncType> {
store
.as_context()
.store
.resolve_instance(*self)
.get_signature(index)
}
pub fn get_export(&self, store: impl AsContext, name: &str) -> Option<Extern> {
store
.as_context()
.store
.resolve_instance(*self)
.get_export(name)
}
pub fn exports<'a, T: 'a>(&self, store: impl Into<StoreContext<'a, T>>) -> ExportsIter<'a> {
store.into().store.resolve_instance(*self).exports()
}
}