Affix

 view release on metacpan or  search on metacpan

infix/include/infix/infix.h  view on Meta::CPAN

 * - **Secure:** Designed with modern security principles like W^X (Write XOR Execute)
 *   and hardened against memory corruption.
 * - **Lightweight & Embeddable:** A small, dependency-free library ideal for
 *   embedding in language runtimes, plugins, and other applications.
 *
 * @section usage_sec Basic Usage
 *
 * ```c
 * #include <infix/infix.h>
 * #include <stdio.h>
 *
 * // The C function we want to call.
 * int add(int a, int b) { return a + b; }
 *
 * int main() {
 *     infix_forward_t* trampoline = NULL;
 *     const char* signature = "(int, int) -> int";
 *
 *     // Create a "bound" trampoline JIT-compiled for the `add` function.
 *     infix_forward_create(&trampoline, signature, (void*)add, NULL);
 *
 *     // Get the callable function pointer from the trampoline.
 *     infix_cif_func cif = infix_forward_get_code(trampoline);
 *
 *     // Prepare arguments as an array of pointers.
 *     int a = 10, b = 32;
 *     void* args[] = { &a, &b };
 *     int result;
 *
 *     // Call the function through the FFI interface.
 *     cif(&result, args);
 *
 *     printf("Result: %d\n", result); // Output: Result: 42
 *
 *     infix_forward_destroy(trampoline);
 *     return 0;
 * }
 * ```
 */
#pragma once
/**
 * @defgroup version_info Version Information
 * @brief Macros defining the semantic version of the infix library.
 * @details The versioning scheme follows Semantic Versioning 2.0.0 (SemVer).
 * @{
 */
#define INFIX_MAJOR 0 /**< The major version number. Changes with incompatible API updates. */
#define INFIX_MINOR 1 /**< The minor version number. Changes with new, backward-compatible features. */
#define INFIX_PATCH 6 /**< The patch version number. Changes with backward-compatible bug fixes. */

#if defined(__has_c_attribute)
#define _INFIX_HAS_C_ATTRIBUTE(x) __has_c_attribute(x)
#else
#define _INFIX_HAS_C_ATTRIBUTE(x) 0
#endif

/**
 * @def INFIX_API
 * @brief Symbol visibility macro
 *
 * @details infix relies on a unity build so we've been lax about symbol visibility. Functions like `_infix_set_error`
 * or `_infix_type_recalculate_layout` are shared between internal modules (files included by `infix.c`) and thus cannot
 * be static. However, this means that if infix.c is compiled into a shared library (`libinfix.so`), all of these
 * internal _infix_* functions are exported in the dynamic symbol table. This pollutes the ABI and allows users to link
 * against internal functions that might change.
 */
#if defined(_WIN32) || defined(__CYGWIN__)
#if defined(INFIX_BUILDING_DLL)
#define INFIX_API __declspec(dllexport)
#elif defined(INFIX_USING_DLL)
#define INFIX_API __declspec(dllimport)
#else
#define INFIX_API
#endif
#elif defined(__GNUC__) || defined(__clang__)
#define INFIX_API __attribute__((visibility("default")))
#else
#define INFIX_API
#endif

/**
 * @def INFIX_NODISCARD
 * @brief A compatibility macro for the C23 `[[nodiscard]]` attribute.
 *
 * @details This attribute is used to issue a compiler warning if the return value
 * of a function is ignored by the caller. This is extremely useful for catching
 * bugs where an error code or an important result is not checked.
 *
 * This macro expands to:
 * - `[[nodiscard]]` on compilers that support the C23 standard syntax.
 * - `__attribute__((warn_unused_result))` on GCC and Clang.
 * - `_Check_return_` on Microsoft Visual C++.
 * - Nothing on other compilers.
 *
 * This is aliased as `c23_nodiscard` in `compat_c23.h`.
 */
#if _INFIX_HAS_C_ATTRIBUTE(nodiscard) && !defined(__GNUC__) && !defined(__clang__)
#define INFIX_NODISCARD [[nodiscard]]
#elif defined(__GNUC__) || defined(__clang__)
#define INFIX_NODISCARD __attribute__((warn_unused_result))
#elif defined(_MSC_VER)
#define INFIX_NODISCARD _Check_return_
#else
#define INFIX_NODISCARD
#endif

