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