1 use std::ffi::c_void;
2 
3 use wasmtime::component::{Instance, Linker, LinkerInstance, Val};
4 
5 use crate::{
6     WasmtimeStoreContextMut, WasmtimeStoreData, wasm_engine_t, wasmtime_error_t, wasmtime_module_t,
7 };
8 
9 use super::{wasmtime_component_t, wasmtime_component_val_t};
10 
11 #[repr(transparent)]
12 pub struct wasmtime_component_linker_t {
13     pub(crate) linker: Linker<WasmtimeStoreData>,
14 }
15 
16 #[repr(transparent)]
17 pub struct wasmtime_component_linker_instance_t<'a> {
18     pub(crate) linker_instance: LinkerInstance<'a, WasmtimeStoreData>,
19 }
20 
21 #[unsafe(no_mangle)]
22 pub unsafe extern "C" fn wasmtime_component_linker_new(
23     engine: &wasm_engine_t,
24 ) -> Box<wasmtime_component_linker_t> {
25     Box::new(wasmtime_component_linker_t {
26         linker: Linker::new(&engine.engine),
27     })
28 }
29 
30 #[unsafe(no_mangle)]
31 pub unsafe extern "C" fn wasmtime_component_linker_root(
32     linker: &mut wasmtime_component_linker_t,
33 ) -> Box<wasmtime_component_linker_instance_t<'_>> {
34     Box::new(wasmtime_component_linker_instance_t {
35         linker_instance: linker.linker.root(),
36     })
37 }
38 
39 #[unsafe(no_mangle)]
40 pub unsafe extern "C" fn wasmtime_component_linker_instantiate(
41     linker: &wasmtime_component_linker_t,
42     context: WasmtimeStoreContextMut<'_>,
43     component: &wasmtime_component_t,
44     instance_out: &mut Instance,
45 ) -> Option<Box<wasmtime_error_t>> {
46     let result = linker.linker.instantiate(context, &component.component);
47     crate::handle_result(result, |instance| *instance_out = instance)
48 }
49 
50 #[unsafe(no_mangle)]
51 pub unsafe extern "C" fn wasmtime_component_linker_delete(
52     _linker: Box<wasmtime_component_linker_t>,
53 ) {
54 }
55 
56 #[unsafe(no_mangle)]
57 pub unsafe extern "C" fn wasmtime_component_linker_instance_add_instance<'a>(
58     linker_instance: &'a mut wasmtime_component_linker_instance_t<'a>,
59     name: *const u8,
60     name_len: usize,
61     linker_instance_out: &mut *mut wasmtime_component_linker_instance_t<'a>,
62 ) -> Option<Box<wasmtime_error_t>> {
63     let name = unsafe { std::slice::from_raw_parts(name, name_len) };
64     let Ok(name) = std::str::from_utf8(name) else {
65         return crate::bad_utf8();
66     };
67 
68     let result = linker_instance.linker_instance.instance(&name);
69     crate::handle_result(result, |linker_instance| {
70         *linker_instance_out = Box::into_raw(Box::new(wasmtime_component_linker_instance_t {
71             linker_instance,
72         }));
73     })
74 }
75 
76 #[unsafe(no_mangle)]
77 pub unsafe extern "C" fn wasmtime_component_linker_instance_add_module(
78     linker_instance: &mut wasmtime_component_linker_instance_t,
79     name: *const u8,
80     name_len: usize,
81     module: &wasmtime_module_t,
82 ) -> Option<Box<wasmtime_error_t>> {
83     let name = unsafe { std::slice::from_raw_parts(name, name_len) };
84     let Ok(name) = std::str::from_utf8(name) else {
85         return crate::bad_utf8();
86     };
87 
88     let result = linker_instance
89         .linker_instance
90         .module(&name, &module.module);
91 
92     crate::handle_result(result, |_| ())
93 }
94 
95 pub type wasmtime_component_func_callback_t = extern "C" fn(
96     *mut c_void,
97     WasmtimeStoreContextMut<'_>,
98     *const wasmtime_component_val_t,
99     usize,
100     *mut wasmtime_component_val_t,
101     usize,
102 ) -> Option<Box<wasmtime_error_t>>;
103 
104 #[unsafe(no_mangle)]
105 pub unsafe extern "C" fn wasmtime_component_linker_instance_add_func(
106     linker_instance: &mut wasmtime_component_linker_instance_t,
107     name: *const u8,
108     name_len: usize,
109     callback: wasmtime_component_func_callback_t,
110     data: *mut c_void,
111     finalizer: Option<extern "C" fn(*mut c_void)>,
112 ) -> Option<Box<wasmtime_error_t>> {
113     let name = unsafe { std::slice::from_raw_parts(name, name_len) };
114     let Ok(name) = std::str::from_utf8(name) else {
115         return crate::bad_utf8();
116     };
117 
118     let foreign = crate::ForeignData { data, finalizer };
119 
120     let result = linker_instance
121         .linker_instance
122         .func_new(&name, move |ctx, args, rets| {
123             let _ = &foreign;
124 
125             let args = args
126                 .iter()
127                 .map(|x| wasmtime_component_val_t::from(x))
128                 .collect::<Vec<_>>();
129 
130             let mut c_rets = vec![wasmtime_component_val_t::Bool(false); rets.len()];
131 
132             let res = callback(
133                 foreign.data,
134                 ctx,
135                 args.as_ptr(),
136                 args.len(),
137                 c_rets.as_mut_ptr(),
138                 c_rets.len(),
139             );
140 
141             if let Some(res) = res {
142                 return Err((*res).into());
143             }
144 
145             for (rust_val, c_val) in std::iter::zip(rets, c_rets) {
146                 *rust_val = Val::from(&c_val);
147             }
148 
149             Ok(())
150         });
151 
152     crate::handle_result(result, |_| ())
153 }
154 
155 #[unsafe(no_mangle)]
156 #[cfg(feature = "wasi")]
157 pub unsafe extern "C" fn wasmtime_component_linker_add_wasip2(
158     linker: &mut wasmtime_component_linker_t,
159 ) -> Option<Box<wasmtime_error_t>> {
160     let result = wasmtime_wasi::p2::add_to_linker_sync(&mut linker.linker);
161     crate::handle_result(result, |_| ())
162 }
163 
164 #[unsafe(no_mangle)]
165 pub unsafe extern "C" fn wasmtime_component_linker_instance_delete(
166     _linker_instance: Box<wasmtime_component_linker_instance_t>,
167 ) {
168 }
169