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