Affix
view release on metacpan or search on metacpan
infix/include/infix/infix.h view on Meta::CPAN
* @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
infix/include/infix/infix.h view on Meta::CPAN
*/
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[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.
( run in 1.249 second using v1.01-cache-2.11-cpan-39bf76dae61 )