Affix
view release on metacpan or search on metacpan
infix/include/infix/infix.h view on Meta::CPAN
* #define infix_malloc my_custom_malloc
* #define infix_calloc my_custom_calloc
* #define infix_free my_custom_free
* #define infix_realloc my_custom_realloc
* #include <infix/infix.h>
* @endcode
*/
#ifndef infix_malloc
#define infix_malloc malloc
#endif
/** @brief A macro that can be defined to override the default `calloc` function. */
#ifndef infix_calloc
#define infix_calloc calloc
#endif
/** @brief A macro that can be defined to override the default `realloc` function. */
#ifndef infix_realloc
#define infix_realloc realloc
#endif
/** @brief A macro that can be defined to override the default `free` function. */
#ifndef infix_free
#define infix_free free
#endif
/** @brief A macro that can be defined to override the default `memcpy` function. */
#ifndef infix_memcpy
#define infix_memcpy memcpy
#endif
/** @brief A macro that can be defined to override the default `memset` function. */
#ifndef infix_memset
#define infix_memset memset
#endif
/** @} */ // end of memory_management group
/**
* @addtogroup high_level_api
* @{
*/
/**
* @brief A function pointer type for an unbound forward trampoline.
* @details This is the callable code generated by `infix_forward_create_unbound`. It takes the
* target function as its first argument, allowing it to be reused for any C
* function that matches the signature it was created with.
*
* @param target_function The native C function to call.
* @param return_value_ptr A pointer to a buffer to receive the return value. Can be `nullptr` if the return type is
* `void`.
* @param args_array An array of pointers, where each element points to an argument's value.
*/
typedef void (*infix_unbound_cif_func)(void *, void *, void **);
/**
* @brief A function pointer type for a bound forward trampoline.
* @details This is the callable code generated by `infix_forward_create`. The target
* C function is "bound" into the JIT-compiled code, offering higher performance.
*
* @param return_value_ptr A pointer to a buffer to receive the return value. Can be `nullptr` for `void` returns.
* @param args_array An array of pointers, where each element points to an argument's value.
*/
typedef void (*infix_cif_func)(void *, void **);
/**
* @brief A function pointer type for a generic closure handler.
*
* This handler is used with `infix_reverse_create_closure` and is ideal for language
* bindings or stateful callbacks where the handler needs access to user-provided data.
*
* @param context The reverse trampoline context, from which `user_data` can be retrieved via
* `infix_reverse_get_user_data`.
* @param return_value_ptr A pointer to a buffer where the handler must write the function's return value.
* @param args_array An array of pointers to the argument values passed by the native C caller.
*/
typedef void (*infix_closure_handler_fn)(infix_context_t *, void *, void **);
/**
* @brief Enumerates the possible status codes returned by `infix` API functions.
*/
typedef enum {
INFIX_SUCCESS = 0, /**< The operation completed successfully. */
INFIX_ERROR_ALLOCATION_FAILED, /**< A memory allocation failed. Check `infix_get_last_error` for details. */
INFIX_ERROR_INVALID_ARGUMENT, /**< An invalid argument was provided. Check `infix_get_last_error`. */
INFIX_ERROR_UNSUPPORTED_ABI, /**< The current platform's ABI is not supported. */
INFIX_ERROR_LAYOUT_FAILED, /**< Failed to calculate a valid memory layout for a type. */
INFIX_ERROR_PROTECTION_FAILED, /**< Failed to set memory protection flags (e.g., for W^X). */
INFIX_ERROR_ /**< Placeholder to ensure enum is sized correctly. */
} infix_status;
/**
* @defgroup registry_api Named Type Registry
* @brief APIs for defining, storing, and reusing complex types by name.
* @ingroup high_level_api
* @{
*/
/**
* @brief Creates a new, empty named type registry.
*
* A registry acts as a dictionary for `infix` types, allowing you to define complex
* structs, unions, or aliases once and refer to them by name (e.g., `@MyStruct`)
* in any signature string. This is essential for managing complex, recursive, or
* mutually-dependent types.
*
* @return A pointer to the new registry, or `nullptr` on allocation failure. The returned
* handle must be freed with `infix_registry_destroy`.
*/
INFIX_API INFIX_NODISCARD infix_registry_t * infix_registry_create(void);
/**
* @brief Creates a deep copy of an existing type registry.
*
* This copies all defined types and their dependency graphs into a new registry with its own arena.
* This is essential for thread safety in languages that spawn threads by cloning interpreter state (like Perl).
*
* @param[in] registry The registry to clone.
* @return A pointer to the new registry, or `nullptr` on failure.
*/
INFIX_API INFIX_NODISCARD infix_registry_t * infix_registry_clone(const infix_registry_t *);
/**
* @brief Destroys a type registry and frees all associated memory.
*
* This includes freeing the registry handle itself, its internal hash table, and
* all `infix_type` objects that were created as part of a definition.
*
* @param[in] registry The registry to destroy. Safe to call with `nullptr`.
*/
INFIX_API void infix_registry_destroy(infix_registry_t *);
/**
* @brief Parses a string of type definitions and adds them to a registry.
*
* This is the primary way to populate a registry. Definitions are separated by
infix/include/infix/infix.h view on Meta::CPAN
*
* When the `target_arena` is the same as the registry's arena, this function
* will share pointers to named types instead of deep-copying them, saving memory.
*
* @param[out] out_trampoline Receives the created trampoline handle.
* @param[in] target_arena The arena to use for the trampoline's internal metadata.
* @param[in] signature The signature string of the target function.
* @param[in] target_function The address of the C function to be called.
* @param[in] registry An optional type registry.
* @return `INFIX_SUCCESS` on success.
*/
INFIX_API INFIX_NODISCARD infix_status
infix_forward_create_in_arena(infix_forward_t **, infix_arena_t *, const char *, void *, infix_registry_t *);
/**
* @brief Creates a type-safe reverse trampoline (callback).
*
* @details This function generates a native C function pointer that, when called by
* external C code, will invoke your `user_callback_fn`. This API is designed
* primarily for C/C++ developers, as the provided handler function must have a
* clean, type-safe C signature that exactly matches the one described in the
* `signature` string. This provides a high level of convenience and compile-time safety.
*
* @param[out] out_context A pointer to an `infix_reverse_t*` that will receive the
* created context handle.
* @param[in] signature The signature of the function pointer to be created (e.g., `"(int, int)->int"`).
* @param[in] user_callback_fn A pointer to a C function with a matching signature to handle the call.
* @param[in] registry An optional type registry.
* @return `INFIX_SUCCESS` on success.
* @note The caller is responsible for destroying the handle with `infix_reverse_destroy`.
*
* @code
* // Define the type-safe C handler function.
* // Its signature must match "(int, int)->int".
* int my_handler(int a, int b) {
* return a * b;
* }
*
* // Create the reverse trampoline.
* infix_reverse_t* ctx = NULL;
* infix_reverse_create_callback(&ctx, "(int,int)->int", (void*)my_handler, NULL);
*
* // Get the JIT-compiled C function pointer.
* typedef int (*my_func_ptr_t)(int, int);
* my_func_ptr_t func_ptr = (my_func_ptr_t)infix_reverse_get_code(ctx);
*
* // Pass this `func_ptr` to some C library that expects a callback.
* // some_c_library_function(func_ptr);
* // When the library calls func_ptr(5, 10), `my_handler` will be invoked
* // and will return 50.
*
* infix_reverse_destroy(ctx);
* @endcode
*/
INFIX_API INFIX_NODISCARD infix_status infix_reverse_create_callback(infix_reverse_t **,
const char *,
void *,
infix_registry_t *);
/**
* @brief Creates a generic reverse trampoline (closure) for stateful callbacks.
*
* @details This is the low-level API for reverse calls, designed for language bindings
* and advanced use cases. The handler function has a generic signature
* (`infix_closure_handler_fn`) and receives arguments as a `void**` array.
* A `user_data` pointer can be provided to maintain state between calls, making it
* a "closure".
*
* This is the most flexible way to handle callbacks, as it allows the handler
* to be implemented in another language and to access state associated with the
* callback object.
*
* @param[out] out_context A pointer to an `infix_reverse_t*` that will receive the
* created context handle.
* @param[in] signature The signature of the function pointer to be created.
* @param[in] user_callback_fn A pointer to a generic `infix_closure_handler_fn`.
* @param[in] user_data A `void*` pointer to application-specific state. This pointer
* can be retrieved inside the handler via `infix_reverse_get_user_data(context)`.
* @param[in] registry An optional type registry.
* @return `INFIX_SUCCESS` on success.
* @note The caller is responsible for destroying the handle with `infix_reverse_destroy`.
*
* @code
* // User-defined state for our closure.
* typedef struct {
* int call_count;
* } my_state_t;
*
* // Define the generic closure handler.
* void my_closure_handler(infix_context_t* ctx, void* ret_val, void** args) {
* // Retrieve our state.
* my_state_t* state = (my_state_t*)infix_reverse_get_user_data(ctx);
* state->call_count++;
*
* // Unpack arguments from the void** array.
* int a = *(int*)args[0];
* int b = *(int*)args[1];
*
* // Perform the operation and write to the return value buffer.
* int result = (a + b) * state->call_count;
* memcpy(ret_val, &result, sizeof(int));
* }
*
* // Create the state and the closure.
* my_state_t my_state = { .call_count = 0 };
* infix_reverse_t* ctx = NULL;
* infix_reverse_create_closure(&ctx, "(int,int)->int", my_closure_handler, &my_state, NULL);
*
* // Get the JIT-compiled C function pointer.
* int (*func_ptr)(int, int) = infix_reverse_get_code(ctx);
*
* // Pass the func_ptr to C code.
* int result1 = func_ptr(10, 5); // result1 is (10+5)*1 = 15
* int result2 = func_ptr(2, 3); // result2 is (2+3)*2 = 10
*
* infix_reverse_destroy(ctx);
* @endcode
*/
INFIX_API INFIX_NODISCARD infix_status
infix_reverse_create_closure(infix_reverse_t **, const char *, infix_closure_handler_fn, void *, infix_registry_t *);
/**
* @brief Parses a full function signature string into its constituent parts.
*
infix/include/infix/infix.h view on Meta::CPAN
*/
INFIX_API INFIX_NODISCARD infix_status infix_type_from_signature(infix_type **,
infix_arena_t **,
const char *,
infix_registry_t *);
/** @} */ // end of high_level_api group
/**
* @defgroup exports_api Dynamic Library & Globals API
* @brief Cross-platform functions for loading shared libraries and accessing exported symbols.
* @{
*/
/**
* @brief Opens a dynamic library and returns a handle to it.
* @param[in] path The file path to the library (e.g., `./mylib.so`, `user32.dll`).
* @return A handle to the library, or `nullptr` on failure. The handle must be freed with `infix_library_close`.
*/
INFIX_API INFIX_NODISCARD infix_library_t * infix_library_open(const char *);
/**
* @brief Closes a dynamic library handle.
* @param[in] lib The library handle to close. Safe to call with `nullptr`.
*/
INFIX_API void infix_library_close(infix_library_t *);
/**
* @brief Retrieves the address of a symbol (function or variable) from a loaded library.
* @param[in] lib The library handle.
* @param[in] symbol_name The name of the symbol to look up.
* @return A pointer to the symbol's address, or `nullptr` if not found.
*/
INFIX_API INFIX_NODISCARD void * infix_library_get_symbol(infix_library_t *, const char *);
/**
* @brief Reads the value of a global variable from a library into a buffer.
*
* Uses the signature parser to determine the size of the variable to ensure the
* correct number of bytes are copied.
*
* @param[in] lib The library handle.
* @param[in] symbol_name The name of the global variable.
* @param[in] type_signature The `infix` signature string describing the variable's type.
* @param[out] buffer A pointer to the destination buffer to receive the data.
* @param[in] registry An optional registry for resolving named types in the signature.
* @return `INFIX_SUCCESS` on success, or an error code on failure.
*/
INFIX_API INFIX_NODISCARD infix_status
infix_read_global(infix_library_t *, const char *, const char *, void *, infix_registry_t *);
/**
* @brief Writes data from a buffer into a global variable in a library.
* @param[in] lib The library handle.
* @param[in] symbol_name The name of the global variable.
* @param[in] type_signature The `infix` signature string describing the variable's type.
* @param[in] buffer A pointer to the source buffer containing the data to write.
* @param[in] registry An optional registry for resolving named types in the signature.
* @return `INFIX_SUCCESS` on success, or an error code on failure.
*/
INFIX_API INFIX_NODISCARD infix_status
infix_write_global(infix_library_t *, const char *, const char *, void *, infix_registry_t *);
/** @} */ // end of exports_api group
/**
* @defgroup manual_api Manual API
* @brief A lower-level, programmatic API for creating trampolines from `infix_type` objects.
*
* This API is intended for performance-critical applications or language bindings that
* need to construct type information dynamically without the overhead of string parsing.
* All `infix_type` objects passed to these functions must be allocated from an `infix_arena_t`.
* @{
*/
/**
* @brief Creates a bound forward trampoline from `infix_type` objects.
* @param[out] out_trampoline Receives the created trampoline handle.
* @param[in] return_type The `infix_type` for the function's return value.
* @param[in] arg_types An array of `infix_type*` for the function's arguments.
* @param[in] num_args The number of arguments.
* @param[in] num_fixed_args The number of non-variadic arguments.
* @param[in] target_function The address of the C function to call.
* @return `INFIX_SUCCESS` on success.
*/
INFIX_API INFIX_NODISCARD infix_status
infix_forward_create_manual(infix_forward_t **, infix_type *, infix_type **, size_t, size_t, void *);
/**
* @brief Creates an unbound forward trampoline from `infix_type` objects.
* @param[out] out_trampoline Receives the created trampoline handle.
* @param[in] return_type The `infix_type` for the function's return value.
* @param[in] arg_types An array of `infix_type*` for the function's arguments.
* @param[in] num_args The number of arguments.
* @param[in] num_fixed_args The number of non-variadic arguments.
* @return `INFIX_SUCCESS` on success.
*/
INFIX_API INFIX_NODISCARD infix_status
infix_forward_create_unbound_manual(infix_forward_t **, infix_type *, infix_type **, size_t, size_t);
/**
* @brief Creates a type-safe reverse trampoline (callback) from `infix_type` objects.
* @param[out] out_context Receives the created context handle.
* @param[in] return_type The function's return type.
* @param[in] arg_types An array of argument types.
* @param[in] num_args The number of arguments.
* @param[in] num_fixed_args The number of non-variadic arguments.
* @param[in] user_callback_fn A pointer to the type-safe C handler function.
* @return `INFIX_SUCCESS` on success.
*/
INFIX_API INFIX_NODISCARD infix_status
infix_reverse_create_callback_manual(infix_reverse_t **, infix_type *, infix_type **, size_t, size_t, void *);
/**
* @brief Creates a generic reverse trampoline (closure) from `infix_type` objects.
* @param[out] out_context Receives the created context handle.
* @param[in] return_type The function's return type.
* @param[in] arg_types An array of argument types.
* @param[in] num_args The number of arguments.
* @param[in] num_fixed_args The number of non-variadic arguments.
* @param[in] user_callback_fn A pointer to the generic `infix_closure_handler_fn`.
* @param[in] user_data A `void*` pointer to application-specific state.
* @return `INFIX_SUCCESS` on success.
*/
INFIX_API INFIX_NODISCARD infix_status infix_reverse_create_closure_manual(
infix_reverse_t **, infix_type *, infix_type **, size_t, size_t, infix_closure_handler_fn, void *);
/**
* @brief Destroys a forward trampoline and frees all associated memory.
* @param[in] trampoline The trampoline to destroy. Safe to call with `nullptr`.
*/
INFIX_API void infix_forward_destroy(infix_forward_t *);
/**
* @brief Destroys a reverse trampoline and frees all associated memory.
* @param[in] reverse_trampoline The reverse trampoline context to destroy. Safe to call with `nullptr`.
infix/include/infix/infix.h view on Meta::CPAN
INFIX_API INFIX_NODISCARD infix_status infix_type_create_vector(infix_arena_t *, infix_type **, infix_type *, size_t);
/**
* @brief A factory function to create an `infix_struct_member`.
* @param[in] name The name of the member (optional, can be `nullptr`).
* @param[in] type The `infix_type` of the member.
* @param[in] offset The byte offset of the member. This is ignored by `infix_type_create_struct`.
* @return An initialized `infix_struct_member` object.
*/
INFIX_API infix_struct_member infix_type_create_member(const char *, infix_type *, size_t);
/**
* @brief A factory function to create a bitfield `infix_struct_member`.
* @param[in] name The name of the member.
* @param[in] type The integer `infix_type` of the bitfield.
* @param[in] offset The byte offset (usually calculated automatically, so 0 is fine for automatic layout).
* @param[in] bit_width The width of the bitfield in bits.
* @return An initialized `infix_struct_member` object with bitfield metadata.
*/
INFIX_API infix_struct_member infix_type_create_bitfield_member(const char *, infix_type *, size_t, uint8_t);
/** @} */ // end of manual_api group (continued)
/** @} */ // end of type_system group
/**
* @addtogroup memory_management
* @{
*/
/**
* @brief Creates a new memory arena.
* @details An arena is a fast, region-based allocator. All objects allocated from it
* are freed at once when the arena is destroyed. This is the required mechanism for
* creating types for the Manual API.
* @param[in] initial_size The initial capacity of the arena in bytes.
* @return A pointer to the new arena, or `nullptr` on failure. The caller must free this with `infix_arena_destroy`.
*/
INFIX_API INFIX_NODISCARD infix_arena_t * infix_arena_create(size_t);
/**
* @brief Destroys an arena and frees all memory allocated from it.
* @param[in] arena The arena to destroy. Safe to call with `nullptr`.
*/
INFIX_API void infix_arena_destroy(infix_arena_t *);
/**
* @brief Allocates a block of memory from an arena.
* @param[in] arena The arena to allocate from.
* @param[in] size The number of bytes to allocate.
* @param[in] alignment The required alignment for the allocation. Must be a power of two.
* @return A pointer to the allocated memory, or `nullptr` on failure.
*/
INFIX_API INFIX_NODISCARD void * infix_arena_alloc(infix_arena_t *, size_t, size_t);
/**
* @brief Allocates and zero-initializes a block of memory from an arena.
* @param[in] arena The arena to allocate from.
* @param[in] num The number of elements.
* @param[in] size The size of each element.
* @param[in] alignment The required alignment. Must be a power of two.
* @return A pointer to the zero-initialized memory, or `nullptr` on failure.
*/
INFIX_API INFIX_NODISCARD void * infix_arena_calloc(infix_arena_t *, size_t, size_t, size_t);
/** @} */ // end of memory_management group (continued)
/**
* @defgroup introspection_api Introspection API
* @brief Functions for inspecting the properties of trampolines and `infix_type` objects at runtime.
*
* This API is essential for building dynamic language bindings, serializers, or any
* tool that needs to understand the memory layout and signature of C data structures
* and functions.
* @{
*/
/**
* @brief Specifies the output format for printing types and function signatures.
*/
typedef enum {
INFIX_DIALECT_SIGNATURE, /**< The standard, human-readable `infix` signature format. */
INFIX_DIALECT_ITANIUM_MANGLING, /**< (Not yet implemented) Itanium C++ ABI name mangling. */
INFIX_DIALECT_MSVC_MANGLING /**< (Not yet implemented) MSVC C++ name mangling. */
} infix_print_dialect_t;
/**
* @brief Serializes an `infix_type` object graph back into a signature string.
* @param[out] buffer The output buffer to write the string into.
* @param[in] buffer_size The size of the output buffer.
* @param[in] type The `infix_type` to print.
* @param[in] dialect The desired output format dialect.
* @return `INFIX_SUCCESS` on success, or `INFIX_ERROR_INVALID_ARGUMENT` if the buffer is too small.
*/
INFIX_API INFIX_NODISCARD infix_status infix_type_print(char *, size_t, const infix_type *, infix_print_dialect_t);
/**
* @brief Serializes a function signature's components into a string.
* @param[out] buffer The output buffer.
* @param[in] buffer_size The size of the output buffer.
* @param[in] function_name Optional name for dialects that support it.
* @param[in] ret_type The return type.
* @param[in] args The array of arguments.
* @param[in] num_args The total number of arguments.
* @param[in] num_fixed_args The number of fixed arguments.
* @param[in] dialect The output dialect.
* @return `INFIX_SUCCESS` on success, or `INFIX_ERROR_INVALID_ARGUMENT` if the buffer is too small.
*/
INFIX_API INFIX_NODISCARD infix_status infix_function_print(char *,
size_t,
const char *,
const infix_type *,
const infix_function_argument *,
size_t,
size_t,
infix_print_dialect_t);
/**
* @brief Gets the callable function pointer from an unbound forward trampoline.
* @param[in] trampoline The unbound `infix_forward_t` handle.
* @return A callable `infix_unbound_cif_func` pointer on success, or `nullptr` if the
* trampoline is `nullptr` or if it is a bound trampoline.
*/
INFIX_API INFIX_NODISCARD infix_unbound_cif_func infix_forward_get_unbound_code(infix_forward_t *);
/**
* @brief Gets the callable function pointer from a bound forward trampoline.
* @param[in] trampoline The bound `infix_forward_t` handle.
* @return A callable `infix_cif_func` pointer on success, or `nullptr` if the
* trampoline is `nullptr` or if it is an unbound trampoline.
*/
INFIX_API INFIX_NODISCARD infix_cif_func infix_forward_get_code(infix_forward_t *);
/**
* @brief Gets the native, callable C function pointer from a reverse trampoline.
* @param[in] reverse_trampoline The `infix_reverse_t` context handle.
* @return A `void*` that can be cast to the appropriate C function pointer type and called.
* The returned pointer is valid for the lifetime of the context handle.
infix/include/infix/infix.h view on Meta::CPAN
} infix_error_category_t;
/**
* @brief Enumerates specific error codes.
*/
typedef enum {
// General Codes (0-99)
INFIX_CODE_SUCCESS = 0, /**< No error occurred. */
INFIX_CODE_UNKNOWN, /**< An unspecified error occurred. */
INFIX_CODE_NULL_POINTER, /**< A required pointer argument was NULL. */
INFIX_CODE_MISSING_REGISTRY, /**< A type registry was required but not provided. */
INFIX_CODE_NATIVE_EXCEPTION, /**< A native exception (C++/SEH) was thrown during execution. */
// Allocation Codes (100-199)
INFIX_CODE_OUT_OF_MEMORY = 100, /**< A call to `malloc`, `calloc`, etc. failed. */
INFIX_CODE_EXECUTABLE_MEMORY_FAILURE, /**< Failed to allocate executable memory from the OS. */
INFIX_CODE_PROTECTION_FAILURE, /**< Failed to change memory protection flags (e.g., `mprotect`). */
INFIX_CODE_INVALID_ALIGNMENT, /**< An invalid alignment (0 or not power-of-two) was requested. */
// Parser Codes (200-299)
INFIX_CODE_UNEXPECTED_TOKEN = 200, /**< Encountered an unexpected character or token. */
INFIX_CODE_UNTERMINATED_AGGREGATE, /**< A struct, union, or array was not properly closed. */
INFIX_CODE_INVALID_KEYWORD, /**< An unknown or misspelled type keyword was used. */
INFIX_CODE_MISSING_RETURN_TYPE, /**< A function signature was missing the '->' and return type. */
INFIX_CODE_INTEGER_OVERFLOW, /**< An integer overflow occurred during layout calculation. */
INFIX_CODE_RECURSION_DEPTH_EXCEEDED, /**< A type definition was too deeply nested. */
INFIX_CODE_EMPTY_MEMBER_NAME, /**< A named member was declared with an empty name. */
INFIX_CODE_EMPTY_SIGNATURE, /**< The provided signature string was empty. */
// ABI/Layout Codes (300-399)
INFIX_CODE_UNSUPPORTED_ABI = 300, /**< The current platform's ABI is not supported by `infix`. */
INFIX_CODE_TYPE_TOO_LARGE, /**< A data type exceeded the ABI's size limits. */
INFIX_CODE_UNRESOLVED_NAMED_TYPE, /**< A named type (`@Name`) was not found in the provided registry. */
INFIX_CODE_INVALID_MEMBER_TYPE, /**< An aggregate contained an illegal member type (e.g., `void`). */
INFIX_CODE_LAYOUT_FAILED, /**< The ABI layer failed to calculate a valid memory layout for a type. */
// Library Loading Codes (400-499)
INFIX_CODE_LIBRARY_NOT_FOUND = 400, /**< The requested dynamic library could not be found. */
INFIX_CODE_SYMBOL_NOT_FOUND, /**< The requested symbol was not found in the library. */
INFIX_CODE_LIBRARY_LOAD_FAILED /**< The dynamic library failed to load for other reasons. */
} infix_error_code_t;
/**
* @struct infix_error_details_t
* @brief Provides detailed, thread-local information about the last error that occurred.
*/
typedef struct {
infix_error_category_t category; /**< The general category of the error. */
infix_error_code_t code; /**< The specific error code. */
size_t position; /**< For parser errors, the byte offset into the signature string. */
long system_error_code; /**< The OS-specific error code (e.g., from `GetLastError()` or `errno`). */
char message[256]; /**< A human-readable description of the error. For parser errors, this includes a code snippet.
*/
} infix_error_details_t;
/**
* @brief Retrieves detailed information about the last error that occurred on the current thread.
* @return A copy of the last error details structure. This function is thread-safe.
*/
INFIX_API infix_error_details_t infix_get_last_error(void);
/** @} */ // end of error_api group
/**
* @defgroup direct_marshalling_api Direct Marshalling API
* @brief An advanced, high-performance API for language bindings.
* @ingroup high_level_api
*
* This API provides a way to create highly optimized forward trampolines that
* bypass the standard `void**` argument array. Instead, the JIT-compiled code
* directly calls user-provided "marshaller" functions to convert language-specific
* objects into native C arguments just-in-time. This reduces memory indirection
* and copying, yielding significant performance gains for FFI calls in tight loops.
* @{
*/
/**
* @brief A function pointer for a direct marshalling forward trampoline.
*
* This is the callable code generated by `infix_forward_create_direct`. It takes
* an array of `void*` pointers that point directly to the language-specific
* objects (e.g., `SV*` in Perl, `PyObject*` in Python).
*
* @param return_value_ptr A pointer to a buffer to receive the C function's return value.
* @param lang_objects_array An array of `void*` pointers to the original language objects.
*/
typedef void (*infix_direct_cif_func)(void *, void **);
/**
* @brief A union to hold any primitive value returned by a scalar marshaller.
*
* Since a C function can only have one return type, a marshaller for primitive
* types (`infix_marshaller_fn`) returns this union. The JIT-compiled code will
* know which member of the union to access based on the argument's C type.
*/
typedef union {
uint64_t u64; ///< Used for all unsigned integer types up to 64 bits.
int64_t i64; ///< Used for all signed integer types up to 64 bits.
double f64; ///< Used for `float` and `double`.
void * ptr; ///< Used for all pointer types.
} infix_direct_value_t;
/**
* @brief A function pointer for a custom marshaller for scalar types.
*
* A language binding provides a function of this type to convert a language object
* into a native C primitive value (integer, float, pointer, etc.).
*
* @param source_object A generic `void*` pointer to the language's native object.
* @return An `infix_direct_value_t` union containing the converted C value.
*/
typedef infix_direct_value_t (*infix_marshaller_fn)(void * source_object);
/**
* @brief A function pointer for a custom marshaller for aggregate types (structs/unions).
*
* A language binding provides a function of this type to populate a C struct/union
* from a language object (e.g., a hash or dictionary).
*
* @param source_object A `void*` pointer to the language's native object.
* @param dest_buffer A pointer to a block of memory, allocated by the JIT trampoline,
* that is the exact size of the C aggregate. The function must
* fill this buffer with the native C data.
* @param type A pointer to the `infix_type` object describing the C aggregate. The
* marshaller can introspect this type to determine field names, offsets,
* and member types.
*/
typedef void (*infix_aggregate_marshaller_fn)(void * source_object, void * dest_buffer, const infix_type * type);
/**
* @brief A function pointer for a "write-back" handler for out/in-out parameters.
*
* This function is called by the JIT trampoline *after* the native C function has
* returned. Its purpose is to update the original language object with any changes
* made to the C data by the function.
*
* @param source_object A `void*` pointer to the original language object that was passed in.
* @param c_data_ptr A pointer to the (potentially modified) C data buffer that was passed
* to the C function.
* @param type A pointer to the `infix_type` object describing the C data.
*/
typedef void (*infix_writeback_fn)(void * source_object, void * c_data_ptr, const infix_type * type);
/**
* @brief A struct containing all the necessary handlers for a single function argument.
*
* For each argument, a language binding provides an instance of this struct. Based on
* the argument's type, one or more of the function pointers will be non-NULL.
*/
typedef struct {
/** @brief For "in" parameters of a scalar type (int, float, pointer). */
infix_marshaller_fn scalar_marshaller;
/** @brief For "in" parameters of an aggregate type (struct, union). */
infix_aggregate_marshaller_fn aggregate_marshaller;
/** @brief For "out" or "in-out" parameters. Called after the C function returns. */
infix_writeback_fn writeback_handler;
} infix_direct_arg_handler_t;
/**
* @brief Creates a forward trampoline with direct, JIT-bound marshalling.
*
* This advanced function generates a highly optimized trampoline that calls user-provided
* marshaller functions directly from the JIT-compiled code to convert language-specific
* objects into native C arguments. This avoids intermediate copying and provides the
* highest performance for forward calls.
*
* @param[out] out_trampoline Receives the created trampoline handle upon success.
* @param[in] signature The C signature of the target function (e.g., `"(int, *char)->void"`).
* @param[in] target_function The address of the C function to be called.
* @param[in] handlers An array of `infix_direct_arg_handler_t` structs, one for each
* argument of the C function. The array must have exactly as many
* elements as the function has arguments.
* @param[in] registry An optional type registry for resolving named types (`@Name`)
* used within the signature. Can be `nullptr`.
* @return `INFIX_SUCCESS` on success, or an error code on failure.
*/
INFIX_API INFIX_NODISCARD infix_status infix_forward_create_direct(infix_forward_t ** out_trampoline,
const char * signature,
void * target_function,
infix_direct_arg_handler_t * handlers,
infix_registry_t * registry);
/**
* @brief Gets the callable function pointer from a direct marshalling trampoline.
*
* @param[in] trampoline The `infix_forward_t` handle created with `infix_forward_create_direct`.
* @return A callable `infix_direct_cif_func` pointer on success, or `nullptr` if the
* trampoline is `nullptr` or is not a direct marshalling trampoline.
*/
INFIX_API INFIX_NODISCARD infix_direct_cif_func infix_forward_get_direct_code(infix_forward_t * trampoline);
/** @} */ // end of direct_marshalling_api group
#ifdef __cplusplus
}
#endif
( run in 0.621 second using v1.01-cache-2.11-cpan-2398b32b56e )