use crate::{ WasmtimeStoreContextMut, WasmtimeStoreData, wasm_engine_t, wasmtime_component_func_type_t, wasmtime_component_resource_type_t, wasmtime_error_t, wasmtime_module_t, }; use std::ffi::c_void; use wasmtime::component::{Instance, Linker, LinkerInstance, Val}; use super::{wasmtime_component_t, wasmtime_component_val_t}; #[repr(transparent)] pub struct wasmtime_component_linker_t { pub(crate) linker: Linker, } #[repr(transparent)] pub struct wasmtime_component_linker_instance_t<'a> { pub(crate) linker_instance: LinkerInstance<'a, WasmtimeStoreData>, } #[unsafe(no_mangle)] pub extern "C" fn wasmtime_component_linker_new( engine: &wasm_engine_t, ) -> Box { Box::new(wasmtime_component_linker_t { linker: Linker::new(&engine.engine), }) } #[unsafe(no_mangle)] pub extern "C" fn wasmtime_component_linker_allow_shadowing( linker: &mut wasmtime_component_linker_t, allow: bool, ) { linker.linker.allow_shadowing(allow); } #[unsafe(no_mangle)] pub extern "C" fn wasmtime_component_linker_root( linker: &mut wasmtime_component_linker_t, ) -> Box> { Box::new(wasmtime_component_linker_instance_t { linker_instance: linker.linker.root(), }) } #[unsafe(no_mangle)] pub extern "C" fn wasmtime_component_linker_instantiate( linker: &wasmtime_component_linker_t, context: WasmtimeStoreContextMut<'_>, component: &wasmtime_component_t, instance_out: &mut Instance, ) -> Option> { let result = linker.linker.instantiate(context, &component.component); crate::handle_result(result, |instance| *instance_out = instance) } #[unsafe(no_mangle)] pub extern "C" fn wasmtime_component_linker_delete(_linker: Box) {} #[unsafe(no_mangle)] pub unsafe extern "C" fn wasmtime_component_linker_instance_add_instance<'a>( linker_instance: &'a mut wasmtime_component_linker_instance_t<'a>, name: *const u8, name_len: usize, linker_instance_out: &mut *mut wasmtime_component_linker_instance_t<'a>, ) -> Option> { let name = unsafe { std::slice::from_raw_parts(name, name_len) }; let Ok(name) = std::str::from_utf8(name) else { return crate::bad_utf8(); }; let result = linker_instance.linker_instance.instance(&name); crate::handle_result(result, |linker_instance| { *linker_instance_out = Box::into_raw(Box::new(wasmtime_component_linker_instance_t { linker_instance, })); }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn wasmtime_component_linker_instance_add_module( linker_instance: &mut wasmtime_component_linker_instance_t, name: *const u8, name_len: usize, module: &wasmtime_module_t, ) -> Option> { let name = unsafe { std::slice::from_raw_parts(name, name_len) }; let Ok(name) = std::str::from_utf8(name) else { return crate::bad_utf8(); }; let result = linker_instance .linker_instance .module(&name, &module.module); crate::handle_result(result, |_| ()) } pub type wasmtime_component_func_callback_t = extern "C" fn( *mut c_void, WasmtimeStoreContextMut<'_>, &wasmtime_component_func_type_t, *mut wasmtime_component_val_t, usize, *mut wasmtime_component_val_t, usize, ) -> Option>; #[unsafe(no_mangle)] pub unsafe extern "C" fn wasmtime_component_linker_instance_add_func( linker_instance: &mut wasmtime_component_linker_instance_t, name: *const u8, name_len: usize, callback: wasmtime_component_func_callback_t, data: *mut c_void, finalizer: Option, ) -> Option> { let name = unsafe { std::slice::from_raw_parts(name, name_len) }; let Ok(name) = std::str::from_utf8(name) else { return crate::bad_utf8(); }; let foreign = crate::ForeignData { data, finalizer }; let result = linker_instance .linker_instance .func_new(&name, move |ctx, ty, args, rets| { let _ = &foreign; let mut args = args .iter() .map(|x| wasmtime_component_val_t::from(x)) .collect::>(); let mut c_rets = vec![wasmtime_component_val_t::Bool(false); rets.len()]; let res = callback( foreign.data, ctx, &ty.into(), args.as_mut_ptr(), args.len(), c_rets.as_mut_ptr(), c_rets.len(), ); if let Some(res) = res { return Err((*res).into()); } for (rust_val, c_val) in std::iter::zip(rets, c_rets) { *rust_val = Val::from(&c_val); } Ok(()) }); crate::handle_result(result, |_| ()) } #[unsafe(no_mangle)] #[cfg(feature = "wasi")] pub unsafe extern "C" fn wasmtime_component_linker_add_wasip2( linker: &mut wasmtime_component_linker_t, ) -> Option> { let result = wasmtime_wasi::p2::add_to_linker_sync(&mut linker.linker); crate::handle_result(result, |_| ()) } #[unsafe(no_mangle)] #[cfg(feature = "wasi-http")] pub unsafe extern "C" fn wasmtime_component_linker_add_wasi_http( linker: &mut wasmtime_component_linker_t, ) -> Option> { let result = wasmtime_wasi_http::p2::add_only_http_to_linker_sync(&mut linker.linker); crate::handle_result(result, |_| ()) } #[unsafe(no_mangle)] pub unsafe extern "C" fn wasmtime_component_linker_define_unknown_imports_as_traps( linker: &mut wasmtime_component_linker_t, component: &wasmtime_component_t, ) -> Option> { let result = linker .linker .define_unknown_imports_as_traps(&component.component); crate::handle_result(result, |_| ()) } pub type wasmtime_component_resource_destructor_t = extern "C" fn(*mut c_void, WasmtimeStoreContextMut<'_>, u32) -> Option>; #[unsafe(no_mangle)] pub unsafe extern "C" fn wasmtime_component_linker_instance_add_resource( linker_instance: &mut wasmtime_component_linker_instance_t, name: *const u8, name_len: usize, ty: &wasmtime_component_resource_type_t, callback: wasmtime_component_resource_destructor_t, data: *mut c_void, finalizer: Option, ) -> Option> { let name = unsafe { std::slice::from_raw_parts(name, name_len) }; let Ok(name) = std::str::from_utf8(name) else { return crate::bad_utf8(); }; let foreign = crate::ForeignData { data, finalizer }; let result = linker_instance .linker_instance .resource(name, ty.ty, move |ctx, rep| { let _ = &foreign; if let Some(res) = callback(foreign.data, ctx, rep) { return Err((*res).into()); } Ok(()) }); crate::handle_result(result, |_| ()) } #[unsafe(no_mangle)] pub unsafe extern "C" fn wasmtime_component_linker_instance_delete( _linker_instance: Box, ) { }