wasvy 0.0.9

WASI-powered modding for the Bevy engine
Documentation
use anyhow::{Result, bail};
use wasmtime::component::Resource;

use crate::{
    bindings::wasvy::ecs::app::HostQuery,
    host::{WasmHost, WasmQueryResult},
    query::{QueryCursor, QueryId},
    runner::State,
};

pub struct WasmQuery {
    id: QueryId,
    cursor: QueryCursor,
}

impl WasmQuery {
    pub(crate) fn new(id: QueryId) -> Self {
        Self {
            id,
            cursor: QueryCursor::default(),
        }
    }
}

impl HostQuery for WasmHost {
    fn iter(
        &mut self,
        query: Resource<WasmQuery>,
    ) -> std::result::Result<Option<Resource<WasmQueryResult>>, wasmtime::Error> {
        (|| -> Result<_> {
            let State::RunSystem { table, queries, .. } = self.access() else {
                bail!("Query can only be accessed in systems")
            };

            let query = table.get_mut(&query)?;
            let cursor = query.cursor.increment();
            let Some(entity) = cursor.entity(queries, query.id) else {
                // We've reached the end of the results
                return Ok(None);
            };

            let result = WasmQueryResult::new(query.id, entity);
            let result = table.push(result)?;
            Ok(Some(result))
        })()
        .map_err(|err| wasmtime::Error::msg(err.to_string()))
    }

    // Note: this is never guaranteed to be called by the wasi binary
    fn drop(&mut self, query: Resource<WasmQuery>) -> std::result::Result<(), wasmtime::Error> {
        (|| -> Result<()> {
            let _ = self.table().delete(query)?;

            Ok(())
        })()
        .map_err(|err| wasmtime::Error::msg(err.to_string()))
    }
}