/**
 * @struct infix_version_t
 * @brief A structure representing the semantic version of the library.
 * @see infix_get_version
 */
typedef struct {
    int major; /**< The major version number (incremented for incompatible API changes). */
    int minor; /**< The minor version number (incremented for backwards-compatible features). */
    int patch; /**< The patch version number (incremented for backwards-compatible bug fixes). */
} infix_version_t;

/** @} */
// Define the POSIX source macro to ensure function declarations for shm_open,
// ftruncate, etc., are visible on all POSIX-compliant systems.
// This must be defined before any system headers are included.
#ifndef _DEFAULT_SOURCE
#define _DEFAULT_SOURCE
#endif
// Define the POSIX source macro to ensure function declarations for posix_memalign
// are visible. This must be defined before any system headers are included.
#if !defined(_POSIX_C_SOURCE)
#define _POSIX_C_SOURCE 200809L
#endif
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif
/**
 * @brief Retrieves the version of the infix library linked at runtime.
 *
 * @details This function allows applications to verify that the version of the
 *          library they are linked against matches the headers they were compiled with.
 *          This is particularly useful when loading `infix` as a shared library/DLL
 *          to detect version mismatches.
 *
 * @return An `infix_version_t` structure containing the major, minor, and patch numbers.
 */
INFIX_API INFIX_NODISCARD infix_version_t infix_get_version(void);

infix/include/infix/infix.h  view on Meta::CPAN

#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
 * semicolons. The parser supports forward declarations (`@Name;`) and out-of-order
 * definitions, making it easy to define mutually recursive types.
 *
 * @param[in] registry The registry to populate.
 * @param[in] definitions A semicolon-separated string of definitions.
 * @return `INFIX_SUCCESS` on success, or an error code on failure.
 * @code
 * const char* my_types =
 *     "@Point = { x: double, y: double };"    // Define a struct
 *     "@Node;"                                // Forward-declare Node
 *     "@List = { head: *@Node };"             // Use the forward declaration
 *     "@Node = { value: int, next: *@Node };" // Define the recursive struct
 * ;
 * infix_register_types(registry, my_types);
 * @endcode
 */
INFIX_API INFIX_NODISCARD infix_status infix_register_types(infix_registry_t *, const char *);
/** @} */  // end of registry_api group
/**
 * @defgroup registry_introspection_api Registry Introspection API
 * @brief APIs for inspecting and serializing the contents of a named type registry.
 * @ingroup high_level_api
 * @{
 */
/**
 * @struct infix_registry_iterator_t
 * @brief An iterator for traversing a type registry.
 * @details This struct holds the complete state needed to traverse the registry's
 * internal hash table, including the current bucket and the current entry within
 * that bucket's linked list.
 *
 * The fields in this struct are implementation details and should not be accessed directly.
 */
typedef struct infix_registry_iterator_t {
    const infix_registry_t * registry; /**< The registry being iterated. */
    size_t _bucket_index;              /**< Internal: current hash bucket. */
    void * _current_entry;             /**< Internal: opaque pointer to current entry. */
} infix_registry_iterator_t;
/**
 * @brief Serializes all defined types within a registry into a single, human-readable string.
 *
 * The output format is a sequence of definitions (e.g., `@Name = { ... };`) separated
 * by newlines, suitable for logging, debugging, or saving to a file. This function
 * will not print forward declarations that have not been fully defined.
 *
 * @param[out] buffer The output buffer to write the string into.
 * @param[in] buffer_size The size of the output buffer.
 * @param[in] registry The registry to serialize.
 * @return `INFIX_SUCCESS` on success, or `INFIX_ERROR_INVALID_ARGUMENT` if the buffer is too small.
 */
