Skip to content

c-api: component-model: Values and function calling #10697

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
358f78a
c-api: component-model: Primitive values
MangoPeachGrape Apr 29, 2025
1dad666
c-api: component-model: Function calling
MangoPeachGrape Apr 29, 2025
151581d
A test
MangoPeachGrape Apr 29, 2025
a20c540
Take args as mut to avoid copying
MangoPeachGrape Apr 29, 2025
ac9eb55
String and char
MangoPeachGrape Apr 29, 2025
77c103e
Rethink value ownership semantics, add list values
MangoPeachGrape May 5, 2025
13e9be6
Record values
MangoPeachGrape May 6, 2025
5040404
Make take Rust values as refs in `::from()` functions
MangoPeachGrape May 6, 2025
c2351c6
Define host functions
MangoPeachGrape May 6, 2025
c9f7a35
`wasmtime_component_valrecord_new()`
MangoPeachGrape May 6, 2025
c392a4e
Use `u32` instead of `char` as its not ffi safe
MangoPeachGrape May 6, 2025
8f422af
Test records and strings in c-api -> vm -> host func -> vm -> c-api
MangoPeachGrape May 11, 2025
9983d65
`wasmtime_component_vallist_new()`
MangoPeachGrape May 14, 2025
e644e3e
Test lists
MangoPeachGrape May 14, 2025
85f9c79
Fix formatting
MangoPeachGrape May 20, 2025
d9e81ef
Use existing `declare_vecs` construct
MangoPeachGrape May 22, 2025
73ec3c6
Add rest of helper functions
MangoPeachGrape May 22, 2025
c131719
Add documentation
MangoPeachGrape May 22, 2025
84f2298
Fix multiline comments
MangoPeachGrape May 22, 2025
50b0270
Third time's the charm
MangoPeachGrape May 22, 2025
01bc672
Fourth time's the charm prtest:full
MangoPeachGrape May 23, 2025
e8f72ef
Doxygen file headers
MangoPeachGrape May 23, 2025
c9fbe6b
Fix other missing documentation
MangoPeachGrape May 23, 2025
4f6c70c
Small fix to docs
MangoPeachGrape May 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/c-api/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ target_include_directories(

if (BUILD_TESTS)
message(STATUS "Building tests")
set(CMAKE_CXX_STANDARD 20)

enable_language(CXX)
set(INSTALL_GTEST OFF CACHE BOOL "" FORCE)
Expand Down
3 changes: 2 additions & 1 deletion crates/c-api/doxygen.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -949,7 +949,8 @@ EXCLUDE_SYMBOLS = assertions \
wasmtime::detail \
CASE_KIND_PRINT_NAME \
CASE_KIND_TO_C \
CASE_C_TO_KIND
CASE_C_TO_KIND \
DECLARE_VEC

# The EXAMPLE_PATH tag can be used to specify one or more files or directories
# that contain example code fragments that are included (see the \include
Expand Down
1 change: 1 addition & 0 deletions crates/c-api/include/wasmtime/component.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
#include <wasmtime/component/func.h>
#include <wasmtime/component/instance.h>
#include <wasmtime/component/linker.h>
#include <wasmtime/component/val.h>

#endif // WASMTIME_COMPONENT_H
6 changes: 4 additions & 2 deletions crates/c-api/include/wasmtime/component/component.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/// \file wasmtime/component/component.h

#ifndef WASMTIME_COMPONENT_COMPONENT_H
#define WASMTIME_COMPONENT_COMPONENT_H

Expand Down Expand Up @@ -101,13 +103,13 @@ WASM_API_EXTERN wasmtime_component_t *
wasmtime_component_clone(const wasmtime_component_t *component);

/**
* \brief Deletes a #wasmtime_component_t created by
* #wasmtime_component_from_binary
* \brief Deletes a #wasmtime_component_t created by #wasmtime_component_new
*
* \param component the component to delete
*/
WASM_API_EXTERN void wasmtime_component_delete(wasmtime_component_t *component);

/// A value which represents a known export of a component.
typedef struct wasmtime_component_export_index_t
wasmtime_component_export_index_t;

Expand Down
18 changes: 18 additions & 0 deletions crates/c-api/include/wasmtime/component/func.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
/// \file wasmtime/component/func.h

#ifndef WASMTIME_COMPONENT_FUNC_H
#define WASMTIME_COMPONENT_FUNC_H

#include <wasmtime/component/val.h>
#include <wasmtime/conf.h>
#include <wasmtime/error.h>
#include <wasmtime/store.h>

#ifdef WASMTIME_FEATURE_COMPONENT_MODEL

Expand All @@ -23,6 +28,19 @@ typedef struct wasmtime_component_func {
size_t index;
} wasmtime_component_func_t;

/// \brief Invokes \p func with the \p args given and returns the result.
///
/// The \p args provided must match the parameters that this function takes in
/// terms of their types and the number of parameters. Results will be written
/// to the \p results provided if the call completes successfully. The initial
/// types of the values in \p results are ignored and values are overwritten to
/// write the result. It's required that the \p results_size exactly matches the
/// number of results that this function produces.
WASM_API_EXTERN wasmtime_error_t *wasmtime_component_func_call(
const wasmtime_component_func_t *func, wasmtime_context_t *context,
const wasmtime_component_val_t *args, size_t args_size,
wasmtime_component_val_t *results, size_t results_size);

#ifdef __cplusplus
} // extern "C"
#endif
Expand Down
6 changes: 4 additions & 2 deletions crates/c-api/include/wasmtime/component/instance.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/// \file wasmtime/component/instance.h

