Skip to main content

wasmtime_c_api/component/
linker.rs

1use crate::{
2    WasmtimeStoreContextMut, WasmtimeStoreData, wasm_engine_t, wasmtime_component_func_type_t,
3    wasmtime_component_resource_type_t, wasmtime_error_t, wasmtime_module_t,
4};
5use std::ffi::c_void;
6use wasmtime::component::{Instance, Linker, LinkerInstance, Val};
7
8use super::{wasmtime_component_t, wasmtime_component_val_t};
9
10#[repr(transparent)]
11pub struct wasmtime_component_linker_t {
12    pub(crate) linker: Linker<WasmtimeStoreData>,
13}
14
15#[repr(transparent)]
16pub struct wasmtime_component_linker_instance_t<'a> {
17    pub(crate) linker_instance: LinkerInstance<'a, WasmtimeStoreData>,
18}
19
20#[unsafe(no_mangle)]
21pub 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)]
30pub 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)]
38pub 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)]
47pub 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)]
58pub extern "C" fn wasmtime_component_linker_delete(_linker: Box<wasmtime_component_linker_t>) {}
59
60#[unsafe(no_mangle)]
61pub 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)]
81pub 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
99pub type wasmtime_component_func_callback_t = extern "C" fn(
100    *mut c_void,
101    WasmtimeStoreContextMut<'_>,
102    &wasmtime_component_func_type_t,
103    *mut wasmtime_component_val_t,
104    usize,
105    *mut wasmtime_component_val_t,
106    usize,
107) -> Option<Box<wasmtime_error_t>>;
108
109#[unsafe(no_mangle)]
110pub unsafe extern "C" fn wasmtime_component_linker_instance_add_func(
111    linker_instance: &mut wasmtime_component_linker_instance_t,
112    name: *const u8,
113    name_len: usize,
114    callback: wasmtime_component_func_callback_t,
115    data: *mut c_void,
116    finalizer: Option<extern "C" fn(*mut c_void)>,
117) -> Option<Box<wasmtime_error_t>> {
118    let name = unsafe { std::slice::from_raw_parts(name, name_len) };
119    let Ok(name) = std::str::from_utf8(name) else {
120        return crate::bad_utf8();
121    };
122
123    let foreign = crate::ForeignData { data, finalizer };
124
125    let result = linker_instance
126        .linker_instance
127        .func_new(&name, move |ctx, ty, args, rets| {
128            let _ = &foreign;
129
130            let mut args = args
131                .iter()
132                .map(|x| wasmtime_component_val_t::from(x))
133                .collect::<Vec<_>>();
134
135            let mut c_rets = vec![wasmtime_component_val_t::Bool(false); rets.len()];
136
137            let res = callback(
138                foreign.data,
139                ctx,
140                &ty.into(),
141                args.as_mut_ptr(),
142                args.len(),
143                c_rets.as_mut_ptr(),
144                c_rets.len(),
145            );
146
147            if let Some(res) = res {
148                return Err((*res).into());
149            }
150
151            for (rust_val, c_val) in std::iter::zip(rets, c_rets) {
152                *rust_val = Val::from(&c_val);
153            }
154
155            Ok(())
156        });
157
158    crate::handle_result(result, |_| ())
159}
160
161#[cfg(feature = "component-model-async")]
162pub type wasmtime_component_func_async_callback_t = extern "C" fn(
163    *mut c_void,
164    WasmtimeStoreContextMut<'_>,
165    &wasmtime_component_func_type_t,
166    *mut wasmtime_component_val_t,
167    usize,
168    *mut wasmtime_component_val_t,
169    usize,
170    &mut Option<Box<wasmtime_error_t>>,
171    &mut crate::wasmtime_async_continuation_t,
172);
173
174#[unsafe(no_mangle)]
175#[cfg(feature = "component-model-async")]
176pub unsafe extern "C" fn wasmtime_component_linker_instance_add_func_async(
177    linker_instance: &mut wasmtime_component_linker_instance_t,
178    name: *const u8,
179    name_len: usize,
180    callback: wasmtime_component_func_async_callback_t,
181    data: *mut c_void,
182    finalizer: Option<extern "C" fn(*mut c_void)>,
183) -> Option<Box<wasmtime_error_t>> {
184    let name = unsafe { std::slice::from_raw_parts(name, name_len) };
185    let Ok(name) = std::str::from_utf8(name) else {
186        return crate::bad_utf8();
187    };
188
189    let foreign = crate::ForeignData { data, finalizer };
190
191    let result =
192        linker_instance
193            .linker_instance
194            .func_new_async(&name, move |ctx, ty, args, rets| {
195                let _ = &foreign;
196
197                let mut c_args = args
198                    .iter()
199                    .map(|x| wasmtime_component_val_t::from(x))
200                    .collect::<Vec<_>>();
201
202                let mut c_rets = vec![wasmtime_component_val_t::Bool(false); rets.len()];
203
204                let mut err = None;
205                extern "C" fn panic_callback(_: *mut c_void) -> bool {
206                    panic!("callback must be set")
207                }
208                let mut continuation = crate::wasmtime_async_continuation_t {
209                    callback: panic_callback,
210                    env: std::ptr::null_mut(),
211                    finalizer: None,
212                };
213                callback(
214                    foreign.data,
215                    ctx,
216                    &ty.into(),
217                    c_args.as_mut_ptr(),
218                    c_args.len(),
219                    c_rets.as_mut_ptr(),
220                    c_rets.len(),
221                    &mut err,
222                    &mut continuation,
223                );
224
225                if let Some(err) = err {
226                    return Box::new(async { Err((*err).into()) });
227                }
228
229                Box::new(async move {
230                    continuation.await;
231                    for (rust_val, c_val) in std::iter::zip(rets, c_rets) {
232                        *rust_val = Val::from(&c_val);
233                    }
234                    Ok(())
235                })
236            });
237
238    crate::handle_result(result, |_| ())
239}
240
241#[unsafe(no_mangle)]
242#[cfg(feature = "wasi")]
243pub unsafe extern "C" fn wasmtime_component_linker_add_wasip2(
244    linker: &mut wasmtime_component_linker_t,
245) -> Option<Box<wasmtime_error_t>> {
246    let result = wasmtime_wasi::p2::add_to_linker_sync(&mut linker.linker);
247    crate::handle_result(result, |_| ())
248}
249
250#[unsafe(no_mangle)]
251#[cfg(feature = "wasi-http")]
252pub unsafe extern "C" fn wasmtime_component_linker_add_wasi_http(
253    linker: &mut wasmtime_component_linker_t,
254) -> Option<Box<wasmtime_error_t>> {
255    let result = wasmtime_wasi_http::p2::add_only_http_to_linker_sync(&mut linker.linker);
256    crate::handle_result(result, |_| ())
257}
258
259#[unsafe(no_mangle)]
260#[cfg(feature = "component-model-async")]
261pub unsafe extern "C" fn wasmtime_component_linker_instantiate_async<'a>(
262    linker: &'a wasmtime_component_linker_t,
263    mut context: WasmtimeStoreContextMut<'a>,
264    component: &'a wasmtime_component_t,
265    instance_out: &'a mut Instance,
266    err_ret: &'a mut *mut wasmtime_error_t,
267) -> Box<crate::wasmtime_call_future_t<'a>> {
268    let fut = Box::pin(async move {
269        match linker
270            .linker
271            .instantiate_async(&mut context, &component.component)
272            .await
273        {
274            Ok(instance) => *instance_out = instance,
275            Err(err) => {
276                *err_ret = Box::into_raw(Box::new(wasmtime_error_t::from(err)));
277            }
278        }
279    });
280    Box::new(crate::wasmtime_call_future_t::new(fut))
281}
282
283#[unsafe(no_mangle)]
284#[cfg(all(feature = "wasi", feature = "component-model-async"))]
285pub unsafe extern "C" fn wasmtime_component_linker_add_wasip2_async(
286    linker: &mut wasmtime_component_linker_t,
287) -> Option<Box<wasmtime_error_t>> {
288    let result = wasmtime_wasi::p2::add_to_linker_async(&mut linker.linker);
289    crate::handle_result(result, |_| ())
290}
291
292#[unsafe(no_mangle)]
293#[cfg(all(feature = "wasi-http", feature = "component-model-async"))]
294pub unsafe extern "C" fn wasmtime_component_linker_add_wasi_http_async(
295    linker: &mut wasmtime_component_linker_t,
296) -> Option<Box<wasmtime_error_t>> {
297    let result = wasmtime_wasi_http::p2::add_only_http_to_linker_async(&mut linker.linker);
298    crate::handle_result(result, |_| ())
299}
300
301#[unsafe(no_mangle)]
302pub unsafe extern "C" fn wasmtime_component_linker_define_unknown_imports_as_traps(
303    linker: &mut wasmtime_component_linker_t,
304    component: &wasmtime_component_t,
305) -> Option<Box<wasmtime_error_t>> {
306    let result = linker
307        .linker
308        .define_unknown_imports_as_traps(&component.component);
309    crate::handle_result(result, |_| ())
310}
311
312pub type wasmtime_component_resource_destructor_t =
313    extern "C" fn(*mut c_void, WasmtimeStoreContextMut<'_>, u32) -> Option<Box<wasmtime_error_t>>;
314
315#[unsafe(no_mangle)]
316pub unsafe extern "C" fn wasmtime_component_linker_instance_add_resource(
317    linker_instance: &mut wasmtime_component_linker_instance_t,
318    name: *const u8,
319    name_len: usize,
320    ty: &wasmtime_component_resource_type_t,
321    callback: wasmtime_component_resource_destructor_t,
322    data: *mut c_void,
323    finalizer: Option<extern "C" fn(*mut c_void)>,
324) -> Option<Box<wasmtime_error_t>> {
325    let name = unsafe { std::slice::from_raw_parts(name, name_len) };
326    let Ok(name) = std::str::from_utf8(name) else {
327        return crate::bad_utf8();
328    };
329
330    let foreign = crate::ForeignData { data, finalizer };
331
332    let result = linker_instance
333        .linker_instance
334        .resource(name, ty.ty, move |ctx, rep| {
335            let _ = &foreign;
336            if let Some(res) = callback(foreign.data, ctx, rep) {
337                return Err((*res).into());
338            }
339            Ok(())
340        });
341
342    crate::handle_result(result, |_| ())
343}
344
345#[unsafe(no_mangle)]
346pub unsafe extern "C" fn wasmtime_component_linker_instance_delete(
347    _linker_instance: Box<wasmtime_component_linker_instance_t>,
348) {
349}