INFIX_API INFIX_NODISCARD infix_status infix_registry_print(char *, size_t, const infix_registry_t *);
/**
 * @brief Initializes an iterator for traversing the types in a registry.
 *
 * @param[in] registry The registry to iterate over.
 * @return An initialized iterator. If the registry is empty, the first call to
 *         `infix_registry_iterator_next` on this iterator will return `false`.
 */
INFIX_API INFIX_NODISCARD infix_registry_iterator_t infix_registry_iterator_begin(const infix_registry_t *);
/**
 * @brief Advances the iterator to the next defined type in the registry.
 *
 * @param[in,out] iterator The iterator to advance.
 * @return `true` if the iterator was advanced to a valid type, or `false` if there are no more types.
 */
INFIX_API INFIX_NODISCARD bool infix_registry_iterator_next(infix_registry_iterator_t *);

infix/include/infix/infix.h  view on Meta::CPAN

 * @param[in] registry The registry to search.
 * @param[in] name The name of the type to check (e.g., "MyStruct").
 * @return `true` if a complete definition for the name exists, `false` otherwise.
 */
INFIX_API INFIX_NODISCARD bool infix_registry_is_defined(const infix_registry_t *, const char *);
/**
 * @brief Retrieves the canonical `infix_type` object for a given name from the registry.
 *
 * @param[in] registry The registry to search.
 * @param[in] name The name of the type to retrieve.
 * @return A pointer to the canonical `infix_type` object if found and fully defined.
 *         Returns `nullptr` if the name is not found or is only a forward declaration.
 *         The returned pointer is owned by the registry and is valid for its lifetime.
 */
INFIX_API INFIX_NODISCARD const infix_type * infix_registry_lookup_type(const infix_registry_t *, const char *);
/**
 * @brief Creates a new named type registry that allocates from a user-provided arena.
 *
 * This advanced function allows multiple registries and trampolines to share a single
 * memory arena, enabling pointer sharing and reducing memory overhead. The user
 * is responsible for managing the lifetime of the provided arena.
 *
 * @param[in] arena The user-managed arena to use for all internal allocations.
 * @return A pointer to the new registry, or `nullptr` on allocation failure.
 * @note The registry should still be destroyed with `infix_registry_destroy`, but
 *       this will not free the user-provided arena itself.
 */
INFIX_API INFIX_NODISCARD infix_registry_t * infix_registry_create_in_arena(infix_arena_t * arena);
/** @} */  // end of registry_introspection_api group
/**
 * @brief Creates a "bound" forward trampoline from a signature string.
 *
 * @details A bound trampoline is a highly optimized JIT-compiled function where the
 * target C function's address is compiled directly into the executable code. This
 * provides the best performance for forward calls, as it involves a direct `call`
 * instruction to a known address. It is ideal for situations where you will call
 * the same C function repeatedly.
 *
 * The returned handle contains a callable function pointer of type `infix_cif_func`,
 * which you can retrieve with `infix_forward_get_code`.
 *
 * @param[out] out_trampoline A pointer to an `infix_forward_t*` that will receive the
 *             created trampoline handle upon success.
 * @param[in] signature The signature string of the target function (e.g., `"(int, int)->int"`).
 * @param[in] target_function The address of the C function to be called.
 * @param[in] registry An optional type registry for resolving named types (`@Name`)
 *             used within the signature. Can be `nullptr` if no named types are used.
 * @return `INFIX_SUCCESS` on success, or an `INFIX_ERROR_...` code on failure.
 * @note The caller is responsible for destroying the handle with `infix_forward_destroy`.
 *
 * @code
 * // C function to call
 * int add(int a, int b) { return a + b; }
 *
 * infix_forward_t* trampoline = NULL;
 * const char* signature = "(int, int) -> int";
 *
 * // Create a trampoline bound to the `add` function.
 * infix_status status = infix_forward_create(&trampoline, signature, (void*)add, NULL);
 * if (status != INFIX_SUCCESS) {
 *     // Handle error...
 * }
 *
 * // Get the callable JIT-compiled function pointer.
 * infix_cif_func cif = infix_forward_get_code(trampoline);
 *
 * // Prepare arguments and return buffer.
 * int a = 10, b = 32;
 * void* args[] = { &a, &b };
 * int result;
 *
 * // Call the C function through the FFI.
 * cif(&result, args); // result is now 42
 *
 * infix_forward_destroy(trampoline);
 * @endcode
 */