#ifndef WASMTIME_COMPONENT_INSTANCE_H
#define WASMTIME_COMPONENT_INSTANCE_H

Expand Down Expand Up @@ -27,8 +29,8 @@ typedef struct wasmtime_component_instance {
} wasmtime_component_instance_t;

/**
* \brief A methods similar to \fn wasmtime_component_get_export_index() except
* for this instance.
* \brief A methods similar to #wasmtime_component_get_export_index except for
* this instance.
*
* \param instance the instance to look up \p name in
* \param context the context where \p instance lives in
Expand Down
30 changes: 29 additions & 1 deletion crates/c-api/include/wasmtime/component/linker.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/// \file wasmtime/component/linker.h

#ifndef WASMTIME_COMPONENT_LINKER_H
#define WASMTIME_COMPONENT_LINKER_H

Expand All @@ -14,7 +16,10 @@
extern "C" {
#endif

/// A type used to instantiate a #wasmtime_component_t.
typedef struct wasmtime_component_linker_t wasmtime_component_linker_t;

/// Structure representing an "instance" being defined within a linker.
typedef struct wasmtime_component_linker_instance_t
wasmtime_component_linker_instance_t;

Expand Down Expand Up @@ -82,7 +87,8 @@ wasmtime_component_linker_delete(wasmtime_component_linker_t *linker);
* \param linker_instance the linker instance from which the new one is created
* \param name new instance name
* \param name_len length of \p name in bytes
* \param linker_instance_out on success, the new #component_linker_instance_t
* \param linker_instance_out on success, the new
* #wasmtime_component_linker_instance_t
* \return on success `NULL`, otherwise an error
*/
WASM_API_EXTERN wasmtime_error_t *
Expand All @@ -108,6 +114,28 @@ WASM_API_EXTERN wasmtime_error_t *wasmtime_component_linker_instance_add_module(
wasmtime_component_linker_instance_t *linker_instance, const char *name,
size_t name_len, const wasmtime_module_t *module);

/// Type of the callback used in #wasmtime_component_linker_instance_add_func
typedef wasmtime_error_t *(*wasmtime_component_func_callback_t)(
void *, wasmtime_context_t *, const wasmtime_component_val_t *, size_t,
wasmtime_component_val_t *, size_t);

/**
* \brief Define a function within this instance.
*
* \param linker_instance the instance to define the function in
* \param name the module name
* \param name_len length of \p name in bytes
* \param callback the callback when this function gets called
* \param data host-specific data passed to the callback invocation, can be
* `NULL`
* \param finalizer optional finalizer for \p data, can be `NULL`
* \return on success `NULL`, otherwise an error
*/
WASM_API_EXTERN wasmtime_error_t *wasmtime_component_linker_instance_add_func(
wasmtime_component_linker_instance_t *linker_instance, const char *name,
size_t name_len, wasmtime_component_func_callback_t callback, void *data,
void (*finalizer)());

