Skip to main content

wasmtime_c_api/component/
val.rs

1use crate::{
2    WasmtimeStoreContextMut, handle_result, wasm_name_t, wasmtime_component_resource_type_t,
3    wasmtime_error_t,
4};
5use std::mem;
6use std::mem::{ManuallyDrop, MaybeUninit};
7use std::ptr;
8use std::slice;
9use wasmtime::component::{ResourceAny, ResourceDynamic, Val};
10
11crate::declare_vecs! {
12    (
13        name: wasmtime_component_vallist_t,
14        ty: wasmtime_component_val_t,
15        new: wasmtime_component_vallist_new,
16        empty: wasmtime_component_vallist_new_empty,
17        uninit: wasmtime_component_vallist_new_uninit,
18        copy: wasmtime_component_vallist_copy,
19        delete: wasmtime_component_vallist_delete,
20    )
21    (
22        name: wasmtime_component_valrecord_t,
23        ty: wasmtime_component_valrecord_entry_t,
24        new: wasmtime_component_valrecord_new,
25        empty: wasmtime_component_valrecord_new_empty,
26        uninit: wasmtime_component_valrecord_new_uninit,
27        copy: wasmtime_component_valrecord_copy,
28        delete: wasmtime_component_valrecord_delete,
29    )
30    (
31        name: wasmtime_component_valtuple_t,
32        ty: wasmtime_component_val_t,
33        new: wasmtime_component_valtuple_new,
34        empty: wasmtime_component_valtuple_new_empty,
35        uninit: wasmtime_component_valtuple_new_uninit,
36        copy: wasmtime_component_valtuple_copy,
37        delete: wasmtime_component_valtuple_delete,
38    )
39    (
40        name: wasmtime_component_valflags_t,
41        ty: wasm_name_t,
42        new: wasmtime_component_valflags_new,
43        empty: wasmtime_component_valflags_new_empty,
44        uninit: wasmtime_component_valflags_new_uninit,
45        copy: wasmtime_component_valflags_copy,
46        delete: wasmtime_component_valflags_delete,
47    )
48    (
49        name: wasmtime_component_valmap_t,
50        ty: wasmtime_component_valmap_entry_t,
51        new: wasmtime_component_valmap_new,
52        empty: wasmtime_component_valmap_new_empty,
53        uninit: wasmtime_component_valmap_new_uninit,
54        copy: wasmtime_component_valmap_copy,
55        delete: wasmtime_component_valmap_delete,
56    )
57}
58
59impl From<&wasmtime_component_vallist_t> for Vec<Val> {
60    fn from(value: &wasmtime_component_vallist_t) -> Self {
61        value.as_slice().iter().map(Val::from).collect()
62    }
63}
64
65impl From<&[Val]> for wasmtime_component_vallist_t {
66    fn from(value: &[Val]) -> Self {
67        value
68            .iter()
69            .map(wasmtime_component_val_t::from)
70            .collect::<Vec<_>>()
71            .into()
72    }
73}
74
75impl From<&wasmtime_component_valmap_t> for Vec<(Val, Val)> {
76    fn from(value: &wasmtime_component_valmap_t) -> Self {
77        value
78            .as_slice()
79            .iter()
80            .map(|entry| (Val::from(&entry.key), Val::from(&entry.value)))
81            .collect()
82    }
83}
84
85impl From<&[(Val, Val)]> for wasmtime_component_valmap_t {
86    fn from(value: &[(Val, Val)]) -> Self {
87        value
88            .iter()
89            .map(|(k, v)| wasmtime_component_valmap_entry_t {
90                key: wasmtime_component_val_t::from(k),
91                value: wasmtime_component_val_t::from(v),
92            })
93            .collect::<Vec<_>>()
94            .into()
95    }
96}
97
98#[derive(Clone)]
99#[repr(C)]
100pub struct wasmtime_component_valrecord_entry_t {
101    name: wasm_name_t,
102    val: wasmtime_component_val_t,
103}
104
105#[derive(Clone, Default)]
106#[repr(C)]
107pub struct wasmtime_component_valmap_entry_t {
108    key: wasmtime_component_val_t,
109    value: wasmtime_component_val_t,
110}
111
112impl Default for wasmtime_component_valrecord_entry_t {
113    fn default() -> Self {
114        Self {
115            name: wasm_name_t::from_name(String::new()),
116            val: Default::default(),
117        }
118    }
119}
120
121impl From<&wasmtime_component_valrecord_entry_t> for (String, Val) {
122    fn from(value: &wasmtime_component_valrecord_entry_t) -> Self {
123        (
124            String::from_utf8(value.name.clone().take()).unwrap(),
125            Val::from(&value.val),
126        )
127    }
128}
129
130impl From<&(String, Val)> for wasmtime_component_valrecord_entry_t {
131    fn from((name, val): &(String, Val)) -> Self {
132        Self {
133            name: wasm_name_t::from_name(name.clone()),
134            val: wasmtime_component_val_t::from(val),
135        }
136    }
137}
138
139impl From<&wasmtime_component_valrecord_t> for Vec<(String, Val)> {
140    fn from(value: &wasmtime_component_valrecord_t) -> Self {
141        value.as_slice().iter().map(Into::into).collect()
142    }
143}
144
145impl From<&[(String, Val)]> for wasmtime_component_valrecord_t {
146    fn from(value: &[(String, Val)]) -> Self {
147        value
148            .iter()
149            .map(wasmtime_component_valrecord_entry_t::from)
150            .collect::<Vec<_>>()
151            .into()
152    }
153}
154
155impl From<&wasmtime_component_valtuple_t> for Vec<Val> {
156    fn from(value: &wasmtime_component_valtuple_t) -> Self {
157        value.as_slice().iter().map(Val::from).collect()
158    }
159}
160
161impl From<&[Val]> for wasmtime_component_valtuple_t {
162    fn from(value: &[Val]) -> Self {
163        value
164            .iter()
165            .map(wasmtime_component_val_t::from)
166            .collect::<Vec<_>>()
167            .into()
168    }
169}
170
171impl From<&wasmtime_component_valflags_t> for Vec<String> {
172    fn from(value: &wasmtime_component_valflags_t) -> Self {
173        value
174            .clone()
175            .take()
176            .into_iter()
177            .map(|mut x| String::from_utf8(x.take()))
178            .collect::<Result<Vec<_>, _>>()
179            .unwrap()
180    }
181}
182
183impl From<&[String]> for wasmtime_component_valflags_t {
184    fn from(value: &[String]) -> Self {
185        value
186            .iter()
187            .map(|x| wasm_name_t::from_name(x.clone()))
188            .collect::<Vec<_>>()
189            .into()
190    }
191}
192
193#[repr(C)]
194#[derive(Clone)]
195pub struct wasmtime_component_valvariant_t {
196    discriminant: wasm_name_t,
197    val: Option<Box<wasmtime_component_val_t>>,
198}
199
200impl From<(&String, &Option<Box<Val>>)> for wasmtime_component_valvariant_t {
201    fn from((discriminant, value): (&String, &Option<Box<Val>>)) -> Self {
202        Self {
203            discriminant: wasm_name_t::from_name(discriminant.clone()),
204            val: value
205                .as_ref()
206                .map(|x| Box::new(wasmtime_component_val_t::from(x.as_ref()))),
207        }
208    }
209}
210
211impl From<&wasmtime_component_valvariant_t> for (String, Option<Box<Val>>) {
212    fn from(value: &wasmtime_component_valvariant_t) -> Self {
213        (
214            String::from_utf8(value.discriminant.clone().take()).unwrap(),
215            value.val.as_ref().map(|x| Box::new(Val::from(x.as_ref()))),
216        )
217    }
218}
219
220#[repr(C)]
221#[derive(Clone)]
222pub struct wasmtime_component_valresult_t {
223    is_ok: bool,
224    val: Option<Box<wasmtime_component_val_t>>,
225}
226
227impl From<&wasmtime_component_valresult_t> for Result<Option<Box<Val>>, Option<Box<Val>>> {
228    fn from(value: &wasmtime_component_valresult_t) -> Self {
229        let val = value.val.as_ref().map(|x| Box::new(Val::from(x.as_ref())));
230
231        match value.is_ok {
232            true => Ok(val),
233            false => Err(val),
234        }
235    }
236}
237
238impl From<&Result<Option<Box<Val>>, Option<Box<Val>>>> for wasmtime_component_valresult_t {
239    fn from(value: &Result<Option<Box<Val>>, Option<Box<Val>>>) -> Self {
240        let (Ok(x) | Err(x)) = value;
241
242        Self {
243            is_ok: value.is_ok(),
244            val: x
245                .as_ref()
246                .map(|x| Box::new(wasmtime_component_val_t::from(x.as_ref()))),
247        }
248    }
249}
250
251#[repr(C, u8)]
252#[derive(Clone)]
253pub enum wasmtime_component_val_t {
254    Bool(bool),
255    S8(i8),
256    U8(u8),
257    S16(i16),
258    U16(u16),
259    S32(i32),
260    U32(u32),
261    S64(i64),
262    U64(u64),
263    F32(f32),
264    F64(f64),
265    Char(u32),
266    String(wasm_name_t),
267    List(wasmtime_component_vallist_t),
268    Record(wasmtime_component_valrecord_t),
269    Tuple(wasmtime_component_valtuple_t),
270    Variant(wasmtime_component_valvariant_t),
271    Enum(wasm_name_t),
272    Option(Option<Box<Self>>),
273    Result(wasmtime_component_valresult_t),
274    Flags(wasmtime_component_valflags_t),
275    Resource(Box<wasmtime_component_resource_any_t>),
276    Map(wasmtime_component_valmap_t),
277    FixedLengthList(wasmtime_component_vallist_t),
278}
279
280// Safety: the C API async contract (documented in async.h) guarantees that
281// values are not concurrently accessed while a future is alive.
282unsafe impl Send for wasmtime_component_val_t {}
283
284impl Default for wasmtime_component_val_t {
285    fn default() -> Self {
286        Self::Bool(false)
287    }
288}
289
290impl From<&wasmtime_component_val_t> for Val {
291    fn from(value: &wasmtime_component_val_t) -> Self {
292        match value {
293            wasmtime_component_val_t::Bool(x) => Val::Bool(*x),
294            wasmtime_component_val_t::S8(x) => Val::S8(*x),
295            wasmtime_component_val_t::U8(x) => Val::U8(*x),
296            wasmtime_component_val_t::S16(x) => Val::S16(*x),
297            wasmtime_component_val_t::U16(x) => Val::U16(*x),
298            wasmtime_component_val_t::S32(x) => Val::S32(*x),
299            wasmtime_component_val_t::U32(x) => Val::U32(*x),
300            wasmtime_component_val_t::S64(x) => Val::S64(*x),
301            wasmtime_component_val_t::U64(x) => Val::U64(*x),
302            wasmtime_component_val_t::F32(x) => Val::Float32(*x),
303            wasmtime_component_val_t::F64(x) => Val::Float64(*x),
304            wasmtime_component_val_t::Char(x) => Val::Char(char::from_u32(*x).unwrap()),
305            wasmtime_component_val_t::String(x) => {
306                Val::String(String::from_utf8(x.clone().take()).unwrap())
307            }
308            wasmtime_component_val_t::List(x) => Val::List(x.into()),
309            wasmtime_component_val_t::Record(x) => Val::Record(x.into()),
310            wasmtime_component_val_t::Tuple(x) => Val::Tuple(x.into()),
311            wasmtime_component_val_t::Variant(x) => {
312                let (a, b) = x.into();
313                Val::Variant(a, b)
314            }
315            wasmtime_component_val_t::Enum(x) => {
316                Val::Enum(String::from_utf8(x.clone().take()).unwrap())
317            }
318            wasmtime_component_val_t::Option(x) => {
319                Val::Option(x.as_ref().map(|x| Box::new(Val::from(x.as_ref()))))
320            }
321            wasmtime_component_val_t::Result(x) => Val::Result(x.into()),
322            wasmtime_component_val_t::Flags(x) => Val::Flags(x.into()),
323            wasmtime_component_val_t::Map(x) => Val::Map(x.into()),
324            wasmtime_component_val_t::Resource(x) => Val::Resource(x.resource),
325            wasmtime_component_val_t::FixedLengthList(x) => Val::FixedLengthList(x.into()),
326        }
327    }
328}
329
330impl From<&Val> for wasmtime_component_val_t {
331    fn from(value: &Val) -> Self {
332        match value {
333            Val::Bool(x) => wasmtime_component_val_t::Bool(*x),
334            Val::S8(x) => wasmtime_component_val_t::S8(*x),
335            Val::U8(x) => wasmtime_component_val_t::U8(*x),
336            Val::S16(x) => wasmtime_component_val_t::S16(*x),
337            Val::U16(x) => wasmtime_component_val_t::U16(*x),
338            Val::S32(x) => wasmtime_component_val_t::S32(*x),
339            Val::U32(x) => wasmtime_component_val_t::U32(*x),
340            Val::S64(x) => wasmtime_component_val_t::S64(*x),
341            Val::U64(x) => wasmtime_component_val_t::U64(*x),
342            Val::Float32(x) => wasmtime_component_val_t::F32(*x),
343            Val::Float64(x) => wasmtime_component_val_t::F64(*x),
344            Val::Char(x) => wasmtime_component_val_t::Char(*x as _),
345            Val::String(x) => wasmtime_component_val_t::String(wasm_name_t::from_name(x.clone())),
346            Val::List(x) => wasmtime_component_val_t::List(x.as_slice().into()),
347            Val::Record(x) => wasmtime_component_val_t::Record(x.as_slice().into()),
348            Val::Tuple(x) => wasmtime_component_val_t::Tuple(x.as_slice().into()),
349            Val::Variant(discriminant, val) => {
350                wasmtime_component_val_t::Variant((discriminant, val).into())
351            }
352            Val::Enum(x) => wasmtime_component_val_t::Enum(wasm_name_t::from_name(x.clone())),
353            Val::Option(x) => wasmtime_component_val_t::Option(
354                x.as_ref()
355                    .map(|x| Box::new(wasmtime_component_val_t::from(x.as_ref()))),
356            ),
357            Val::Result(x) => wasmtime_component_val_t::Result(x.into()),
358            Val::Flags(x) => wasmtime_component_val_t::Flags(x.as_slice().into()),
359            Val::Map(x) => wasmtime_component_val_t::Map(x.as_slice().into()),
360            Val::Resource(resource_any) => {
361                wasmtime_component_val_t::Resource(Box::new(wasmtime_component_resource_any_t {
362                    resource: *resource_any,
363                }))
364            }
365            Val::Future(_) => todo!(),
366            Val::Stream(_) => todo!(),
367            Val::ErrorContext(_) => todo!(),
368            Val::FixedLengthList(ty) => wasmtime_component_val_t::FixedLengthList(
369                wasmtime_component_vallist_t::from(ty.as_ref()),
370            ),
371        }
372    }
373}
374
375#[unsafe(no_mangle)]
376pub extern "C" fn wasmtime_component_val_new(
377    src: &mut wasmtime_component_val_t,
378) -> Box<wasmtime_component_val_t> {
379    Box::new(mem::replace(src, wasmtime_component_val_t::default()))
380}
381
382#[unsafe(no_mangle)]
383pub extern "C" fn wasmtime_component_val_free(_dst: Option<Box<wasmtime_component_val_t>>) {}
384
385#[unsafe(no_mangle)]
386pub extern "C" fn wasmtime_component_val_clone(
387    src: &wasmtime_component_val_t,
388    dst: &mut MaybeUninit<wasmtime_component_val_t>,
389) {
390    dst.write(src.clone());
391}
392
393#[unsafe(no_mangle)]
394pub unsafe extern "C" fn wasmtime_component_val_delete(
395    value: &mut ManuallyDrop<wasmtime_component_val_t>,
396) {
397    unsafe {
398        ManuallyDrop::drop(value);
399    }
400}
401
402#[repr(C)]
403#[derive(Clone)]
404pub struct wasmtime_component_resource_any_t {
405    resource: ResourceAny,
406}
407
408#[unsafe(no_mangle)]
409pub extern "C" fn wasmtime_component_resource_any_type(
410    resource: &wasmtime_component_resource_any_t,
411) -> Box<wasmtime_component_resource_type_t> {
412    Box::new(wasmtime_component_resource_type_t {
413        ty: resource.resource.ty(),
414    })
415}
416
417#[unsafe(no_mangle)]
418pub extern "C" fn wasmtime_component_resource_any_clone(
419    resource: &wasmtime_component_resource_any_t,
420) -> Box<wasmtime_component_resource_any_t> {
421    Box::new(wasmtime_component_resource_any_t {
422        resource: resource.resource,
423    })
424}
425
426#[unsafe(no_mangle)]
427pub extern "C" fn wasmtime_component_resource_any_owned(
428    resource: &wasmtime_component_resource_any_t,
429) -> bool {
430    resource.resource.owned()
431}
432
433#[unsafe(no_mangle)]
434pub extern "C" fn wasmtime_component_resource_any_drop(
435    store: WasmtimeStoreContextMut<'_>,
436    resource: &wasmtime_component_resource_any_t,
437) -> Option<Box<wasmtime_error_t>> {
438    handle_result(resource.resource.resource_drop(store), |()| ())
439}
440
441#[unsafe(no_mangle)]
442pub extern "C" fn wasmtime_component_resource_any_delete(
443    _resource: Option<Box<wasmtime_component_resource_any_t>>,
444) {
445}
446
447#[repr(C)]
448pub struct wasmtime_component_resource_host_t {
449    resource: ResourceDynamic,
450}
451
452impl wasmtime_component_resource_host_t {
453    // "poor man's clone"
454    fn resource(&self) -> ResourceDynamic {
455        let rep = self.resource.rep();
456        let ty = self.resource.ty();
457        if self.resource.owned() {
458            ResourceDynamic::new_own(rep, ty)
459        } else {
460            ResourceDynamic::new_borrow(rep, ty)
461        }
462    }
463}
464
465#[unsafe(no_mangle)]
466pub extern "C" fn wasmtime_component_resource_host_new(
467    owned: bool,
468    rep: u32,
469    ty: u32,
470) -> Box<wasmtime_component_resource_host_t> {
471    Box::new(wasmtime_component_resource_host_t {
472        resource: if owned {
473            ResourceDynamic::new_own(rep, ty)
474        } else {
475            ResourceDynamic::new_borrow(rep, ty)
476        },
477    })
478}
479
480#[unsafe(no_mangle)]
481pub extern "C" fn wasmtime_component_resource_host_clone(
482    resource: &wasmtime_component_resource_host_t,
483) -> Box<wasmtime_component_resource_host_t> {
484    Box::new(wasmtime_component_resource_host_t {
485        resource: resource.resource(),
486    })
487}
488
489#[unsafe(no_mangle)]
490pub extern "C" fn wasmtime_component_resource_host_rep(
491    resource: &wasmtime_component_resource_host_t,
492) -> u32 {
493    resource.resource.rep()
494}
495
496#[unsafe(no_mangle)]
497pub extern "C" fn wasmtime_component_resource_host_type(
498    resource: &wasmtime_component_resource_host_t,
499) -> u32 {
500    resource.resource.ty()
501}
502
503#[unsafe(no_mangle)]
504pub extern "C" fn wasmtime_component_resource_host_owned(
505    resource: &wasmtime_component_resource_host_t,
506) -> bool {
507    resource.resource.owned()
508}
509
510#[unsafe(no_mangle)]
511pub extern "C" fn wasmtime_component_resource_host_delete(
512    _resource: Option<Box<wasmtime_component_resource_host_t>>,
513) {
514}
515
516#[unsafe(no_mangle)]
517pub extern "C" fn wasmtime_component_resource_any_to_host(
518    store: WasmtimeStoreContextMut<'_>,
519    resource: &wasmtime_component_resource_any_t,
520    ret: &mut MaybeUninit<Box<wasmtime_component_resource_host_t>>,
521) -> Option<Box<wasmtime_error_t>> {
522    handle_result(
523        resource.resource.try_into_resource_dynamic(store),
524        |resource| {
525            ret.write(Box::new(wasmtime_component_resource_host_t { resource }));
526        },
527    )
528}
529
530#[unsafe(no_mangle)]
531pub extern "C" fn wasmtime_component_resource_host_to_any(
532    store: WasmtimeStoreContextMut<'_>,
533    resource: &wasmtime_component_resource_host_t,
534    ret: &mut MaybeUninit<Box<wasmtime_component_resource_any_t>>,
535) -> Option<Box<wasmtime_error_t>> {
536    handle_result(
537        resource.resource().try_into_resource_any(store),
538        |resource| {
539            ret.write(Box::new(wasmtime_component_resource_any_t { resource }));
540        },
541    )
542}