INFIX_API INFIX_NODISCARD infix_status infix_forward_create(infix_forward_t **,
                                                            const char *,
                                                            void *,
                                                            infix_registry_t *);
/**
 * @brief Creates a "safe" bound forward trampoline that catches native exceptions.
 * @details This is identical to `infix_forward_create`, but the generated trampoline
 *          is wrapped in a platform-specific exception handler (e.g., SEH on Windows).
 *          If the target function throws an exception, the trampoline will catch it
 *          and set the thread-local error to `INFIX_CODE_NATIVE_EXCEPTION`.
 *
 * @param[out] out_trampoline Receives the created handle.
 * @param[in] signature The function signature.
 * @param[in] target_function The address of the C function.
 * @param[in] registry An optional type registry.
 * @return `INFIX_SUCCESS` on success.
 */
INFIX_API INFIX_NODISCARD infix_status infix_forward_create_safe(infix_forward_t **,
                                                                 const char *,
                                                                 void *,
                                                                 infix_registry_t *);
/**
 * @brief Creates an "unbound" forward trampoline from a signature string.
 *
 * @details An unbound trampoline is more flexible than a bound one. The target function
 * address is not compiled in; instead, it is provided as the first argument at
 * call time. This is useful for calling multiple C functions that share the same
 * signature without needing to generate a separate trampoline for each one.
 *
 * The returned handle contains a callable function pointer of type `infix_unbound_cif_func`,
 * which you can retrieve with `infix_forward_get_unbound_code`.
 *
 * @param[out] out_trampoline A pointer to an `infix_forward_t*` that will receive the
 *             created trampoline handle upon success.
 * @param[in] signature The signature string of the target function.
 * @param[in] registry An optional type registry for resolving named types. Can be `nullptr`.
 * @return `INFIX_SUCCESS` on success.
 * @note The caller is responsible for destroying the handle with `infix_forward_destroy`.
 *
 * @code
 * int add(int a, int b) { return a + b; }
 * int subtract(int a, int b) { return a - b; }
 *
 * infix_forward_t* trampoline = NULL;
 * const char* signature = "(int, int) -> int";
 *
 * // Create one unbound trampoline for the signature.
 * infix_forward_create_unbound(&trampoline, signature, NULL);
 *
 * infix_unbound_cif_func cif = infix_forward_get_unbound_code(trampoline);
 *
 * int a = 10, b = 5;
 * void* args[] = { &a, &b };
 * int result;
 *
 * // Call `add` by passing its address at call time.
 * cif((void*)add, &result, args); // result is 15
 *
 * // Reuse the same trampoline to call `subtract`.
 * cif((void*)subtract, &result, args); // result is 5
 *
 * infix_forward_destroy(trampoline);
 * @endcode
 */
INFIX_API INFIX_NODISCARD infix_status infix_forward_create_unbound(infix_forward_t **,
                                                                    const char *,
                                                                    infix_registry_t *);
/**
 * @brief Creates a "bound" forward trampoline within a user-provided arena.
 *

infix/include/infix/infix.h  view on Meta::CPAN

 * @param[out] out_args On success, receives a pointer to the array of `infix_function_argument` structs.
 * @param[out] out_num_args On success, receives the total number of arguments.
 * @param[out] out_num_fixed_args On success, receives the number of fixed (non-variadic) arguments.
 * @param[in] registry An optional type registry.
 * @return `INFIX_SUCCESS` on success.
 */
INFIX_API INFIX_NODISCARD infix_status infix_signature_parse(
    const char *, infix_arena_t **, infix_type **, infix_function_argument **, size_t *, size_t *, infix_registry_t *);