/**
* \brief Deletes a #wasmtime_component_linker_instance_t
*
Expand Down
157 changes: 157 additions & 0 deletions crates/c-api/include/wasmtime/component/val.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/// \file wasmtime/component/val.h

#ifndef WASMTIME_COMPONENT_VAL_H
#define WASMTIME_COMPONENT_VAL_H

#include <wasmtime/conf.h>

#ifdef WASMTIME_FEATURE_COMPONENT_MODEL

#ifdef __cplusplus
extern "C" {
#endif

/// \brief Discriminant used in #wasmtime_component_val_t::kind
typedef uint8_t wasmtime_component_valkind_t;

/// \brief Value of #wasmtime_component_valkind_t meaning that
/// #wasmtime_component_val_t is a bool
#define WASMTIME_COMPONENT_BOOL 0
/// \brief Value of #wasmtime_component_valkind_t meaning that
/// #wasmtime_component_val_t is a s8
#define WASMTIME_COMPONENT_S8 1
/// \brief Value of #wasmtime_component_valkind_t meaning that
/// #wasmtime_component_val_t is a u8
#define WASMTIME_COMPONENT_U8 2
/// \brief Value of #wasmtime_component_valkind_t meaning that
/// #wasmtime_component_val_t is a s16
#define WASMTIME_COMPONENT_S16 3
/// \brief Value of #wasmtime_component_valkind_t meaning that
/// #wasmtime_component_val_t is a u16
#define WASMTIME_COMPONENT_U16 4
/// \brief Value of #wasmtime_component_valkind_t meaning that
/// #wasmtime_component_val_t is a s32
#define WASMTIME_COMPONENT_S32 5
/// \brief Value of #wasmtime_component_valkind_t meaning that
/// #wasmtime_component_val_t is a u32
#define WASMTIME_COMPONENT_U32 6
/// \brief Value of #wasmtime_component_valkind_t meaning that
/// #wasmtime_component_val_t is a s64
#define WASMTIME_COMPONENT_S64 7
/// \brief Value of #wasmtime_component_valkind_t meaning that
/// #wasmtime_component_val_t is a u64
#define WASMTIME_COMPONENT_U64 8
/// \brief Value of #wasmtime_component_valkind_t meaning that
/// #wasmtime_component_val_t is a f32
#define WASMTIME_COMPONENT_F32 9
/// \brief Value of #wasmtime_component_valkind_t meaning that
/// #wasmtime_component_val_t is a f64
#define WASMTIME_COMPONENT_F64 10
/// \brief Value of #wasmtime_component_valkind_t meaning that
/// #wasmtime_component_val_t is a char
#define WASMTIME_COMPONENT_CHAR 11
/// \brief Value of #wasmtime_component_valkind_t meaning that
/// #wasmtime_component_val_t is a string
#define WASMTIME_COMPONENT_STRING 12
/// \brief Value of #wasmtime_component_valkind_t meaning that
/// #wasmtime_component_val_t is a list
#define WASMTIME_COMPONENT_LIST 13
/// \brief Value of #wasmtime_component_valkind_t meaning that
/// #wasmtime_component_val_t is a record
#define WASMTIME_COMPONENT_RECORD 14

struct wasmtime_component_val;
struct wasmtime_component_valrecord_entry;

#define DECLARE_VEC(name, type) \
/** \brief A vec of a type */ \
typedef struct name { \
/** Length of the vec */ \
size_t size; \
/** Pointer to the elements */ \
type *data; \
} name##_t; \
\
/** \brief Create vec from \p ptr and \p size */ \
WASM_API_EXTERN void name##_new(name##_t *out, size_t size, type *ptr); \
/** \brief Create an empty vec */ \
WASM_API_EXTERN void name##_new_empty(name##_t *out); \
/** \brief Create a vec with length \p size */ \
WASM_API_EXTERN void name##_new_uninit(name##_t *out, size_t size); \
/** \brief Copy \p src to \p dst */ \
WASM_API_EXTERN void name##_copy(name##_t *dst, const name##_t *src); \
/** \brief Delete \p value */ \
WASM_API_EXTERN void name##_delete(name##_t *value);

DECLARE_VEC(wasmtime_component_vallist, struct wasmtime_component_val)
DECLARE_VEC(wasmtime_component_valrecord,
struct wasmtime_component_valrecord_entry)

