#![allow(clippy::missing_safety_doc)]
use std::{os::raw::c_char, ptr::null_mut};
use crate::*;
pub type ExtismMemoryHandle = u64;
pub type Size = u64;
pub struct ExtismFunction(std::cell::Cell<Option<Function>>);
pub static EXTISM_SUCCESS: i32 = 0;
fn make_error_msg(s: String) -> Vec<u8> {
let mut s = s.into_bytes();
s.push(0);
s
}
#[repr(C)]
pub union ValUnion {
i32: i32,
i64: i64,
f32: f32,
f64: f64,
}
#[repr(C)]
pub struct ExtismVal {
t: ValType,
v: ValUnion,
}
pub type ExtismFunctionType = extern "C" fn(
plugin: *mut CurrentPlugin,
inputs: *const ExtismVal,
n_inputs: Size,
outputs: *mut ExtismVal,
n_outputs: Size,
data: *mut std::ffi::c_void,
);
pub type ExtismLogDrainFunctionType = extern "C" fn(data: *const std::ffi::c_char, size: Size);
impl ExtismVal {
fn from_val(value: &wasmtime::Val, ctx: impl AsContext) -> Result<Self, Error> {
match value.ty(ctx)? {
wasmtime::ValType::I32 => Ok(ExtismVal {
t: ValType::I32,
v: ValUnion {
i32: value.unwrap_i32(),
},
}),
wasmtime::ValType::I64 => Ok(ExtismVal {
t: ValType::I64,
v: ValUnion {
i64: value.unwrap_i64(),
},
}),
wasmtime::ValType::F32 => Ok(ExtismVal {
t: ValType::F32,
v: ValUnion {
f32: value.unwrap_f32(),
},
}),
wasmtime::ValType::F64 => Ok(ExtismVal {
t: ValType::F64,
v: ValUnion {
f64: value.unwrap_f64(),
},
}),
t => todo!("{}", t),
}
}
}
#[no_mangle]
pub unsafe extern "C" fn extism_plugin_id(plugin: *mut Plugin) -> *const u8 {
if plugin.is_null() {
return std::ptr::null_mut();
}
let plugin = &mut *plugin;
plugin.id.as_bytes().as_ptr()
}
#[no_mangle]
pub unsafe extern "C" fn extism_current_plugin_host_context(
plugin: *mut CurrentPlugin,
) -> *mut std::ffi::c_void {
if plugin.is_null() {
return std::ptr::null_mut();
}
let plugin = &mut *plugin;
if let Ok(CVoidContainer(ptr)) = plugin.host_context::<CVoidContainer>() {
*ptr
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn extism_current_plugin_memory(plugin: *mut CurrentPlugin) -> *mut u8 {
if plugin.is_null() {
return std::ptr::null_mut();
}
let plugin = &mut *plugin;
plugin.memory_ptr()
}
#[no_mangle]
pub unsafe extern "C" fn extism_current_plugin_memory_alloc(
plugin: *mut CurrentPlugin,
n: Size,
) -> ExtismMemoryHandle {
if plugin.is_null() {
return 0;
}
let plugin = &mut *plugin;
match plugin.memory_alloc(n) {
Ok(x) => x.offset(),
Err(_) => 0,
}
}
#[no_mangle]
pub unsafe extern "C" fn extism_current_plugin_memory_length(
plugin: *mut CurrentPlugin,
n: ExtismMemoryHandle,
) -> Size {
if plugin.is_null() {
return 0;
}
let plugin = &mut *plugin;
plugin.memory_length(n).unwrap_or_default()
}
#[no_mangle]
pub unsafe extern "C" fn extism_current_plugin_memory_free(
plugin: *mut CurrentPlugin,
ptr: ExtismMemoryHandle,
) {
if plugin.is_null() {
return;
}
let plugin = &mut *plugin;
if let Some(handle) = plugin.memory_handle(ptr) {
let _ = plugin.memory_free(handle);
}
}
#[no_mangle]
pub unsafe extern "C" fn extism_function_new(
name: *const std::ffi::c_char,
inputs: *const ValType,
n_inputs: Size,
outputs: *const ValType,
n_outputs: Size,
func: ExtismFunctionType,
user_data: *mut std::ffi::c_void,
free_user_data: Option<extern "C" fn(_: *mut std::ffi::c_void)>,
) -> *mut ExtismFunction {
let name = match std::ffi::CStr::from_ptr(name).to_str() {
Ok(x) => x.to_string(),
Err(_) => {
return std::ptr::null_mut();
}
};
let inputs = if inputs.is_null() || n_inputs == 0 {
&[]
} else {
std::slice::from_raw_parts(inputs, n_inputs as usize)
}
.to_vec();
let output_types = if outputs.is_null() || n_outputs == 0 {
&[]
} else {
std::slice::from_raw_parts(outputs, n_outputs as usize)
}
.to_vec();
let user_data: UserData<()> = UserData::new_pointer(user_data, free_user_data);
let f = Function::new(
name,
inputs,
output_types.clone(),
user_data,
move |plugin, inputs, outputs, user_data| {
let store = &*plugin.store;
let inputs: Vec<_> = inputs
.iter()
.map(|x| ExtismVal::from_val(x, store).unwrap())
.collect();
let mut output_tmp: Vec<_> = output_types
.iter()
.map(|t| ExtismVal {
t: t.clone(),
v: ValUnion { i64: 0 },
})
.collect();
let (inputs_ptr, inputs_len) = if inputs.is_empty() {
(core::ptr::null(), 0 as Size)
} else {
(inputs.as_ptr(), inputs.len() as Size)
};
let (output_ptr, output_len) = if output_tmp.is_empty() {
(null_mut(), 0 as Size)
} else {
(output_tmp.as_mut_ptr(), output_tmp.len() as Size)
};
func(
plugin,
inputs_ptr,
inputs_len,
output_ptr,
output_len,
user_data.as_ptr(),
);
for (tmp, out) in output_tmp.iter().zip(outputs.iter_mut()) {
match tmp.t {
ValType::I32 => *out = Val::I32(tmp.v.i32),
ValType::I64 => *out = Val::I64(tmp.v.i64),
ValType::F32 => *out = Val::F32(tmp.v.f32.to_bits()),
ValType::F64 => *out = Val::F64(tmp.v.f64.to_bits()),
_ => todo!(),
}
}
Ok(())
},
);
Box::into_raw(Box::new(ExtismFunction(std::cell::Cell::new(Some(f)))))
}
#[no_mangle]
pub unsafe extern "C" fn extism_function_free(f: *mut ExtismFunction) {
if f.is_null() {
return;
}
drop(Box::from_raw(f))
}
#[no_mangle]
pub unsafe extern "C" fn extism_function_set_namespace(
ptr: *mut ExtismFunction,
namespace: *const std::ffi::c_char,
) {
let namespace = std::ffi::CStr::from_ptr(namespace);
let f = &mut *ptr;
if let Some(x) = f.0.get_mut() {
x.set_namespace(namespace.to_string_lossy().to_string());
} else {
debug!("Trying to set namespace of already registered function")
}
}
#[no_mangle]
pub unsafe extern "C" fn extism_compiled_plugin_new(
wasm: *const u8,
wasm_size: Size,
functions: *mut *const ExtismFunction,
n_functions: Size,
with_wasi: bool,
errmsg: *mut *mut std::ffi::c_char,
) -> *mut CompiledPlugin {
trace!("Call to extism_plugin_new with wasm pointer {:?}", wasm);
let data = std::slice::from_raw_parts(wasm, wasm_size as usize);
let mut builder = PluginBuilder::new(data).with_wasi(with_wasi);
if !functions.is_null() {
let funcs = (0..n_functions)
.map(|i| unsafe { *functions.add(i as usize) })
.map(|ptr| {
if ptr.is_null() {
return Err("Cannot pass null pointer");
}
let ExtismFunction(func) = &*ptr;
let Some(func) = func.take() else {
return Err("Function cannot be registered with multiple different Plugins");
};
Ok(func)
})
.collect::<Result<Vec<_>, _>>()
.unwrap_or_else(|e| {
if !errmsg.is_null() {
let e = std::ffi::CString::new(e.to_string()).unwrap();
*errmsg = e.into_raw();
}
Vec::new()
});
if funcs.len() != n_functions as usize {
return std::ptr::null_mut();
}
builder = builder.with_functions(funcs);
}
CompiledPlugin::new(builder)
.map(|v| Box::into_raw(Box::new(v)))
.unwrap_or_else(|e| {
if !errmsg.is_null() {
let e = std::ffi::CString::new(format!(
"Unable to compile Extism plugin: {}",
e.root_cause(),
))
.unwrap();
*errmsg = e.into_raw();
}
std::ptr::null_mut()
})
}
#[no_mangle]
pub unsafe extern "C" fn extism_compiled_plugin_new_with_fuel_limit(
wasm: *const u8,
wasm_size: Size,
functions: *mut *const ExtismFunction,
n_functions: Size,
with_wasi: bool,
fuel_limit: u64,
errmsg: *mut *mut std::ffi::c_char,
) -> *mut CompiledPlugin {
trace!("Call to extism_plugin_new with wasm pointer {:?}", wasm);
let data = std::slice::from_raw_parts(wasm, wasm_size as usize);
let mut builder = PluginBuilder::new(data)
.with_wasi(with_wasi)
.with_fuel_limit(fuel_limit);
if !functions.is_null() {
let funcs = (0..n_functions)
.map(|i| unsafe { *functions.add(i as usize) })
.map(|ptr| {
if ptr.is_null() {
return Err("Cannot pass null pointer");
}
let ExtismFunction(func) = &*ptr;
let Some(func) = func.take() else {
return Err("Function cannot be registered with multiple different Plugins");
};
Ok(func)
})
.collect::<Result<Vec<_>, _>>()
.unwrap_or_else(|e| {
if !errmsg.is_null() {
let e = std::ffi::CString::new(e.to_string()).unwrap();
*errmsg = e.into_raw();
}
Vec::new()
});
if funcs.len() != n_functions as usize {
return std::ptr::null_mut();
}
builder = builder.with_functions(funcs);
}
CompiledPlugin::new(builder)
.map(|v| Box::into_raw(Box::new(v)))
.unwrap_or_else(|e| {
if !errmsg.is_null() {
let e = std::ffi::CString::new(format!(
"Unable to compile Extism plugin: {}",
e.root_cause(),
))
.unwrap();
*errmsg = e.into_raw();
}
std::ptr::null_mut()
})
}
#[no_mangle]
pub unsafe extern "C" fn extism_compiled_plugin_free(plugin: *mut CompiledPlugin) {
if plugin.is_null() {
return;
}
let plugin = Box::from_raw(plugin);
trace!("called extism_compiled_plugin_free");
drop(plugin)
}
#[no_mangle]
pub unsafe extern "C" fn extism_plugin_new(
wasm: *const u8,
wasm_size: Size,
functions: *mut *const ExtismFunction,
n_functions: Size,
with_wasi: bool,
errmsg: *mut *mut std::ffi::c_char,
) -> *mut Plugin {
let data = std::slice::from_raw_parts(wasm, wasm_size as usize);
let funcs = if functions.is_null() {
vec![]
} else {
let funcs = (0..n_functions)
.map(|i| unsafe { *functions.add(i as usize) })
.map(|ptr| {
if ptr.is_null() {
return Err("Cannot pass null pointer");
}
let ExtismFunction(func) = &*ptr;
let Some(func) = func.take() else {
return Err("Function cannot be registered with multiple different Plugins");
};
Ok(func)
})
.collect::<Result<Vec<_>, _>>()
.unwrap_or_else(|e| {
if !errmsg.is_null() {
let e = std::ffi::CString::new(e.to_string()).unwrap();
*errmsg = e.into_raw();
}
Vec::new()
});
if funcs.len() != n_functions as usize {
return std::ptr::null_mut();
}
funcs
};
Plugin::new(data, funcs, with_wasi)
.map(|v| Box::into_raw(Box::new(v)))
.unwrap_or_else(|e| {
if !errmsg.is_null() {
let e = std::ffi::CString::new(format!(
"Unable to compile Extism plugin: {}",
e.root_cause(),
))
.unwrap();
*errmsg = e.into_raw();
}
std::ptr::null_mut()
})
}
#[no_mangle]
pub unsafe extern "C" fn extism_plugin_new_from_compiled(
compiled: *const CompiledPlugin,
errmsg: *mut *mut std::ffi::c_char,
) -> *mut Plugin {
let plugin = Plugin::new_from_compiled(&*compiled);
match plugin {
Err(e) => {
if !errmsg.is_null() {
let e = std::ffi::CString::new(format!(
"Unable to create Extism plugin: {}",
e.root_cause(),
))
.unwrap();
*errmsg = e.into_raw();
}
std::ptr::null_mut()
}
Ok(p) => Box::into_raw(Box::new(p)),
}
}
#[no_mangle]
pub unsafe extern "C" fn extism_plugin_new_with_fuel_limit(
wasm: *const u8,
wasm_size: Size,
functions: *mut *const ExtismFunction,
n_functions: Size,
with_wasi: bool,
fuel_limit: u64,
errmsg: *mut *mut std::ffi::c_char,
) -> *mut Plugin {
trace!(
"Call to extism_plugin_new_with_fuel_limit with wasm pointer {:?}",
wasm
);
let data = std::slice::from_raw_parts(wasm, wasm_size as usize);
let funcs = if functions.is_null() {
vec![]
} else {
let funcs = (0..n_functions)
.map(|i| unsafe { *functions.add(i as usize) })
.map(|ptr| {
if ptr.is_null() {
return Err("Cannot pass null pointer");
}
let ExtismFunction(func) = &*ptr;
let Some(func) = func.take() else {
return Err("Function cannot be registered with multiple different Plugins");
};
Ok(func)
})
.collect::<Result<Vec<_>, _>>()
.unwrap_or_else(|e| {
if !errmsg.is_null() {
let e = std::ffi::CString::new(e.to_string()).unwrap();
*errmsg = e.into_raw();
}
Vec::new()
});
if funcs.len() != n_functions as usize {
return std::ptr::null_mut();
}
funcs
};
let compiled = match CompiledPlugin::new(
PluginBuilder::new(data)
.with_functions(funcs)
.with_wasi(with_wasi)
.with_fuel_limit(fuel_limit),
) {
Ok(x) => x,
Err(e) => {
if !errmsg.is_null() {
let e = std::ffi::CString::new(format!(
"Unable to compile Extism plugin: {}",
e.root_cause(),
))
.unwrap();
*errmsg = e.into_raw();
}
return std::ptr::null_mut();
}
};
let plugin = Plugin::new_from_compiled(&compiled);
match plugin {
Err(e) => {
if !errmsg.is_null() {
let e = std::ffi::CString::new(format!(
"Unable to create Extism plugin: {}",
e.root_cause(),
))
.unwrap();
*errmsg = e.into_raw();
}
std::ptr::null_mut()
}
Ok(p) => Box::into_raw(Box::new(p)),
}
}
#[no_mangle]
pub unsafe extern "C" fn extism_plugin_allow_http_response_headers(plugin: *mut Plugin) {
let plugin = &mut *plugin;
plugin.store.data_mut().http_headers = Some(BTreeMap::new());
}
#[no_mangle]
pub unsafe extern "C" fn extism_plugin_new_error_free(err: *mut std::ffi::c_char) {
if err.is_null() {
return;
}
drop(std::ffi::CString::from_raw(err))
}
#[no_mangle]
pub unsafe extern "C" fn extism_plugin_free(plugin: *mut Plugin) {
if plugin.is_null() {
return;
}
let plugin = Box::from_raw(plugin);
trace!(plugin = plugin.id.to_string(), "called extism_plugin_free");
drop(plugin)
}
#[no_mangle]
pub unsafe extern "C" fn extism_plugin_cancel_handle(plugin: *const Plugin) -> *const CancelHandle {
if plugin.is_null() {
return std::ptr::null();
}
let plugin = &*plugin;
trace!(
plugin = plugin.id.to_string(),
"called extism_plugin_cancel_handle"
);
&plugin.cancel_handle as *const _
}
#[no_mangle]
pub unsafe extern "C" fn extism_plugin_cancel(handle: *const CancelHandle) -> bool {
let handle = &*handle;
trace!(
plugin = handle.id.to_string(),
"called extism_plugin_cancel"
);
handle.cancel().is_ok()
}
#[no_mangle]
pub unsafe extern "C" fn extism_plugin_config(
plugin: *mut Plugin,
json: *const u8,
json_size: Size,
) -> bool {
if plugin.is_null() {
return false;
}
let plugin = &mut *plugin;
trace!(
plugin = plugin.id.to_string(),
"call to extism_plugin_config with pointer {:?}",
json
);
let data = std::slice::from_raw_parts(json, json_size as usize);
let json: std::collections::BTreeMap<String, Option<String>> =
match serde_json::from_slice(data) {
Ok(x) => x,
Err(_) => {
return false;
}
};
let id = plugin.id;
let config = &mut plugin.current_plugin_mut().manifest.config;
for (k, v) in json.into_iter() {
match v {
Some(v) => {
trace!(plugin = id.to_string(), "config, adding {k}");
config.insert(k, v);
}
None => {
trace!(plugin = id.to_string(), "config, removing {k}");
config.remove(&k);
}
}
}
let _ = plugin.clear_error();
true
}
#[no_mangle]
pub unsafe extern "C" fn extism_plugin_function_exists(
plugin: *mut Plugin,
func_name: *const c_char,
) -> bool {
if plugin.is_null() {
return false;
}
let plugin = &mut *plugin;
let name = std::ffi::CStr::from_ptr(func_name);
trace!(
plugin = plugin.id.to_string(),
"extism_plugin_function_exists: {:?}",
name
);
let name = match name.to_str() {
Ok(x) => x,
Err(_) => {
return false;
}
};
let _ = plugin.clear_error();
plugin.function_exists(name)
}
#[no_mangle]
pub unsafe extern "C" fn extism_plugin_call(
plugin: *mut Plugin,
func_name: *const c_char,
data: *const u8,
data_len: Size,
) -> i32 {
extism_plugin_call_with_host_context(plugin, func_name, data, data_len, std::ptr::null_mut())
}
#[derive(Clone)]
#[repr(transparent)]
struct CVoidContainer(*mut std::ffi::c_void);
unsafe impl Send for CVoidContainer {}
unsafe impl Sync for CVoidContainer {}
#[no_mangle]
pub unsafe extern "C" fn extism_plugin_call_with_host_context(
plugin: *mut Plugin,
func_name: *const c_char,
data: *const u8,
data_len: Size,
host_context: *mut std::ffi::c_void,
) -> i32 {
if plugin.is_null() {
return -1;
}
let plugin = &mut *plugin;
let lock = plugin.instance.clone();
let mut lock = lock.lock().unwrap();
let name = std::ffi::CStr::from_ptr(func_name);
let name = match name.to_str() {
Ok(name) => name,
Err(e) => {
plugin.error_msg = Some(make_error_msg(e.to_string()));
return -1;
}
};
trace!(
plugin = plugin.id.to_string(),
"calling function {} using extism_plugin_call",
name
);
let input = std::slice::from_raw_parts(data, data_len as usize);
let r = if host_context.is_null() {
None
} else {
Some(CVoidContainer(host_context))
};
let res = plugin.raw_call(&mut lock, name, input, r);
match res {
Err((e, rc)) => {
plugin.error_msg = Some(make_error_msg(e.to_string()));
rc
}
Ok(x) => x,
}
}
#[no_mangle]
#[deprecated]
pub unsafe extern "C" fn extism_error(plugin: *mut Plugin) -> *const c_char {
extism_plugin_error(plugin)
}
#[no_mangle]
pub unsafe extern "C" fn extism_plugin_error(plugin: *mut Plugin) -> *const c_char {
if plugin.is_null() {
return std::ptr::null();
}
let plugin = &mut *plugin;
let _lock = plugin.instance.clone();
let _lock = _lock.lock().unwrap();
if plugin.output.error_offset == 0 {
if let Some(err) = &plugin.error_msg {
return err.as_ptr() as *const _;
}
trace!(plugin = plugin.id.to_string(), "error is NULL");
return std::ptr::null();
}
let offs = plugin.output.error_offset;
let ptr = plugin.current_plugin_mut().memory_ptr().add(offs as usize) as *const _;
let len = plugin
.current_plugin_mut()
.memory_length(offs)
.unwrap_or_default();
let mut data = std::slice::from_raw_parts(ptr, len as usize).to_vec();
data.push(0);
plugin.error_msg = Some(data);
plugin.error_msg.as_ref().unwrap().as_ptr() as *const _
}
#[no_mangle]
pub unsafe extern "C" fn extism_plugin_output_length(plugin: *mut Plugin) -> Size {
if plugin.is_null() {
return 0;
}
let plugin = &mut *plugin;
let _lock = plugin.instance.clone();
let _lock = _lock.lock().unwrap();
plugin.output.length
}
#[no_mangle]
pub unsafe extern "C" fn extism_plugin_output_data(plugin: *mut Plugin) -> *const u8 {
if plugin.is_null() {
return std::ptr::null();
}
let plugin = &mut *plugin;
let _lock = plugin.instance.clone();
let _lock = _lock.lock().unwrap();
trace!(
plugin = plugin.id.to_string(),
"extism_plugin_output_data: offset={}, length={}",
plugin.output.offset,
plugin.output.length
);
let ptr = plugin.current_plugin_mut().memory_ptr();
ptr.add(plugin.output.offset as usize)
}
#[no_mangle]
pub unsafe extern "C" fn extism_log_file(
filename: *const c_char,
log_level: *const c_char,
) -> bool {
let file = if !filename.is_null() {
let file = std::ffi::CStr::from_ptr(filename);
match file.to_str() {
Ok(x) => x,
Err(_) => {
return false;
}
}
} else {
"stderr"
};
let level = if !log_level.is_null() {
let level = std::ffi::CStr::from_ptr(log_level);
match level.to_str() {
Ok(x) => x,
Err(_) => {
return false;
}
}
} else {
"error"
};
set_log_file(file, level).is_ok()
}
fn set_log_file(log_file: impl Into<std::path::PathBuf>, filter: &str) -> Result<(), Error> {
let log_file = log_file.into();
let s = log_file.to_str();
let is_level = tracing::Level::from_str(filter).is_ok();
let cfg = tracing_subscriber::FmtSubscriber::builder().with_env_filter({
let x = tracing_subscriber::EnvFilter::builder()
.with_default_directive(tracing::Level::ERROR.into());
if is_level {
x.parse_lossy(format!("extism={filter}"))
} else {
x.parse_lossy(filter)
}
});
let res = if s == Some("-") || s == Some("stderr") {
cfg.with_ansi(true).with_writer(std::io::stderr).try_init()
} else if s == Some("stdout") {
cfg.with_ansi(true).with_writer(std::io::stdout).try_init()
} else {
let log_file = log_file.to_path_buf();
let f = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(log_file)
.expect("Open log file");
cfg.with_ansi(false)
.with_writer(move || f.try_clone().unwrap())
.try_init()
};
if let Err(e) = res {
return Err(Error::msg(e.to_string()));
}
Ok(())
}
static LOG_BUFFER: std::sync::Mutex<Option<LogBuffer>> = std::sync::Mutex::new(None);
#[no_mangle]
pub unsafe extern "C" fn extism_log_custom(log_level: *const c_char) -> bool {
let level = if !log_level.is_null() {
let level = std::ffi::CStr::from_ptr(log_level);
match level.to_str() {
Ok(x) => x,
Err(_) => {
return false;
}
}
} else {
"error"
};
set_log_buffer(level).is_ok()
}
unsafe fn set_log_buffer(filter: &str) -> Result<(), Error> {
let is_level = tracing::Level::from_str(filter).is_ok();
let cfg = tracing_subscriber::FmtSubscriber::builder().with_env_filter({
let x = tracing_subscriber::EnvFilter::builder()
.with_default_directive(tracing::Level::ERROR.into());
if is_level {
x.parse_lossy(format!("extism={filter}"))
} else {
x.parse_lossy(filter)
}
});
*LOG_BUFFER.lock().unwrap() = Some(LogBuffer::default());
let buf = LOG_BUFFER.lock().unwrap().clone().unwrap();
cfg.with_ansi(false)
.with_writer(move || buf.clone())
.try_init()
.map_err(|x| Error::msg(x.to_string()))?;
Ok(())
}
#[no_mangle]
pub unsafe extern "C" fn extism_log_drain(handler: ExtismLogDrainFunctionType) {
if let Some(buf) = LOG_BUFFER.lock().unwrap().as_mut() {
if let Ok(mut buf) = buf.buffer.lock() {
for (line, len) in buf.drain(..) {
handler(line.as_ptr(), len as u64);
}
}
}
}
#[derive(Default, Clone)]
struct LogBuffer {
buffer:
std::sync::Arc<std::sync::Mutex<std::collections::VecDeque<(std::ffi::CString, usize)>>>,
}
unsafe impl Send for LogBuffer {}
unsafe impl Sync for LogBuffer {}
impl std::io::Write for LogBuffer {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
if let Ok(s) = std::str::from_utf8(buf) {
if let Ok(mut buf) = self.buffer.lock() {
buf.push_back((std::ffi::CString::new(s)?, s.len()));
}
}
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
#[no_mangle]
pub unsafe extern "C" fn extism_plugin_reset(plugin: *mut Plugin) -> bool {
let plugin = &mut *plugin;
if let Err(e) = plugin.reset() {
error!(
plugin = plugin.id.to_string(),
"unable to reset plugin: {}",
e.to_string()
);
if let Err(e) = plugin.current_plugin_mut().set_error(e.to_string()) {
error!(
plugin = plugin.id.to_string(),
"unable to set error after failed plugin reset: {}",
e.to_string()
);
}
false
} else {
true
}
}
#[no_mangle]
pub unsafe extern "C" fn extism_version() -> *const c_char {
VERSION.as_ptr() as *const _
}