tinywasm 0.11.0-beta.0

A tiny WebAssembly interpreter
Documentation
use alloc::vec::Vec;
use tinywasm_types::{Shared, WeakShared};

use crate::Trap;
use crate::interpreter::ValueRef;

pub(crate) struct Roots {
    entries: Vec<Option<Root>>,
    free: Vec<u32>,
}

struct Root {
    value: ValueRef,
    token: WeakShared<()>,
}

impl Roots {
    pub(crate) const fn new() -> Self {
        Self { entries: Vec::new(), free: Vec::new() }
    }

    pub(crate) fn reserve(&mut self, additional: usize) -> Result<(), Trap> {
        self.remove_dead();
        let needed = additional.saturating_sub(self.free.len());
        self.entries.try_reserve(needed).map_err(|_| Trap::OutOfMemory)
    }

    pub(crate) fn insert(&mut self, value: ValueRef) -> Result<Shared<()>, Trap> {
        if self.free.is_empty() && self.entries.len() == self.entries.capacity() {
            self.remove_dead();
        }
        let index = if let Some(index) = self.free.pop() {
            index
        } else {
            let index = u32::try_from(self.entries.len()).map_err(|_| Trap::OutOfMemory)?;
            self.entries.try_reserve(1).map_err(|_| Trap::OutOfMemory)?;
            self.entries.push(None);
            index
        };

        let token = Shared::new(());
        self.entries[index as usize] = Some(Root { value, token: Shared::downgrade(&token) });
        Ok(token)
    }

    pub(crate) fn values(&mut self) -> impl Iterator<Item = ValueRef> + '_ {
        self.remove_dead();
        self.entries.iter().flatten().map(|root| root.value)
    }

    fn remove_dead(&mut self) {
        for (index, root) in self.entries.iter_mut().enumerate() {
            if root.as_ref().is_some_and(|root| root.token.strong_count() == 0) {
                *root = None;
                self.free.push(index as u32);
            }
        }
    }
}