bevy_mod_ffi_guest 0.2.0

FFI utilities for Bevy guests
Documentation
use super::{ParamBuilder, SystemParam, bevy_guest_run_system};
use crate::{
    system::{IntoSystem, ParamCursor, System, SystemClosure},
    world::World,
};
use bevy_mod_ffi_core::{dyn_system_param, system, system_state};
use bevy_mod_ffi_guest_sys;
use bytemuck::Pod;
use std::{marker::PhantomData, mem, ptr, slice};

pub struct SystemState<P: SystemParam> {
    pub(crate) ptr: *mut system_state,
    pub(crate) state: P::State,
    _marker: PhantomData<fn() -> P>,
}

impl<P: SystemParam + 'static> SystemState<P> {
    pub fn new(world: &mut World) -> Self {
        let mut builder = ParamBuilder::new();
        let state = P::build(world, &mut builder);
        let state_ptr = builder.build(world);

        Self {
            ptr: state_ptr,
            state,
            _marker: PhantomData,
        }
    }

    pub fn get<'w, 's>(&'s mut self, world: &'w mut World) -> P::Item<'w, 's> {
        let mut params_ptr: *mut *mut dyn_system_param = ptr::null_mut();
        let mut params_len: i32 = 0;

        unsafe {
            bevy_mod_ffi_guest_sys::system::state::bevy_system_state_get(
                world.ptr,
                self.ptr,
                &mut params_ptr,
                &mut params_len,
            )
        };

        let params = { unsafe { slice::from_raw_parts(params_ptr, params_len as usize) } };
        let mut cursor = ParamCursor::new(params);
        let out = unsafe { P::get_param(&mut self.state, &mut cursor) };

        unsafe {
            bevy_mod_ffi_guest_sys::system::state::bevy_dyn_system_params_drop(
                params_ptr as *mut dyn_system_param,
            )
        };

        out
    }

    pub fn apply(&mut self, world: &mut World) {
        if !self.ptr.is_null() {
            unsafe {
                bevy_mod_ffi_guest_sys::system::state::bevy_system_state_apply(world.ptr, self.ptr);
            }
        }
    }

    pub fn state(&self) -> &P::State {
        &self.state
    }

    pub fn state_mut(&mut self) -> &mut P::State {
        &mut self.state
    }

    pub fn build<Marker, In, Out, S>(mut self, system: S) -> SystemRef<S::System>
    where
        S: IntoSystem<Marker, In = In, Out = Out>,
        S::System: System<In = In, Out = Out, Param = P> + 'static,
        In: Pod,
        Out: Pod,
    {
        let mut system = system.into_system();
        let state_ptr = self.ptr;

        let output_size = mem::size_of::<Out>();

        let system_boxed: SystemClosure = Box::new(move |params, input_ptr, output_ptr| {
            let mut param_cursor = ParamCursor::new(params);
            let params = unsafe {
                <<S::System as System>::Param as SystemParam>::get_param(
                    &mut self.state,
                    &mut param_cursor,
                )
            };

            let input = unsafe { *(input_ptr as *const In) };
            let output = system.run(input, params);

            let output_bytes = bytemuck::bytes_of(&output);
            unsafe {
                ptr::copy_nonoverlapping(output_bytes.as_ptr(), output_ptr, output_size);
            }
        });

        let mut ptr: *mut system = ptr::null_mut();
        unsafe {
            bevy_mod_ffi_guest_sys::system::state::bevy_system_state_build(
                state_ptr,
                Box::into_raw(Box::new(system_boxed)) as _,
                bevy_guest_run_system,
                &mut ptr,
            )
        }

        SystemRef {
            ptr,
            _marker: PhantomData,
        }
    }
}

impl<P: SystemParam> Drop for SystemState<P> {
    fn drop(&mut self) {
        unsafe { bevy_mod_ffi_guest_sys::system::state::bevy_system_state_drop(self.ptr) };
    }
}

pub struct SystemRef<F> {
    pub(crate) ptr: *mut system,
    _marker: PhantomData<F>,
}

impl<F> SystemRef<F> {}