/**
 * @brief Parses a signature string representing a single data type.
 *
 * This is the core function for introspection, allowing you to get a detailed,
 * fully resolved memory layout for any C type described by a signature.
 *
 * @param[out] out_type On success, receives a pointer to the parsed type object.
 * @param[out] out_arena On success, receives a pointer to the arena holding the type. The caller must free this with
 * `infix_arena_destroy`.
 * @param[in] signature The signature string of the data type (e.g., `"{id:int, name:*char}"`).
 * @param[in] registry An optional type registry for resolving named types.
 * @return `INFIX_SUCCESS` on success.
 */
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/include/infix/infix.h  view on Meta::CPAN

 * @param[in] trampoline The trampoline context handle.
 * @param[in] index The zero-based index of the argument.
 * @return A pointer to the `infix_type`, or `nullptr` if the index is out of bounds.
 */
INFIX_API INFIX_NODISCARD const infix_type * infix_reverse_get_arg_type(const infix_reverse_t *, size_t);
/**
 * @brief Gets the semantic alias of a type, if one exists.
 * @param[in] type The type object to inspect.
 * @return The name of the type if it was created from a registry alias (e.g., "MyInt"), or `nullptr` if the type is
 * anonymous.
 */
INFIX_API INFIX_NODISCARD const char * infix_type_get_name(const infix_type *);
/**
 * @brief Gets the fundamental category of a type.
 * @param[in] type The type object to inspect.
 * @return The `infix_type_category` enum value.
 */
INFIX_API INFIX_NODISCARD infix_type_category infix_type_get_category(const infix_type *);
/**
 * @brief Gets the size of a type in bytes.
 * @param[in] type The type object to inspect.
 * @return The size in bytes.
 */
INFIX_API INFIX_NODISCARD size_t infix_type_get_size(const infix_type *);
/**
 * @brief Gets the alignment requirement of a type in bytes.
 * @param[in] type The type object to inspect.
 * @return The alignment in bytes.
 */
INFIX_API INFIX_NODISCARD size_t infix_type_get_alignment(const infix_type *);
/**
 * @brief Gets the number of members in a struct or union type.
 * @param[in] type The aggregate type object to inspect.
 * @return The number of members, or 0 if the type is not a struct or union.
 */
INFIX_API INFIX_NODISCARD size_t infix_type_get_member_count(const infix_type *);
/**
 * @brief Gets a specific member from a struct or union type.
 * @param[in] type The aggregate type object to inspect.
 * @param[in] index The zero-based index of the member.
 * @return A pointer to the `infix_struct_member`, or `nullptr` if the index is out of bounds.
 */
INFIX_API INFIX_NODISCARD const infix_struct_member * infix_type_get_member(const infix_type *, size_t);
/**
 * @brief Gets the name of a specific argument from a function type.
 * @param[in] func_type The function type object to inspect (`INFIX_TYPE_REVERSE_TRAMPOLINE`).
 * @param[in] index The zero-based index of the argument.
 * @return The name of the argument, or `nullptr` if anonymous or out of bounds.
 */
INFIX_API INFIX_NODISCARD const char * infix_type_get_arg_name(const infix_type *, size_t);
/**
 * @brief Gets the type of a specific argument from a function type.
 * @param[in] func_type The function type object to inspect.
 * @param[in] index The zero-based index of the argument.
 * @return A pointer to the `infix_type`, or `nullptr` if the index is out of bounds.
 */
INFIX_API INFIX_NODISCARD const infix_type * infix_type_get_arg_type(const infix_type *, size_t);
/** @} */  // end addtogroup type_system
/** @} */  // end of introspection_api group
/**
 * @defgroup error_api Error Handling API
 * @brief Functions and types for detailed, thread-safe error reporting.
 * @{
 */
/**
 * @brief Enumerates the high-level categories of errors that can occur.
 */
typedef enum {
    INFIX_CATEGORY_NONE,       /**< No error. */
    INFIX_CATEGORY_GENERAL,    /**< A general or miscellaneous error. */
    INFIX_CATEGORY_ALLOCATION, /**< A memory allocation error. */
    INFIX_CATEGORY_PARSER,     /**< A syntax error in a signature string. */
    INFIX_CATEGORY_ABI         /**< An error related to ABI classification or layout. */
} 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.696 second using v1.01-cache-2.11-cpan-39bf76dae61 )