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
4 changes: 2 additions & 2 deletions turing/benches/lua_api_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ extern "C" fn fetch_string(
fn setup_turing_for_lua() -> Turing<DirectExt> {
let mut turing = Turing::new();

let mut meta = ScriptFnMetadata::new(Some("test".to_owned()), log_info_wasm, None);
let mut meta = ScriptFnMetadata::new("test".to_owned(), log_info_wasm, None);
let _ = meta.add_param_type(DataType::RustString, "msg");
turing.add_function("Log.info", meta).unwrap();

let mut meta = ScriptFnMetadata::new(Some("test".to_owned()), fetch_string, None);
let mut meta = ScriptFnMetadata::new("test".to_owned(), fetch_string, None);
let _ = meta.add_return_type(DataType::ExtString);
turing.add_function("fetch_string", meta).unwrap();

Expand Down
4 changes: 2 additions & 2 deletions turing/benches/wasm_api_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ extern "C" fn fetch_string(_params: FfiParamArray) -> FfiParam {
fn setup_turing_with_callbacks() -> Turing<DirectExt> {
let mut turing = Turing::new();

let mut meta = ScriptFnMetadata::new(Some("test".to_owned()), log_info_wasm, None);
let mut meta = ScriptFnMetadata::new("test".to_owned(), log_info_wasm, None);
let _ = meta.add_param_type(DataType::RustString, "msg");
turing.add_function("log_info", meta).unwrap();

let mut meta = ScriptFnMetadata::new(Some("test".to_owned()), fetch_string, None);
let mut meta = ScriptFnMetadata::new("test".to_owned(), fetch_string, None);
let _ = meta.add_return_type(DataType::ExtString);
turing.add_function("fetch_string", meta).unwrap();

Expand Down
8 changes: 4 additions & 4 deletions turing/src/engine/lua_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,13 +212,13 @@ impl<Ext: ExternalFunctions> LuaInterpreter<Ext> {
fn generate_function(&self, lua: &Lua, table: &Table, name: &str, metadata: &ScriptFnMetadata) -> Result<()> {
let cap = metadata.capability.clone();
let callback = metadata.callback;
let pts = metadata.param_types.clone();
let pts = metadata.param_types.iter().map(|d| d.data_type).collect::<Vec<_>>();
let data = Arc::clone(&self.data);


let func = lua.create_function(move |lua, args: LuaVariadic<Value>| -> mlua::Result<Value> {
lua_bind_env::<Ext>(
&data, lua, cap.as_deref(), &args, pts.as_slice(), &callback
&data, lua, &cap, &args, &pts, &callback
)
}).map_err(|e| anyhow!("Failed to create function: {e}"))?;

Expand Down Expand Up @@ -446,13 +446,13 @@ impl<Ext: ExternalFunctions> LuaInterpreter<Ext> {
fn lua_bind_env<Ext: ExternalFunctions>(
data: &Arc<RwLock<EngineDataState>>,
lua: &Lua,
cap: Option<&str>,
cap: &str,
ps: &LuaVariadic<Value>,
p: &[DataType],
func: &ScriptCallback,
) -> mlua::Result<Value> {

if let Some(cap) = cap && !data.read().active_capabilities.contains(cap) {
if !data.read().active_capabilities.contains(cap) {
return Err(mlua::Error::RuntimeError(format!("Mod capability '{cap}' is not currently loaded")))
}

Expand Down
86 changes: 55 additions & 31 deletions turing/src/engine/types.rs
Original file line number Diff line number Diff line change
@@ -1,76 +1,97 @@
use anyhow::anyhow;
use crate::interop::params::{DataType, FfiParam, FfiParamArray};
use anyhow::anyhow;

pub type ScriptCallback = extern "C" fn(FfiParamArray) -> FfiParam;

#[derive(Clone)]
pub struct ScriptFnParameter {
pub name: String,
pub data_type: DataType,
pub data_type_name: String,
}

#[derive(Clone)]
pub struct ScriptFnMetadata {
pub capability: Option<String>,
pub capability: String,
pub callback: ScriptCallback,
pub param_types: Vec<DataType>,
pub param_type_names: Vec<(String, String)>,
pub return_type: Vec<DataType>,
pub return_type_names: Vec<String>,
pub param_types: Vec<ScriptFnParameter>,
pub return_type: Vec<(DataType, String)>,
pub doc_comment: Option<String>,
}

impl ScriptFnMetadata {
pub fn new(capability: Option<String>, callback: ScriptCallback, doc_comment: Option<String>) -> Self {
pub fn new(
capability: String,
callback: ScriptCallback,
doc_comment: Option<String>,
) -> Self {
Self {
capability,
callback,
param_types: Vec::new(),
param_type_names: Vec::new(),
return_type: Vec::new(),
return_type_names: Vec::new(),
doc_comment,
}
}

/// May error if DataType is not a valid parameter type
pub fn add_param_type(&mut self, p: DataType, param_name: impl ToString) -> anyhow::Result<&mut Self> {
if !p.is_valid_param_type() {
return Err(anyhow!("DataType '{}' is not a valid parameter type", p))
}
self.param_types.push(p);
self.param_type_names.push((param_name.to_string(), p.as_spec_param_type()?.to_string()));
pub fn add_param_type(
&mut self,
p: DataType,
param_name: impl ToString,
) -> anyhow::Result<&mut Self> {
if !p.is_valid_param_type() {
return Err(anyhow!("DataType '{}' is not a valid parameter type", p));
}
self.param_types.push(ScriptFnParameter {
name: param_name.to_string(),
data_type: p,
data_type_name: p.as_spec_param_type()?.to_string(),
});

Ok(self)
}

/// May error if DataType is not a valid parameter type
pub fn add_param_type_named(&mut self, p: DataType, param_name: String, type_name: String) -> anyhow::Result<&mut Self> {
pub fn add_param_type_named(
&mut self,
p: DataType,
param_name: String,
type_name: String,
) -> anyhow::Result<&mut Self> {
if !p.is_valid_param_type() {
return Err(anyhow!("DataType '{}' is not a valid parameter type", p))
return Err(anyhow!("DataType '{}' is not a valid parameter type", p));
}
self.param_types.push(p);
self.param_type_names.push((param_name, type_name));
self.param_types.push(ScriptFnParameter {
name: param_name,
data_type: p,
data_type_name: type_name,
});

Ok(self)
}

/// May error if DataType is not a valid return type
pub fn add_return_type(&mut self, r: DataType) -> anyhow::Result<&mut Self> {
if !r.is_valid_return_type() {
return Err(anyhow!("DataType '{}' is not a valid return type", r))
return Err(anyhow!("DataType '{}' is not a valid return type", r));
}
self.return_type.push(r);
self.return_type_names.push(r.as_spec_return_type()?.to_string());
self.return_type.push((r, r.as_spec_return_type()?.to_string()));
Ok(self)
}

/// May error if DataType is not a valid return type
pub fn add_return_type_named(&mut self, r: DataType, type_name: String) -> anyhow::Result<&mut Self> {
pub fn add_return_type_named(
&mut self,
r: DataType,
type_name: String,
) -> anyhow::Result<&mut Self> {
if !r.is_valid_return_type() {
return Err(anyhow!("DataType '{}' is not a valid return type", r))
return Err(anyhow!("DataType '{}' is not a valid return type", r));
}
self.return_type.push(r);
self.return_type_names.push(type_name);
self.return_type.push((r, type_name));
Ok(self)
}


}

impl DataType {
Expand All @@ -89,7 +110,9 @@ impl DataType {
DataType::Bool => "bool",
DataType::RustString | DataType::ExtString => "&str",
DataType::Object => return Err(anyhow!("Cannot derive type name from 'Object'")),
DataType::RustError | DataType::ExtError => return Err(anyhow!("Error is not a valid param type")),
DataType::RustError | DataType::ExtError => {
return Err(anyhow!("Error is not a valid param type"));
}
DataType::Void => return Err(anyhow!("Void is not a valid param type")),
DataType::Vec2 => "Vec2",
DataType::Vec3 => "Vec3",
Expand All @@ -114,7 +137,9 @@ impl DataType {
DataType::Bool => "bool",
DataType::RustString | DataType::ExtString => "String",
DataType::Object => return Err(anyhow!("Cannot derive type name from 'Object'")),
DataType::RustError | DataType::ExtError => return Err(anyhow!("Error is not a valid param type")),
DataType::RustError | DataType::ExtError => {
return Err(anyhow!("Error is not a valid param type"));
}
DataType::Void => "void",
DataType::Vec2 => "Vec2",
DataType::Vec3 => "Vec3",
Expand All @@ -124,4 +149,3 @@ impl DataType {
})
}
}

18 changes: 7 additions & 11 deletions turing/src/engine/wasm_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -615,26 +615,26 @@ impl<Ext: ExternalFunctions + Send + Sync + 'static> WasmInterpreter<Ext> {
let mut name = name.replace(":", "_").replace(".", "_").to_case(Case::Snake);
name.insert(0, '_');

let p_types = metadata.param_types.iter().map(|d| d.to_val_type()).collect::<Result<Vec<ValType>>>()?;
let p_types = metadata.param_types.iter().map(|d| d.data_type.to_val_type()).collect::<Result<Vec<ValType>>>()?;

// if the only return type is void, we treat it as no return types
let r_types = if metadata.return_type.len() == 1 && metadata.return_type.first().cloned() == Some(DataType::Void) {
let r_types = if metadata.return_type.len() == 1 && metadata.return_type.first().cloned().map(|r| r.0) == Some(DataType::Void) {
Vec::new()
} else {
metadata.return_type.iter().map(|d| d.to_val_type()).collect::<Result<Vec<ValType>>>()?
metadata.return_type.iter().map(|d| d.0.to_val_type()).collect::<Result<Vec<ValType>>>()?
};
let ft = FuncType::new(engine, p_types, r_types);
let cap = metadata.capability.clone();
let callback = metadata.callback;
let pts = metadata.param_types.clone();
let pts = metadata.param_types.iter().map(|d| d.data_type).collect::<Vec<DataType>>();

let data2 = Arc::clone(&data);
linker.func_new(
"env",
name.as_str(),
ft,
move |caller, ps, rs| {
wasm_bind_env::<Ext>(&data2, caller, cap.as_deref(), ps, rs, pts.as_slice(), &callback)
wasm_bind_env::<Ext>(&data2, caller, &cap, ps, rs, pts.as_slice(), &callback)
}
)?;

Expand Down Expand Up @@ -709,10 +709,6 @@ impl<Ext: ExternalFunctions + Send + Sync + 'static> WasmInterpreter<Ext> {
ret_type: DataType,
data: &Arc<RwLock<EngineDataState>>,
) -> Param {
let Some(instance) = &mut self.script_instance else {
return Param::Error("No script is loaded or reentry was attempted".to_string());
};

// Fast-path: typed cache (common signatures). Falls back to dynamic call below.
if let Some(entry) = self.typed_cache.get(&cache_key) {
return entry.invoke(&mut self.store, params).unwrap_or_else(Param::Error)
Expand Down Expand Up @@ -787,14 +783,14 @@ impl<Ext: ExternalFunctions + Send + Sync + 'static> WasmInterpreter<Ext> {
fn wasm_bind_env<Ext: ExternalFunctions>(
data: &Arc<RwLock<EngineDataState>>,
mut caller: Caller<'_, WasiP1Ctx>,
cap: Option<&str>,
cap: &str,
ps: &[Val],
rs: &mut [Val],
p: &[DataType],
func: &ScriptCallback,
) -> Result<()> {

if let Some(cap) = cap && !data.read().active_capabilities.contains(cap) {
if !data.read().active_capabilities.contains(cap) {
return Err(anyhow!("Mod capability '{}' is not currently loaded", cap))
}

Expand Down
55 changes: 27 additions & 28 deletions turing/src/global_ffi/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,12 @@ unsafe extern "C" fn turing_create_script_data(
callback: ScriptCallback,
doc_comment: *const c_char,
) -> *mut ScriptFnMetadata {
if capability.is_null() {
panic!("turing_create_script_data(): capability must be a valid string pointer, null is not allowed");
}

let cap = unsafe {
capability
.as_ref()
.map(|s| CStr::from_ptr(s))
.map(|s| s.to_string_lossy())
.map(|s| s.to_string())
CStr::from_ptr(capability).to_string_lossy().to_string()
};

let doc = if doc_comment.is_null() {
Expand All @@ -150,30 +150,29 @@ unsafe extern "C" fn turing_create_script_data(
unsafe extern "C" fn turing_script_data_add_param_type(data: *mut ScriptFnMetadata, params: *mut DataType, param_names: *mut *const c_char, param_type_names: *mut *const c_char, params_count: u32) -> *const c_char {
let data = unsafe { &mut *data };
let array = unsafe { slice::from_raw_parts(params, params_count as usize) };
let param_names = unsafe { slice::from_raw_parts(param_names, params_count as usize) }
.iter()
.map(
|ptr| unsafe { CStr::from_ptr(*ptr) }.to_string_lossy().into_owned()
)
.collect::<Vec<String>>();
let param_type_names = unsafe { slice::from_raw_parts(param_type_names, params_count as usize) }
.iter()
.map(
|ptr| if ptr.is_null() { None } else { Some(unsafe { CStr::from_ptr(*ptr) }.to_string_lossy().into_owned()) }
)
.collect::<Vec<Option<String>>>();

for ((ty, name), ty_name) in array.iter().zip(param_names).zip(param_type_names) {
if let Some(ty_name) = ty_name {
if let Err(e) = data.add_param_type_named(*ty, name, ty_name) {
return CString::new(format!("{}", e)).unwrap().into_raw()
}
} else {
if let Err(e) = data.add_param_type(*ty, name) {
return CString::new(format!("{}", e)).unwrap().into_raw()
}
}
let names = unsafe { slice::from_raw_parts(param_names, params_count as usize) };
let type_names = unsafe { slice::from_raw_parts(param_type_names, params_count as usize) };

for i in 0..(params_count as usize) {
let ty = array[i];
let name = unsafe { CStr::from_ptr(names[i]) }.to_string_lossy().into_owned();

let ty_ptr = type_names[i];
match ty_ptr.is_null() {
true => {
if let Err(e) = data.add_param_type(ty, name) {
return CString::new(format!("{}", e)).unwrap().into_raw()
}
},
false => {
let ty_name = unsafe { CStr::from_ptr(ty_ptr) }.to_string_lossy().into_owned();
if let Err(e) = data.add_param_type_named(ty, name, ty_name) {
return CString::new(format!("{}", e)).unwrap().into_raw()
}
},
};
}

ptr::null()
}

Expand Down
14 changes: 14 additions & 0 deletions turing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ new_key_type! {
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct ScriptFnKey(u32);

impl ScriptFnKey {
pub fn new(id: u32) -> Self {
Self(id)
}

pub fn is_valid(&self) -> bool {
self.0 != u32::MAX
}
}

impl From<u32> for ScriptFnKey {
fn from(value: u32) -> Self {
ScriptFnKey(value)
Expand Down Expand Up @@ -231,6 +241,10 @@ impl<Ext: ExternalFunctions + Send + Sync + 'static> Turing<Ext> {
return Param::Error("No code engine is active".to_string())
};

if !cache_key.is_valid() {
return Param::Error("Invalid function key".to_string());
}

engine.call_fn(
cache_key,
params,
Expand Down
Loading
Loading