Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 41 additions & 34 deletions turing/src/global_ffi/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, ScriptFnMetadata>;
pub type TuringInstance = Turing<CsFns>;
pub type TuringInit = Result<Turing<CsFns>>;
pub type TuringInitResult = Result<Turing<CsFns>>;
pub type VersionTable = Vec<(String, Semver)>;
pub type CacheKey = u32;

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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(),
}
Expand All @@ -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<String, ScriptFnMetadata>`.
/// `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;
Expand All @@ -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<Turing>`.
/// 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 {
Expand All @@ -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 {
Expand Down Expand Up @@ -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`.
Expand Down Expand Up @@ -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::<VersionTable>() 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::<VersionTable>() 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)]
Expand Down
18 changes: 9 additions & 9 deletions turing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ pub struct Turing<Ext: ExternalFunctions + Send + Sync + 'static> {
pub engine: Option<Engine<Ext>>,
pub data: Arc<RwLock<EngineDataState>>,
pub script_fns: FxHashMap<String, ScriptFnMetadata>,
pub available_capabilities: HashMap<String, Semver>,
_ext: PhantomData<Ext>
}

Expand Down Expand Up @@ -146,21 +145,22 @@ impl<Ext: ExternalFunctions + Send + Sync + 'static> Turing<Ext> {
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<str>) {
self.data.write().active_capabilities.remove(name.as_ref());
}



pub fn load_script(
&mut self,
source: impl ToString,
Expand Down
2 changes: 1 addition & 1 deletion turing/src/spec_gen/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::interop::types::Semver;
/// This places txt files in the `output_folder` titled as `<capability>.txt`
pub fn generate_specs(
metadata: &FxHashMap<String, ScriptFnMetadata>,
api_versions: &HashMap<String, Semver>,
api_versions: &FxHashMap<String, Semver>,
output_directory: &Path,
) -> Result<()> {

Expand Down
Loading