Affix

 view release on metacpan or  search on metacpan

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

/**
 * Copyright (c) 2025 Sanko Robinson
 *
 * This source code is dual-licensed under the Artistic License 2.0 or the MIT License.
 * You may choose to use this code under the terms of either license.
 *
 * SPDX-License-Identifier: (Artistic-2.0 OR MIT)
 *
 * The documentation blocks within this file are licensed under the
 * Creative Commons Attribution 4.0 International License (CC BY 4.0).
 *
 * SPDX-License-Identifier: CC-BY-4.0
 */
/**
 * @file infix.h
 * @brief The public interface for the infix FFI library.
 *
 * @mainpage infix FFI Library
 *
 * @section intro_sec Introduction
 *
 * `infix` is a powerful, modern, and lightweight C library for creating Foreign
 * Function Interface (FFI) trampolines at runtime. It allows you to dynamically
 * call C functions or create C callbacks from any language or environment, using
 * a simple, human-readable string-based syntax to describe function signatures.
 *
 * @section features_sec Key Features
 *
 * - **Simple Signature Syntax:** Describe complex C types, structs, and function
 *   prototypes with an intuitive string format.
 * - **Forward & Reverse Calls:** Create "forward" trampolines to call C from your
 *   code, and "reverse" trampolines (callbacks) to allow C to call back into your code.
 * - **Named Type Registry:** Define, reuse, and link complex, recursive, and
 *   mutually-dependent structs by name.
 * - **Cross-Platform:** Supports major architectures (x86-64, AArch64) and operating
 *   systems (Linux, macOS, Windows).
 * - **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

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

/**
 * @brief Creates a "bound" forward trampoline within a user-provided arena.
 *
 * 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.
 *
 * This function provides a way to deconstruct a signature string into its components
 * (`return_type`, `arg_types`, etc.) without generating a trampoline. It is useful
 * for introspection and for preparing arguments for the Manual API.
 *
 * @param[in] signature The signature string to parse.
 * @param[out] out_arena On success, receives a pointer to an arena holding all parsed types. The caller owns this and



( run in 0.958 second using v1.01-cache-2.11-cpan-39bf76dae61 )