diff --git a/turing/src/global_ffi/ffi.rs b/turing/src/global_ffi/ffi.rs index 717ad94..7745217 100644 --- a/turing/src/global_ffi/ffi.rs +++ b/turing/src/global_ffi/ffi.rs @@ -8,13 +8,13 @@ use anyhow::{anyhow, Result}; use rustc_hash::FxHashMap; use crate::interop::params::{DataType, FfiParam, FreeableDataType, Param, Params}; use crate::interop::types::Semver; -use crate::{Turing, panic_hook}; +use crate::{Turing, panic_hook, spec_gen}; use crate::engine::types::{ScriptCallback, ScriptFnMetadata}; use crate::global_ffi::wrappers::*; pub type ScriptFnMap = FxHashMap; pub type TuringInstance = Turing; -pub type TuringInit = Result>; +pub type TuringInitResult = Result>; pub type VersionTable = Vec<(String, Semver)>; pub type CacheKey = u32; @@ -181,9 +181,14 @@ unsafe extern "C" fn turing_script_data_add_param_type(data: *mut ScriptFnMetada /// `data` must be a valid pointer to a `ScriptFnMetadata`. /// Returns a pointer to an error message, if the pointer is null then no error occurred. Caller is responsible for freeing this string. /// none of the passed data is freed. -unsafe extern "C" fn turing_script_data_set_return_type(data: *mut ScriptFnMetadata, return_type: DataType) -> *const c_char { +unsafe extern "C" fn turing_script_data_set_return_type(data: *mut ScriptFnMetadata, return_type: DataType, type_names: *const c_char) -> *const c_char { let data = unsafe { &mut *data }; - if let Err(e) = data.add_return_type(return_type) { + let return_type_name = unsafe { type_names.as_ref().map(|ptr| CStr::from_ptr(ptr).to_string_lossy().into_owned() ) }; + + if let Err(e) = match return_type_name { + Some(name) => data.add_return_type_named(return_type, name), + None => data.add_return_type(return_type), + } { return CString::new(format!("{}", e)).unwrap().into_raw() } ptr::null() @@ -292,12 +297,16 @@ unsafe extern "C" fn turing_script_fast_call_fixed_update(turing: *mut TuringIns /// /// The caller is responsible for freeing the returned error string if not null #[unsafe(no_mangle)] -unsafe extern "C" fn turing_script_dump_sec(turing: *mut TuringInstance, out_dir: *const c_char) -> *const c_char { - let turing = unsafe { &mut *turing }; +unsafe extern "C" fn turing_script_dump_sec(out_dir: *const c_char, wasm_fns_ptr: *mut ScriptFnMap, versions: *mut VersionTable) -> *const c_char { + let map = unsafe { &*wasm_fns_ptr }; + let versions = unsafe { &*versions }; + + let versions_map = versions.clone().into_iter().collect(); + let out = unsafe { CStr::from_ptr(out_dir).to_string_lossy().into_owned() }; let out = std::path::Path::new(&out); - match turing.generate_specs(out) { + match spec_gen::generator::generate_specs(map, &versions_map, out) { Ok(_) => ptr::null(), Err(e) => CString::new(format!("{}", e)).unwrap().into_raw(), } @@ -307,7 +316,7 @@ unsafe extern "C" fn turing_script_dump_sec(turing: *mut TuringInstance, out_dir /// # Safety /// `wasm_fns_ptr` must be a valid pointer to a `HashMap`. /// `wasm_fns_ptr` will be freed during this function and must no longer be used. -unsafe extern "C" fn turing_create_instance(wasm_fns_ptr: *mut ScriptFnMap) -> *mut TuringInit { +unsafe extern "C" fn turing_create_instance(wasm_fns_ptr: *mut ScriptFnMap) -> *mut TuringInitResult { let map = unsafe { Box::from_raw(wasm_fns_ptr) }; let mut turing = Turing::new(); turing.script_fns = *map; @@ -320,7 +329,7 @@ unsafe extern "C" fn turing_create_instance(wasm_fns_ptr: *mut ScriptFnMap) -> * /// # Safety /// `res_ptr` must be a valid pointer to a `Result`. /// the caller is responsible for freeing the returned string if not null. -unsafe extern "C" fn turing_instance_check_error(res_ptr: *mut TuringInit) -> *const c_char { +unsafe extern "C" fn turing_instance_check_error(res_ptr: *mut TuringInitResult) -> *const c_char { let res = unsafe { &*res_ptr }; if let Err(e) = res { @@ -336,7 +345,7 @@ unsafe extern "C" fn turing_instance_check_error(res_ptr: *mut TuringInit) -> *c /// `res_ptr` must have been checked with `check_error` and handled if an error was returned. /// If `res_ptr` points to an `Err` value, this function will abort the process. /// `res_ptr` will be freed during this function and must no longer be used. -unsafe extern "C" fn turing_instance_unwrap(res_ptr: *mut TuringInit) -> *mut TuringInstance { +unsafe extern "C" fn turing_instance_unwrap(res_ptr: *mut TuringInitResult) -> *mut TuringInstance { let res = unsafe { *Box::from_raw(res_ptr) }; let Ok(turing) = res else { @@ -364,6 +373,18 @@ extern "C" fn turing_create_params(size: u32) -> *mut Params { })) } +#[unsafe(no_mangle)] +extern "C" fn turing_params_get_size(params: *mut Params) -> u32 { + let params = unsafe { &*params }; + params.len() +} + +#[unsafe(no_mangle)] +extern "C" fn turing_params_clear(params: *mut Params) { + let params = unsafe { &mut *params }; + params.clear(); +} + #[unsafe(no_mangle)] /// # Safety /// `params` must be a valid pointer to a `Params`. @@ -407,35 +428,21 @@ extern "C" fn turing_delete_param(param: FfiParam) { /// The returned table may be null if no engine is active or no script is loaded. unsafe extern "C" fn turing_versions_get(turing: *mut TuringInstance) -> *mut VersionTable { let turing = unsafe { &*turing }; - if let Some(versions) = turing.get_api_versions() { - let versions: VersionTable = versions.iter().map(|(n, v)| (n.clone(), *v)).collect(); - let versions = Box::new(versions.clone()); - Box::into_raw(versions) - } else { - ptr::null::() as *mut _ - } - -} -#[unsafe(no_mangle)] -/// Creates a new VersionTable and returns a pointer to it. You must free this with `turing_delete_versions` -extern "C" fn turing_versions_create() -> *mut VersionTable { - let versions: VersionTable = Vec::new(); + let Some(versions) = turing.get_api_versions() else { + return ptr::null::() as *mut _; + }; + + let versions: VersionTable = versions.iter().map(|(n, v)| (n.clone(), *v)).collect(); let versions = Box::new(versions.clone()); Box::into_raw(versions) } #[unsafe(no_mangle)] -/// # Safety -/// `turing` must be a valid pointer to a `Turing`. -/// `versions` must be a valid pointer to a `VersionTable`. Note: the versions table is not freed and can continue to be modified independently of what this turing instance has. -unsafe extern "C" fn turing_versions_set(turing: *mut TuringInstance, versions: *mut VersionTable) { - let turing = unsafe { &mut *turing }; - let versions = unsafe { &*versions }; - - for (name, version) in versions { - turing.register_api_version(name, *version); - } - +/// Creates a new VersionTable and returns a pointer to it. You must free this with `turing_delete_versions` +extern "C" fn turing_versions_create() -> *mut VersionTable { + let versions: VersionTable = Default::default(); + let versions = Box::new(versions); + Box::into_raw(versions) } #[unsafe(no_mangle)] diff --git a/turing/src/lib.rs b/turing/src/lib.rs index adc687f..7a108ad 100644 --- a/turing/src/lib.rs +++ b/turing/src/lib.rs @@ -103,7 +103,6 @@ pub struct Turing { pub engine: Option>, pub data: Arc>, pub script_fns: FxHashMap, - pub available_capabilities: HashMap, _ext: PhantomData } @@ -146,21 +145,22 @@ impl Turing { engine: None, script_fns, data, - available_capabilities: HashMap::new(), _ext: PhantomData, } } - /// Calling this is only required for the spec generator to work correctly. - pub fn register_api_version(&mut self, name: impl ToString, version: Semver) { - self.available_capabilities.insert(name.to_string(), version); + /// Enables a capability for the currently loaded script + pub fn register_capability(&mut self, name: impl ToString) { + self.data.write().active_capabilities.insert(name.to_string()); } - - /// This is a dev function for generating the spec files used to generate binding files, not meant to be called in production. - pub fn generate_specs(&self, output_directory: &Path) -> Result<()> { - generate_specs(&self.script_fns, &self.available_capabilities, output_directory) + + /// Disables a capability for the currently loaded script + pub fn unregister_capability(&mut self, name: impl AsRef) { + self.data.write().active_capabilities.remove(name.as_ref()); } + + pub fn load_script( &mut self, source: impl ToString, diff --git a/turing/src/spec_gen/generator.rs b/turing/src/spec_gen/generator.rs index 1f612ce..6052af6 100644 --- a/turing/src/spec_gen/generator.rs +++ b/turing/src/spec_gen/generator.rs @@ -11,7 +11,7 @@ use crate::interop::types::Semver; /// This places txt files in the `output_folder` titled as `.txt` pub fn generate_specs( metadata: &FxHashMap, - api_versions: &HashMap, + api_versions: &FxHashMap, output_directory: &Path, ) -> Result<()> {