barretenberg
Loading...
Searching...
No Matches
cbind.hpp
1#pragma once
2// Meant to be the main header included by translation units that use msgpack.
3// Note: heavy header due to serialization logic, don't include if msgpack.hpp will do
4// CBinding helpers that take a function or a lambda and
5// - bind the input as a coded msgpack array of all the arguments (using template metamagic)
6// - bind the return value to an out buffer, where the caller must free the memory
7
8#include "msgpack_impl/check_memory_span.hpp"
9#include "msgpack_impl/concepts.hpp"
10#include "msgpack_impl/func_traits.hpp"
11#include "msgpack_impl/msgpack_impl.hpp"
12#include "msgpack_impl/name_value_pair_macro.hpp"
13#include "msgpack_impl/schema_impl.hpp"
14#include "msgpack_impl/schema_name.hpp"
15#include "msgpack_impl/struct_map_impl.hpp"
16
17#include <cstring>
18#include <type_traits>
19
25inline std::pair<uint8_t*, size_t> msgpack_encode_buffer(auto&& obj)
26{
27 // Create a buffer to store the encoded data
28 msgpack::sbuffer buffer;
29 msgpack::pack(buffer, obj);
30
31 uint8_t* output = (uint8_t*)aligned_alloc(64, buffer.size());
32 memcpy(output, buffer.data(), buffer.size());
33 // Convert the buffer data to a string and return it
34 return { output, buffer.size() };
35}
36
37// This is a template function that will return the argument types
38// of a given function type T as a tuple.
39template <typename T> constexpr auto param_tuple()
40{
41 // decltype is used to determine the type of the expression at compile-time.
42 // get_func_traits<T>() is assumed to return a structure whose ::Args member is a tuple
43 // of argument types of function T. This function constructs an instance of that tuple and returns it.
44 return typename decltype(get_func_traits<T>())::Args{};
45}
46
47// This function is intended to bind a function to a MessagePack-formatted input data,
48// perform the function with the unpacked data, then pack the result back into MessagePack format.
49inline void msgpack_cbind_impl(auto func, // The function to be applied
50 const uint8_t* input_in, // The input data in MessagePack format
51 size_t input_len_in, // The length of the input data
52 uint8_t** output_out, // The output data in MessagePack format
53 size_t* output_len_out) // The length of the output data
54{
55 // Get the parameter types of the function as a tuple.
56 auto params = param_tuple<decltype(func)>();
57
58 // Unpack the input data into the parameter tuple.
59 // msgpack::unpack takes a buffer and its size, and returns an object_handle.
60 // Calling .get() on that handle yields an object, and calling .convert on that
61 // object converts it into the given type, in this case, the parameter tuple for func.
62 msgpack::unpack((const char*)input_in, input_len_in).get().convert(params);
63
64 // Apply the function to the parameters, then encode the result into a MessagePack buffer.
65 // std::apply takes a function and a tuple, and applies the function to the tuple's elements.
66 // msgpack_encode_buffer is assumed to take the result of the function and return a pair
67 // consisting of a pointer to the output buffer and its size.
68 auto [output, output_len] = msgpack_encode_buffer(std::apply(func, params));
69
70 // Assign the output data and its length to the given output parameters.
71 *output_out = output;
72 *output_len_out = output_len;
73}
74
75// returns a C-style string json of the schema
76inline void msgpack_cbind_schema_impl(auto func, uint8_t** output_out, size_t* output_len_out)
77{
78 (void)func; // unused except for type
79 // Object representation of the cbind
80 auto cbind_obj = get_func_traits<decltype(func)>();
81 std::string schema = msgpack_schema_to_string(cbind_obj);
82 *output_out = (uint8_t*)aligned_alloc(64, schema.size() + 1);
83 memcpy(*output_out, schema.c_str(), schema.size() + 1);
84 *output_len_out = schema.size();
85}
86
87// The CBIND_NOSCHEMA macro generates a function named 'cname' that decodes the input arguments from msgpack format,
88// calls the target function, and then encodes the return value back into msgpack format. It should be used over CBIND
89// in cases where we do not want schema generation, such as meta-functions that themselves give information to control
90// how the schema is interpreted.
91#define CBIND_NOSCHEMA(cname, func) \
92 WASM_EXPORT void cname(const uint8_t* input_in, size_t input_len_in, uint8_t** output_out, size_t* output_len_out) \
93 { \
94 msgpack_cbind_impl(func, input_in, input_len_in, output_out, output_len_out); \
95 }
96
97// The CBIND macro is a convenient utility that abstracts away several steps in binding C functions with msgpack
98// serialization. It creates two separate functions:
99// 1. cname function: This decodes the input arguments from msgpack format, calls the target function,
100// and then encodes the return value back into msgpack format.
101// 2. cname##__schema function: This creates a JSON schema of the function's input arguments and return type.
102#define CBIND(cname, func) \
103 CBIND_NOSCHEMA(cname, func) \
104 WASM_EXPORT void cname##__schema(uint8_t** output_out, size_t* output_len_out) \
105 { \
106 msgpack_cbind_schema_impl(func, output_out, output_len_out); \
107 }