#undef DECLARE_VEC

/// \brief Represents possible runtime values which a component function can
/// either consume or produce
typedef union {
/// Field used if #wasmtime_component_val_t::kind is #WASMTIME_COMPONENT_BOOL
bool boolean;
/// Field used if #wasmtime_component_val_t::kind is #WASMTIME_COMPONENT_S8
int8_t s8;
/// Field used if #wasmtime_component_val_t::kind is #WASMTIME_COMPONENT_U8
uint8_t u8;
/// Field used if #wasmtime_component_val_t::kind is #WASMTIME_COMPONENT_S16
int16_t s16;
/// Field used if #wasmtime_component_val_t::kind is #WASMTIME_COMPONENT_U16
uint16_t u16;
/// Field used if #wasmtime_component_val_t::kind is #WASMTIME_COMPONENT_S32
int32_t s32;
/// Field used if #wasmtime_component_val_t::kind is #WASMTIME_COMPONENT_U32
uint32_t u32;
/// Field used if #wasmtime_component_val_t::kind is #WASMTIME_COMPONENT_S64
int64_t s64;
/// Field used if #wasmtime_component_val_t::kind is #WASMTIME_COMPONENT_U64
uint64_t u64;
/// Field used if #wasmtime_component_val_t::kind is #WASMTIME_COMPONENT_F32
float32_t f32;
/// Field used if #wasmtime_component_val_t::kind is #WASMTIME_COMPONENT_F64
float64_t f64;
/// Field used if #wasmtime_component_val_t::kind is #WASMTIME_COMPONENT_CHAR
uint32_t character;
/// Field used if #wasmtime_component_val_t::kind is
/// #WASMTIME_COMPONENT_STRING
wasm_name_t string;
/// Field used if #wasmtime_component_val_t::kind is #WASMTIME_COMPONENT_LIST
wasmtime_component_vallist_t list;
/// Field used if #wasmtime_component_val_t::kind is
/// #WASMTIME_COMPONENT_RECORD
wasmtime_component_valrecord_t record;
} wasmtime_component_valunion_t;

/// \brief Represents possible runtime values which a component function can
/// either consume or produce
typedef struct wasmtime_component_val {
/// The type discriminant
wasmtime_component_valkind_t kind;
/// Value of type \ref kind
wasmtime_component_valunion_t of;
} wasmtime_component_val_t;

/// \brief A pair of a name and a value that represents one entry in a value
/// with kind #WASMTIME_COMPONENT_RECORD
typedef struct wasmtime_component_valrecord_entry {
/// The name of this entry
wasm_name_t name;
/// The value of this entry
wasmtime_component_val_t val;
} wasmtime_component_valrecord_entry_t;

/// \brief Calls the destructor on \p value deallocating any owned memory
WASM_API_EXTERN void
wasmtime_component_val_delete(wasmtime_component_val_t *value);

#ifdef __cplusplus
} // extern "C"
#endif

#endif // WASMTIME_FEATURE_COMPONENT_MODEL

#endif // WASMTIME_COMPONENT_VAL_H
31 changes: 31 additions & 0 deletions crates/c-api/src/component/func.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use wasmtime::component::{Func, Val};

use crate::{WasmtimeStoreContextMut, wasmtime_error_t};

use super::wasmtime_component_val_t;

#[unsafe(no_mangle)]
pub unsafe extern "C" fn wasmtime_component_func_call(
func: &Func,
mut context: WasmtimeStoreContextMut<'_>,
args: *const wasmtime_component_val_t,
args_len: usize,
results: *mut wasmtime_component_val_t,
results_len: usize,
) -> Option<Box<wasmtime_error_t>> {
let c_args = unsafe { std::slice::from_raw_parts(args, args_len) };
let c_results = unsafe { std::slice::from_raw_parts_mut(results, results_len) };

let args = c_args.iter().map(Val::from).collect::<Vec<_>>();
let mut results = vec![Val::Bool(false); results_len];

let result = func
.call(&mut context, &args, &mut results)
.and_then(|_| func.post_return(&mut context));

crate::handle_result(result, |_| {
for (c_val, rust_val) in std::iter::zip(c_results, results) {
*c_val = wasmtime_component_val_t::from(&rust_val);
}
})
}
Loading
Loading