wasmi 2.0.0-beta.2

WebAssembly interpreter
Documentation
use crate::{
    engine::executor::{Cell, CellError, LiftFromCells, LiftFromCellsByValue, LowerToCells},
    store::AsStoreId,
};
use core::cmp::max;

/// Wrapper around a slice of [`Cell`]s to manage reading parameters and writing results of a function call.
#[derive(Debug)]
pub struct InOutParams<'cells> {
    /// The underlying slice of cells used for both parameters and results.
    cells: &'cells mut [Cell],
    /// The number of cells used for parameters.
    ///
    /// # Note
    ///
    /// Must be less than or equal to the length of `cells`.
    len_params: usize,
    /// The number of cells used for results.
    ///
    /// # Note
    ///
    /// Must be less than or equal to the length of `cells`.
    len_results: usize,
}

impl<'cells> InOutParams<'cells> {
    /// Creates a new [`InOutParams`] from the given parts.
    ///
    /// # Errors
    ///
    /// If max(len_params, len_results) is not equal to `cells.len()`.
    pub fn new(
        cells: &'cells mut [Cell],
        len_params: usize,
        len_results: usize,
    ) -> Result<Self, CellError> {
        let required_cells = max(len_params, len_results);
        if required_cells < cells.len() {
            return Err(CellError::NotEnoughValues);
        }
        if required_cells > cells.len() {
            return Err(CellError::NotEnoughCells);
        }
        Ok(Self {
            cells,
            len_params,
            len_results,
        })
    }

    /// Returns the slice of [`Cell`] parameters.
    pub fn params(&self) -> &[Cell] {
        &self.cells[..self.len_params]
    }

    /// Decodes the parameter slice of [`Cell`]s into `T` if possible.
    ///
    /// Returns a [`CellError`], otherwise.
    pub fn decode_params_into<T>(&self, store: impl AsStoreId, out: T) -> Result<(), CellError>
    where
        T: LiftFromCells<Value = ()>,
    {
        out.lift_from_cells(store, &mut self.params())
    }

    /// Decodes the parameter slice of [`Cell`]s into `T` if possible.
    ///
    /// Returns a [`CellError`], otherwise.
    pub fn decode_params<T>(&self, store: impl AsStoreId) -> Result<T, CellError>
    where
        T: LiftFromCellsByValue,
    {
        <T as LiftFromCellsByValue>::lift_from_cells_by_value(store, &mut self.params())
    }

    /// Encodes the `results` of type `T` into the result [`Cell`]s if possible.
    ///
    /// Returns a [`CellError`], otherwise.
    pub fn encode_results<T>(
        self,
        store: impl AsStoreId,
        results: T,
    ) -> Result<InOutResults<'cells>, CellError>
    where
        T: LowerToCells,
    {
        let mut cells = &mut self.cells[..self.len_results];
        results.lower_to_cells(store, &mut cells)?;
        Ok(InOutResults { cells })
    }
}

/// The result [`Cell`]s of a (host) function invocation.
#[derive(Debug)]
pub struct InOutResults<'cells> {
    /// The underlying [`Cell`]s representing the encoded results.
    cells: &'cells mut [Cell],
}

impl<'cells> InOutResults<'cells> {
    /// Returns the slice of [`Cell`] results.
    pub fn results(&self) -> &[Cell] {
        self.cells
    }
}