infix
A JIT-Powered FFI Library for C
Loading...
Searching...
No Matches
types.c
Go to the documentation of this file.
1
34#include "common/utility.h"
35#include <limits.h> // For SIZE_MAX
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39
40// Static Singleton Instances for Primitive Types
41/*
42 * Helper macro to initialize a static `infix_type` for a primitive.
43 * This ensures size and alignment are correct for the compilation target at compile time.
44 */
45#define INFIX_TYPE_INIT(id, T) \
46 {.category = INFIX_TYPE_PRIMITIVE, \
47 .size = sizeof(T), \
48 .alignment = _Alignof(T), \
49 .is_arena_allocated = false, \
50 .meta.primitive_id = id}
51
52/*
53 * These statically allocated singletons are a performance optimization. They avoid
54 * dynamic allocation for common types and simplify memory management for the user,
55 * as they do not need to be freed.
56 */
58 .category = INFIX_TYPE_VOID, .size = 0, .alignment = 0, .is_arena_allocated = false, .meta = {0}};
59
61 .size = sizeof(void *),
62 .alignment = _Alignof(void *),
63 .is_arena_allocated = false,
64 .meta.pointer_info = {.pointee_type = &_infix_type_void}};
65
75#if !defined(INFIX_COMPILER_MSVC)
76// 128-bit integers are a non-standard GCC/Clang extension.
79#endif
82
83// Only define a separate long double type if it's distinct from double on the target platform.
84#if defined(INFIX_COMPILER_MSVC) || (defined(INFIX_OS_WINDOWS) && defined(INFIX_COMPILER_CLANG)) || \
85 defined(INFIX_OS_MACOS)
86// On these platforms, long double is an alias for double.
87#else
89#endif
90
91/*
92 * Implementation for infix_type_create_primitive.
93 * This acts as a factory, returning a pointer to one of the static singletons.
94 * It correctly handles platform-specific ABI differences, such as when `long double`
95 * is just an alias for `double`.
96 */
98 switch (id) {
100 return &_infix_type_bool;
102 return &_infix_type_uint8;
104 return &_infix_type_sint8;
106 return &_infix_type_uint16;
108 return &_infix_type_sint16;
110 return &_infix_type_uint32;
112 return &_infix_type_sint32;
114 return &_infix_type_uint64;
116 return &_infix_type_sint64;
117#if !defined(INFIX_COMPILER_MSVC)
119 return &_infix_type_uint128;
121 return &_infix_type_sint128;
122#endif
124 return &_infix_type_float;
126 return &_infix_type_double;
128// On MSVC, Clang-for-Windows, and all Apple platforms, long double is just an alias for double.
129// Return the canonical double type to ensure correct ABI handling.
130#if defined(INFIX_COMPILER_MSVC) || (defined(INFIX_OS_WINDOWS) && defined(INFIX_COMPILER_CLANG)) || \
131 defined(INFIX_OS_MACOS)
132 return &_infix_type_double;
133#else
135#endif
136 default:
137 return nullptr;
138 }
139}
140
141/*
142 * Implementation for infix_type_create_pointer.
143 * Returns a pointer to the static singleton instance describing `void*`.
144 */
148
149/*
150 * Implementation for infix_type_create_void.
151 * Returns a pointer to the static singleton instance describing the `void` type.
152 */
156
157/*
158 * Implementation for infix_type_create_member.
159 * This is a simple helper function for creating an `infix_struct_member` value.
160 */
161infix_struct_member infix_type_create_member(const char * name, infix_type * type, size_t offset) {
162 return (infix_struct_member){name, type, offset};
163}
164
165/*
166 * @internal
167 * This is a common setup function for creating any aggregate type (struct or union)
168 * from an arena. It handles argument validation, allocates the main `infix_type`
169 * struct, and crucially, copies the user-provided `members` array into the arena.
170 * This copy makes the final `infix_type` object self-contained and immune to use-after-free
171 * bugs if the original `members` array was stack-allocated.
172 */
174 infix_type ** out_type,
175 infix_struct_member ** out_arena_members,
177 size_t num_members) {
178 if (out_type == nullptr)
180
181 // Validate that all member types are non-null before proceeding.
182 for (size_t i = 0; i < num_members; ++i) {
183 if (members[i].type == nullptr) {
184 *out_type = nullptr;
186 }
187 }
188
189 infix_type * type = infix_arena_alloc(arena, sizeof(infix_type), _Alignof(infix_type));
190 if (type == nullptr) {
191 *out_type = nullptr;
193 }
194
195 // Copy the caller's member data into the arena to make this type object self-contained.
196 infix_struct_member * arena_members = nullptr;
197 if (num_members > 0) {
198 arena_members =
199 infix_arena_alloc(arena, sizeof(infix_struct_member) * num_members, _Alignof(infix_struct_member));
200 if (arena_members == nullptr) {
201 *out_type = nullptr;
203 }
204 infix_memcpy(arena_members, members, sizeof(infix_struct_member) * num_members);
205 // Deep copy the member names to make the type fully self-contained.
206 for (size_t i = 0; i < num_members; ++i) {
207 const char * src_name = members[i].name;
208 if (src_name) {
209 size_t name_len = strlen(src_name) + 1;
210 char * dest_name = infix_arena_alloc(arena, name_len, 1);
211 if (!dest_name) {
212 *out_type = nullptr;
214 }
215 infix_memcpy(dest_name, src_name, name_len);
216 arena_members[i].name = dest_name;
217 }
218 }
219 }
220
221 *out_type = type;
222 *out_arena_members = arena_members;
223 return INFIX_SUCCESS;
224}
225
226/*
227 * Implementation for infix_type_create_pointer_to.
228 * Creates a pointer type that retains introspection information about its pointee.
229 */
231 infix_type ** out_type,
232 infix_type * pointee_type) {
233 if (!out_type || !pointee_type)
235
236 infix_type * type = infix_arena_alloc(arena, sizeof(infix_type), _Alignof(infix_type));
237 if (type == nullptr) {
238 *out_type = nullptr;
240 }
241
242 *type = *infix_type_create_pointer(); // Copy base properties from the void* singleton
243 type->is_arena_allocated = true;
244 type->meta.pointer_info.pointee_type = pointee_type;
245 *out_type = type;
246 return INFIX_SUCCESS;
247}
248
249/*
250 * Implementation for infix_type_create_array.
251 * Calculates array layout, including a critical security check to prevent integer
252 * overflow when calculating the total size from untrusted inputs (e.g., a fuzzer).
253 */
255 infix_type ** out_type,
256 infix_type * element_type,
257 size_t num_elements) {
258 if (out_type == nullptr || element_type == nullptr)
260
261 // Security: Check for integer overflow before calculating the total array size.
262 if (element_type->size > 0 && num_elements > SIZE_MAX / element_type->size) {
263 *out_type = nullptr;
266 }
267
268 infix_type * type = infix_arena_alloc(arena, sizeof(infix_type), _Alignof(infix_type));
269 if (type == nullptr) {
270 *out_type = nullptr;
272 }
273
274 type->is_arena_allocated = true;
276 type->meta.array_info.element_type = element_type;
277 type->meta.array_info.num_elements = num_elements;
278 type->alignment = element_type->alignment;
279 type->size = element_type->size * num_elements;
280
281 *out_type = type;
282 return INFIX_SUCCESS;
283}
284
285/*
286 * Implementation for infix_type_create_enum.
287 * For ABI purposes, an enum is just a wrapper around its underlying integer type.
288 */
290 infix_type ** out_type,
291 infix_type * underlying_type) {
292 if (out_type == nullptr || underlying_type == nullptr)
294
295 // Enums must be based on an integer type.
296 if (underlying_type->category != INFIX_TYPE_PRIMITIVE ||
297 underlying_type->meta.primitive_id > INFIX_PRIMITIVE_SINT128) {
299 }
300
301 infix_type * type = infix_arena_alloc(arena, sizeof(infix_type), _Alignof(infix_type));
302 if (type == nullptr) {
303 *out_type = nullptr;
305 }
306
307 INFIX_DEBUG_PRINTF("Created struct type. Size: %llu, Alignment: %llu",
308 (unsigned long long)type->size,
309 (unsigned long long)type->alignment);
310 type->is_arena_allocated = true;
312 type->size = underlying_type->size;
313 type->alignment = underlying_type->alignment;
314 type->meta.enum_info.underlying_type = underlying_type;
315
316 *out_type = type;
317 return INFIX_SUCCESS;
318}
319
320/*
321 * Implementation for infix_type_create_complex.
322 * A complex number is laid out in memory as two contiguous floating-point values.
323 */
325 infix_type ** out_type,
326 infix_type * base_type) {
327 if (out_type == nullptr || base_type == nullptr)
329
330 // A complex number must be based on a float or double.
331 if (!is_float(base_type) && !is_double(base_type))
333
334 infix_type * type = infix_arena_alloc(arena, sizeof(infix_type), _Alignof(infix_type));
335 if (type == nullptr) {
336 *out_type = nullptr;
338 }
339
340 type->is_arena_allocated = true;
342 type->size = base_type->size * 2;
343 type->alignment = base_type->alignment;
344 type->meta.complex_info.base_type = base_type;
345
346 *out_type = type;
347 return INFIX_SUCCESS;
348}
349
350/*
351 * Implementation for infix_type_create_vector.
352 * Calculates vector layout, including overflow checks.
353 */
355 infix_type ** out_type,
356 infix_type * element_type,
357 size_t num_elements) {
358 if (out_type == nullptr || element_type == nullptr || element_type->category != INFIX_TYPE_PRIMITIVE)
360
361 // Security: Check for integer overflow before calculating the total vector size.
362 if (element_type->size > 0 && num_elements > SIZE_MAX / element_type->size) {
363 *out_type = nullptr;
365 }
366
367 infix_type * type = infix_arena_alloc(arena, sizeof(infix_type), _Alignof(infix_type));
368 if (type == nullptr) {
369 *out_type = nullptr;
371 }
372
373 type->is_arena_allocated = true;
375 type->meta.vector_info.element_type = element_type;
376 type->meta.vector_info.num_elements = num_elements;
377 // A vector's size is the total size of its elements.
378 type->size = element_type->size * num_elements;
379 // Common ABIs require 128-bit vectors to be 16-byte aligned.
380 // We will enforce this alignment, as it's the strictest requirement.
381 type->alignment = type->size > 8 ? 16 : type->size;
382
383 *out_type = type;
384 return INFIX_SUCCESS;
385}
386
387/*
388 * Implementation for infix_type_create_union.
389 * This function calculates the size and alignment for a union according to standard
390 * C layout rules: size is the max member size (padded), alignment is the max member alignment.
391 */
393 infix_type ** out_type,
395 size_t num_members) {
396 infix_type * type = nullptr;
397 infix_struct_member * arena_members = nullptr;
398 infix_status status = _create_aggregate_setup(arena, &type, &arena_members, members, num_members);
399 if (status != INFIX_SUCCESS) {
400 *out_type = nullptr;
401 return status;
402 }
403
404 type->is_arena_allocated = true;
406 type->meta.aggregate_info.name = nullptr; // Initialize name for anonymous union
407 type->meta.aggregate_info.members = arena_members;
408 type->meta.aggregate_info.num_members = num_members;
409
410 size_t max_size = 0;
411 size_t max_alignment = 1;
412
413 // A union's size is determined by its largest member, and its alignment
414 // by the strictest alignment of any member.
415 for (size_t i = 0; i < num_members; ++i) {
416 arena_members[i].offset = 0; // All union members are at offset 0.
417 if (arena_members[i].type->size > max_size)
418 max_size = arena_members[i].type->size;
419 if (arena_members[i].type->alignment > max_alignment)
420 max_alignment = arena_members[i].type->alignment;
421 }
422 type->alignment = max_alignment;
423
424 // The final size is the size of the largest member, rounded up to a
425 // multiple of the union's overall alignment.
426 type->size = _infix_align_up(max_size, max_alignment);
427 if (type->size < max_size) { // Overflow check
428 *out_type = nullptr;
430 }
431
432 INFIX_DEBUG_PRINTF("Created arena union type. Size: %llu, Alignment: %llu",
433 (unsigned long long)type->size,
434 (unsigned long long)type->alignment);
435
436 *out_type = type;
437 return INFIX_SUCCESS;
438}
439
440/*
441 * Implementation for infix_type_create_struct.
442 * This function calculates the size and alignment of the struct based on its
443 * members, adhering to standard C layout and padding rules.
444 */
446 infix_type ** out_type,
448 size_t num_members) {
450 infix_type * type = nullptr;
451 infix_struct_member * arena_members = nullptr;
452 infix_status status = _create_aggregate_setup(arena, &type, &arena_members, members, num_members);
453 if (status != INFIX_SUCCESS) {
454 *out_type = nullptr;
455 return status;
456 }
457
458 type->is_arena_allocated = true;
460 type->meta.aggregate_info.name = nullptr; // Initialize name for anonymous struct
461 type->meta.aggregate_info.members = arena_members;
462 type->meta.aggregate_info.num_members = num_members;
463
464 size_t current_offset = 0;
465 size_t max_alignment = 1; // Empty structs have an alignment of 1.
466
467 // Calculate layout based on the safe, arena-allocated copy of members.
468 for (size_t i = 0; i < num_members; ++i) {
469 infix_struct_member * member = &arena_members[i];
470 size_t member_align = member->type->alignment;
471
472 if (member_align == 0) {
473 *out_type = nullptr;
475 }
476
477 // Align the current offset for this member.
478 size_t aligned_offset = _infix_align_up(current_offset, member_align);
479
480 // Security: Check for integer overflow during alignment.
481 if (aligned_offset < current_offset) {
482 *out_type = nullptr;
484 }
485 current_offset = aligned_offset;
486 member->offset = current_offset;
487
488 // Security: Check for integer overflow before adding the member's size.
489 if (current_offset > SIZE_MAX - member->type->size) {
490 *out_type = nullptr;
492 }
493 current_offset += member->type->size;
494
495 if (member_align > max_alignment)
496 max_alignment = member_align;
497 }
498
499 type->alignment = max_alignment;
500
501 // The final size is the calculated offset rounded up to the nearest multiple
502 // of the struct's overall alignment to account for trailing padding.
503 type->size = _infix_align_up(current_offset, max_alignment);
504 // Security: Check for overflow during final alignment.
505 if (type->size < current_offset) {
506 *out_type = nullptr;
508 }
509
510 *out_type = type;
511 return INFIX_SUCCESS;
512}
513
514/*
515 * Implementation for infix_type_create_packed_struct.
516 * This variant does not calculate layout; it trusts the user-provided size, alignment,
517 * and member offsets, which is necessary for non-standard packed layouts.
518 */
520 infix_type ** out_type,
521 size_t total_size,
522 size_t alignment,
524 size_t num_members) {
525 if (out_type == nullptr || (num_members > 0 && members == nullptr) || alignment == 0)
527
528 infix_type * type = infix_arena_alloc(arena, sizeof(infix_type), _Alignof(infix_type));
529 if (type == nullptr) {
530 *out_type = nullptr;
532 }
533
534 // Copy the caller's member data into the arena to make the type self-contained.
535 infix_struct_member * arena_members = nullptr;
536 if (num_members > 0) {
537 arena_members =
538 infix_arena_alloc(arena, sizeof(infix_struct_member) * num_members, _Alignof(infix_struct_member));
539 if (arena_members == nullptr) {
540 *out_type = nullptr;
542 }
543 infix_memcpy(arena_members, members, sizeof(infix_struct_member) * num_members);
544 }
545
546 type->is_arena_allocated = true;
547 type->size = total_size;
548 type->alignment = alignment;
550 type->meta.aggregate_info.name = nullptr; // Packed structs are anonymous by default via this API
551 type->meta.aggregate_info.members = arena_members;
552 type->meta.aggregate_info.num_members = num_members;
553
554 *out_type = type;
555 return INFIX_SUCCESS;
556}
557
558/*
559 * Implementation for infix_type_create_named_reference.
560 * Creates a placeholder for a type that is referenced by name but not yet defined.
561 * A type graph containing this node cannot be used to generate a trampoline.
562 */
564 infix_type ** out_type,
565 const char * name,
567 if (out_type == nullptr || name == nullptr)
569
570 infix_type * type = infix_arena_alloc(arena, sizeof(infix_type), _Alignof(infix_type));
571 if (type == nullptr) {
572 *out_type = nullptr;
574 }
575
576 // Allocate a copy of the name into the arena to make the type self-contained.
577 size_t name_len = strlen(name) + 1;
578 char * arena_name = infix_arena_alloc(arena, name_len, 1);
579 if (arena_name == nullptr) {
580 *out_type = nullptr;
582 }
583 infix_memcpy(arena_name, name, name_len);
584
585 type->is_arena_allocated = true;
587 // References are conceptual placeholders. Give them a minimal valid alignment
588 // so that they can be stored as members in aggregates without causing
589 // layout calculation errors in the parser. The FFI core will reject any
590 // attempt to generate a trampoline from a type graph containing this type.
591 type->size = 0;
592 type->alignment = 1;
593 type->meta.named_reference.name = arena_name;
595
596 *out_type = type;
597 return INFIX_SUCCESS;
598}
599
611 if (src_type == nullptr)
612 return nullptr;
613
614 // Optimization: If the source type is a static primitive, we don't need to copy it.
615 if (!src_type->is_arena_allocated)
616 return (infix_type *)src_type;
617
618 // Allocate space for the new type in the destination arena and copy the base struct.
619 infix_type * dest_type = infix_arena_alloc(dest_arena, sizeof(infix_type), _Alignof(infix_type));
620 if (dest_type == nullptr)
621 return nullptr;
622 infix_memcpy(dest_type, src_type, sizeof(infix_type));
623
624 // Recursively copy any nested types based on the category.
625 switch (src_type->category) {
627 dest_type->meta.pointer_info.pointee_type =
629 break;
630 case INFIX_TYPE_ARRAY:
631 dest_type->meta.array_info.element_type =
633 break;
635 case INFIX_TYPE_UNION:
636 {
637 // Deep copy the aggregate's own name, if it has one.
638 const char * src_agg_name = src_type->meta.aggregate_info.name;
639 if (src_agg_name) {
640 size_t name_len = strlen(src_agg_name) + 1;
641 char * dest_agg_name = infix_arena_alloc(dest_arena, name_len, 1);
642 if (!dest_agg_name)
643 return nullptr; // Allocation failed
644 infix_memcpy(dest_agg_name, src_agg_name, name_len);
645 // We need to cast away const to write to the destination struct field.
646 *((const char **)&dest_type->meta.aggregate_info.name) = dest_agg_name;
647 }
648
649 if (src_type->meta.aggregate_info.num_members > 0) {
650 size_t members_size = sizeof(infix_struct_member) * src_type->meta.aggregate_info.num_members;
651 dest_type->meta.aggregate_info.members =
652 infix_arena_alloc(dest_arena, members_size, _Alignof(infix_struct_member));
653 if (dest_type->meta.aggregate_info.members == nullptr)
654 return nullptr;
656 dest_type->meta.aggregate_info.members, src_type->meta.aggregate_info.members, members_size);
657
658 for (size_t i = 0; i < src_type->meta.aggregate_info.num_members; ++i) {
659 dest_type->meta.aggregate_info.members[i].type =
660 _copy_type_graph_to_arena(dest_arena, src_type->meta.aggregate_info.members[i].type);
661 // Deep copy the member name string to avoid dangling pointers.
662 const char * src_name = src_type->meta.aggregate_info.members[i].name;
663 if (src_name) {
664 size_t name_len = strlen(src_name) + 1;
665 char * dest_name = infix_arena_alloc(dest_arena, name_len, 1);
666 if (!dest_name)
667 return nullptr;
668 infix_memcpy(dest_name, src_name, name_len);
669 *((const char **)&dest_type->meta.aggregate_info.members[i].name) = dest_name;
670 }
671 }
672 }
673 }
674 break;
676 dest_type->meta.func_ptr_info.return_type =
678 if (src_type->meta.func_ptr_info.num_args > 0) {
679 size_t args_size = sizeof(infix_function_argument) * src_type->meta.func_ptr_info.num_args;
680 dest_type->meta.func_ptr_info.args =
681 infix_arena_alloc(dest_arena, args_size, _Alignof(infix_function_argument));
682 if (dest_type->meta.func_ptr_info.args == nullptr)
683 return nullptr;
684 infix_memcpy(dest_type->meta.func_ptr_info.args, src_type->meta.func_ptr_info.args, args_size);
685
686 for (size_t i = 0; i < src_type->meta.func_ptr_info.num_args; ++i) {
687 dest_type->meta.func_ptr_info.args[i].type =
688 _copy_type_graph_to_arena(dest_arena, src_type->meta.func_ptr_info.args[i].type);
689 const char * src_name = src_type->meta.func_ptr_info.args[i].name;
690 if (src_name) {
691 size_t name_len = strlen(src_name) + 1;
692 char * dest_name = infix_arena_alloc(dest_arena, name_len, 1);
693 if (!dest_name)
694 return nullptr;
695 infix_memcpy(dest_name, src_name, name_len);
696 *((const char **)&dest_type->meta.func_ptr_info.args[i].name) = dest_name;
697 }
698 }
699 }
700 break;
701 default:
702 // For PRIMITIVE, VOID, ENUM, etc., the initial shallow copy is sufficient.
703 break;
704 }
705 return dest_type;
706}
707/*
708 * The following functions are simple, null-safe getters that form the public
709 * Introspection API. They provide a stable way for users to query type and
710 * trampoline properties without needing to know the internal layout of the
711 * opaque `infix_type_t`, `infix_forward_t`, or `infix_reverse_t` structs.
712 */
713
714/*
715 * Implementation for infix_type_get_category.
716 * This is a simple, null-safe getter. It returns an invalid category enum
717 * value if the type pointer is null, which is a safe failure mode.
718 */
722
723/*
724 * Implementation for infix_type_get_size.
725 * A simple, null-safe getter. Returns 0 if the type pointer is null, which
726 * is a sensible default for an invalid type.
727 */
729 return type ? type->size : 0;
730}
731
732/*
733 * Implementation for infix_type_get_alignment.
734 * A simple, null-safe getter. Returns 0 if the type pointer is null.
735 */
737 return type ? type->alignment : 0;
738}
739
740/*
741 * Implementation for infix_type_get_member_count.
742 * This getter is both null-safe and type-safe, ensuring we only access
743 * aggregate metadata for struct or union types.
744 */
746 if (!type || (type->category != INFIX_TYPE_STRUCT && type->category != INFIX_TYPE_UNION))
747 return 0;
748 return type->meta.aggregate_info.num_members;
749}
750
751/*
752 * Implementation for infix_type_get_member.
753 * Performs thorough validation (null-check, category check, and bounds check)
754 * before returning a pointer to internal member data.
755 */
757 if (!type || (type->category != INFIX_TYPE_STRUCT && type->category != INFIX_TYPE_UNION))
758 return nullptr;
759 if (index >= type->meta.aggregate_info.num_members)
760 return nullptr;
761 return &type->meta.aggregate_info.members[index];
762}
763
764/*
765 * Implementation for infix_type_get_arg_name.
766 * Performs validation to ensure the type is a function signature and the index
767 * is within bounds before accessing argument metadata.
768 */
769c23_nodiscard const char * infix_type_get_arg_name(const infix_type * func_type, size_t index) {
770 if (!func_type || func_type->category != INFIX_TYPE_REVERSE_TRAMPOLINE)
771 return nullptr;
772 if (index >= func_type->meta.func_ptr_info.num_args) // Allow access to variadic names if present
773 return nullptr;
774 return func_type->meta.func_ptr_info.args[index].name;
775}
776
777/*
778 * Implementation for infix_type_get_arg_type.
779 * Performs validation to ensure the type is a function signature and the index
780 * is within bounds before returning the argument's type.
781 */
782c23_nodiscard const infix_type * infix_type_get_arg_type(const infix_type * func_type, size_t index) {
783 if (!func_type || func_type->category != INFIX_TYPE_REVERSE_TRAMPOLINE)
784 return nullptr;
785 if (index >= func_type->meta.func_ptr_info.num_args)
786 return nullptr;
787 return func_type->meta.func_ptr_info.args[index].type;
788}
789
790/*
791 * Simple null-safe getter for the forward trampoline's argument count.
792 */
794 return trampoline ? trampoline->num_args : 0;
795}
796
803 return trampoline ? trampoline->num_fixed_args : 0;
804}
805
806/*
807 * Simple null-safe getter for the forward trampoline's return type.
808 */
810 return trampoline ? trampoline->return_type : nullptr;
811}
812
813/*
814 * Null-safe and bounds-checked getter for a forward trampoline's argument type.
815 */
816c23_nodiscard const infix_type * infix_forward_get_arg_type(const infix_forward_t * trampoline, size_t index) {
817 if (!trampoline || index >= trampoline->num_args)
818 return nullptr;
819 return trampoline->arg_types[index];
820}
821
822/*
823 * Simple null-safe getter for the reverse trampoline's argument count.
824 */
826 return trampoline ? trampoline->num_args : 0;
827}
828
835 return trampoline ? trampoline->num_fixed_args : 0;
836}
837/*
838 * Simple null-safe getter for the reverse trampoline's return type.
839 */
841 return trampoline ? trampoline->return_type : nullptr;
842}
843
844/*
845 * Null-safe and bounds-checked getter for a reverse trampoline's argument type.
846 */
847c23_nodiscard const infix_type * infix_reverse_get_arg_type(const infix_reverse_t * trampoline, size_t index) {
848 if (!trampoline || index >= trampoline->num_args)
849 return nullptr;
850 return trampoline->arg_types[index];
851}
infix_arena_t * arena
Definition 005_layouts.c:57
infix_status status
Definition 103_unions.c:74
infix_struct_member * members
Definition 103_unions.c:68
#define c23_nodiscard
Definition compat_c23.h:93
@ INFIX_CODE_INTEGER_OVERFLOW
Definition infix.h:1070
@ INFIX_CATEGORY_PARSER
An error that occurred while parsing a signature string.
Definition infix.h:1043
c23_nodiscard size_t infix_type_get_size(const infix_type *type)
Retrieves the size of an infix_type in bytes.
Definition types.c:728
c23_nodiscard const infix_type * infix_type_get_arg_type(const infix_type *func_type, size_t index)
Retrieves the type of a function argument by its index.
Definition types.c:782
c23_nodiscard size_t infix_type_get_alignment(const infix_type *type)
Retrieves the alignment requirement of an infix_type in bytes.
Definition types.c:736
c23_nodiscard size_t infix_forward_get_num_fixed_args(const infix_forward_t *trampoline)
Retrieves the number of fixed (non-variadic) arguments for a forward trampoline.
Definition types.c:802
c23_nodiscard const infix_type * infix_forward_get_return_type(const infix_forward_t *trampoline)
Retrieves the return type for a forward trampoline.
Definition types.c:809
c23_nodiscard const infix_type * infix_forward_get_arg_type(const infix_forward_t *trampoline, size_t index)
Retrieves the type of a specific argument for a forward trampoline.
Definition types.c:816
c23_nodiscard const infix_type * infix_reverse_get_return_type(const infix_reverse_t *trampoline)
Retrieves the return type for a reverse trampoline.
Definition types.c:840
c23_nodiscard size_t infix_reverse_get_num_args(const infix_reverse_t *trampoline)
Retrieves the number of arguments for a reverse trampoline.
Definition types.c:825
c23_nodiscard size_t infix_type_get_member_count(const infix_type *type)
Retrieves the number of members in an aggregate type (struct or union).
Definition types.c:745
c23_nodiscard const char * infix_type_get_arg_name(const infix_type *func_type, size_t index)
Retrieves the name of a function argument by its index.
Definition types.c:769
c23_nodiscard size_t infix_forward_get_num_args(const infix_forward_t *trampoline)
Retrieves the number of arguments for a forward trampoline.
Definition types.c:793
c23_nodiscard infix_type_category infix_type_get_category(const infix_type *type)
Retrieves the fundamental category of an infix_type.
Definition types.c:719
c23_nodiscard const infix_type * infix_reverse_get_arg_type(const infix_reverse_t *trampoline, size_t index)
Retrieves the type of a specific argument for a reverse trampoline.
Definition types.c:847
c23_nodiscard size_t infix_reverse_get_num_fixed_args(const infix_reverse_t *trampoline)
Retrieves the number of fixed (non-variadic) arguments for a reverse trampoline.
Definition types.c:834
c23_nodiscard const infix_struct_member * infix_type_get_member(const infix_type *type, size_t index)
Retrieves a specific member from an aggregate type by its index.
Definition types.c:756
#define infix_memcpy
A macro for copying memory from a source to a destination pointer.
Definition infix.h:290
c23_nodiscard void * infix_arena_alloc(infix_arena_t *, size_t, size_t)
Allocates a block of memory from the arena with a specific alignment.
Definition arena.c:86
infix_status
An enumeration of all possible success or failure codes from the public API.
Definition infix.h:351
@ INFIX_ERROR_ALLOCATION_FAILED
A memory allocation request failed.
Definition infix.h:353
@ INFIX_SUCCESS
The operation completed successfully.
Definition infix.h:352
@ INFIX_ERROR_INVALID_ARGUMENT
An invalid argument was provided to a function.
Definition infix.h:354
c23_nodiscard infix_status infix_type_create_packed_struct(infix_arena_t *arena, infix_type **out_type, size_t total_size, size_t alignment, infix_struct_member *members, size_t num_members)
Creates a new infix_type for a packed struct from an arena.
Definition types.c:519
c23_nodiscard infix_type * infix_type_create_void(void)
Creates an infix_type descriptor for the void type.
Definition types.c:153
infix_primitive_type_id
Enumerates the specific primitive C types supported by the FFI system.
Definition infix.h:133
c23_nodiscard infix_status infix_type_create_union(infix_arena_t *arena, infix_type **out_type, infix_struct_member *members, size_t num_members)
Creates a new infix_type for a union from an arena.
Definition types.c:392
c23_nodiscard infix_status infix_type_create_enum(infix_arena_t *arena, infix_type **out_type, infix_type *underlying_type)
Creates a new infix_type for an enum from an arena.
Definition types.c:289
c23_nodiscard infix_status infix_type_create_vector(infix_arena_t *arena, infix_type **out_type, infix_type *element_type, size_t num_elements)
Creates a new infix_type for a SIMD vector from an arena.
Definition types.c:354
struct infix_struct_member_t infix_struct_member
Describes a single member of an aggregate type (struct or union).
Definition infix.h:94
c23_nodiscard infix_type * infix_type_create_pointer(void)
Creates an infix_type descriptor for a generic void* pointer.
Definition types.c:145
c23_nodiscard infix_status infix_type_create_complex(infix_arena_t *arena, infix_type **out_type, infix_type *base_type)
Creates a new infix_type for a _Complex number from an arena.
Definition types.c:324
struct infix_function_argument_t infix_function_argument
Describes a single argument of a function type, including its optional name.
Definition infix.h:96
infix_type_category
Enumerates the fundamental categories of types supported by the FFI system.
Definition infix.h:114
c23_nodiscard infix_status infix_type_create_array(infix_arena_t *arena, infix_type **out_type, infix_type *element_type, size_t num_elements)
Creates a new infix_type for a fixed-size array from an arena.
Definition types.c:254
c23_nodiscard infix_status infix_type_create_pointer_to(infix_arena_t *arena, infix_type **out_type, infix_type *pointee_type)
Creates an infix_type for a pointer to a specific type from an arena.
Definition types.c:230
infix_aggregate_category_t
Distinguishes between struct and union for named references.
Definition infix.h:151
c23_nodiscard infix_status infix_type_create_struct(infix_arena_t *arena, infix_type **out_type, infix_struct_member *members, size_t num_members)
Creates a new infix_type for a struct from an arena.
Definition types.c:445
c23_nodiscard infix_status infix_type_create_named_reference(infix_arena_t *arena, infix_type **out_type, const char *name, infix_aggregate_category_t agg_cat)
Creates a new infix_type for a named reference from an arena.
Definition types.c:563
c23_nodiscard infix_type * infix_type_create_primitive(infix_primitive_type_id id)
Creates an infix_type descriptor for a primitive C type.
Definition types.c:97
infix_struct_member infix_type_create_member(const char *name, infix_type *type, size_t offset)
A factory function to create an infix_struct_member.
Definition types.c:161
@ INFIX_PRIMITIVE_UINT16
unsigned short, uint16_t
Definition infix.h:137
@ INFIX_PRIMITIVE_UINT32
unsigned int, uint32_t
Definition infix.h:139
@ INFIX_PRIMITIVE_LONG_DOUBLE
long double
Definition infix.h:147
@ INFIX_PRIMITIVE_FLOAT
float
Definition infix.h:145
@ INFIX_PRIMITIVE_DOUBLE
double
Definition infix.h:146
@ INFIX_PRIMITIVE_SINT16
signed short, int16_t
Definition infix.h:138
@ INFIX_PRIMITIVE_SINT64
signed long long, int64_t
Definition infix.h:142
@ INFIX_PRIMITIVE_SINT32
signed int, int32_t
Definition infix.h:140
@ INFIX_PRIMITIVE_UINT8
unsigned char, uint8_t
Definition infix.h:135
@ INFIX_PRIMITIVE_UINT128
__uint128_t (GCC/Clang specific)
Definition infix.h:143
@ INFIX_PRIMITIVE_BOOL
bool or _Bool
Definition infix.h:134
@ INFIX_PRIMITIVE_UINT64
unsigned long long, uint64_t
Definition infix.h:141
@ INFIX_PRIMITIVE_SINT128
__int128_t (GCC/Clang specific)
Definition infix.h:144
@ INFIX_PRIMITIVE_SINT8
signed char, int8_t
Definition infix.h:136
@ INFIX_TYPE_UNION
A user-defined union (union).
Definition infix.h:118
@ INFIX_TYPE_PRIMITIVE
A built-in type like int, float, double.
Definition infix.h:115
@ INFIX_TYPE_COMPLEX
A _Complex number type.
Definition infix.h:122
@ INFIX_TYPE_ARRAY
A fixed-size array.
Definition infix.h:119
@ INFIX_TYPE_VECTOR
A SIMD vector type.
Definition infix.h:123
@ INFIX_TYPE_VOID
The void type, used for function returns with no value.
Definition infix.h:125
@ INFIX_TYPE_POINTER
A generic void* pointer type.
Definition infix.h:116
@ INFIX_TYPE_NAMED_REFERENCE
A reference to a named type (e.g., struct<Node>).
Definition infix.h:124
@ INFIX_TYPE_REVERSE_TRAMPOLINE
A callback wrapper.
Definition infix.h:120
@ INFIX_TYPE_ENUM
A C-style enumeration, with an underlying integer type.
Definition infix.h:121
@ INFIX_TYPE_STRUCT
A user-defined structure (struct).
Definition infix.h:117
Declarations for internal-only functions, types, and constants.
void _infix_set_error(infix_error_category_t, infix_error_code_t, size_t)
Sets the thread-local error details for a library-internal error.
Definition error.c:44
static size_t _infix_align_up(size_t value, size_t alignment)
Definition infix_internals.h:383
static bool is_double(const infix_type *type)
Convenience helper to check if an infix_type is a double.
Definition infix_internals.h:394
void _infix_clear_error(void)
Resets the thread-local error state. Called at the start of every public API function.
Definition error.c:76
static bool is_float(const infix_type *type)
Convenience helper to check if an infix_type is a float.
Definition infix_internals.h:389
Definition infix_internals.h:130
Definition infix_internals.h:72
size_t num_args
The total number of arguments.
Definition infix_internals.h:77
size_t num_fixed_args
The number of non-variadic arguments.
Definition infix_internals.h:78
infix_type ** arg_types
An array of infix_type pointers for each argument.
Definition infix_internals.h:76
infix_type * return_type
The infix_type of the trampoline's return value.
Definition infix_internals.h:75
Describes a single argument to a function, pairing an optional name with its type.
Definition infix.h:229
infix_type * type
An infix_type describing the argument's type.
Definition infix.h:231
const char * name
The name of the argument (for reflection). Can be nullptr if anonymous.
Definition infix.h:230
Definition infix_internals.h:102
infix_type * return_type
The infix_type of the callback's return value.
Definition infix_internals.h:106
size_t num_args
The total number of arguments.
Definition infix_internals.h:108
size_t num_fixed_args
The number of non-variadic arguments.
Definition infix_internals.h:109
infix_type ** arg_types
An array of infix_type pointers for each argument.
Definition infix_internals.h:107
Describes a single member of an aggregate type (struct or union).
Definition infix.h:219
const char * name
The name of the member (for debugging/reflection).
Definition infix.h:220
infix_type * type
An infix_type describing the member's type.
Definition infix.h:221
size_t offset
The byte offset of the member from the start of the aggregate.
Definition infix.h:222
The central structure for describing any data type in the FFI system.
Definition infix.h:161
struct infix_type_t::@0::@1 pointer_info
For INFIX_TYPE_POINTER.
union infix_type_t::@0 meta
Type-specific metadata.
struct infix_type_t::@0::@7 vector_info
For INFIX_TYPE_VECTOR.
struct infix_type_t::@0::@4 func_ptr_info
For INFIX_TYPE_REVERSE_TRAMPOLINE.
size_t num_elements
The number of elements in the array.
Definition infix.h:183
size_t size
The total size of the type in bytes, per sizeof.
Definition infix.h:163
size_t alignment
The alignment requirement of the type in bytes, per _Alignof.
Definition infix.h:164
infix_struct_member * members
Array of members for the aggregate.
Definition infix.h:177
struct infix_type_t::@0::@6 complex_info
For INFIX_TYPE_COMPLEX.
const char * name
Optional name of the aggregate.
Definition infix.h:176
infix_function_argument * args
Array of function arguments (name and type).
Definition infix.h:188
infix_aggregate_category_t aggregate_category
Definition infix.h:208
infix_type_category category
The fundamental category of the type.
Definition infix.h:162
struct infix_type_t::@0::@2 aggregate_info
For INFIX_TYPE_STRUCT and INFIX_TYPE_UNION.
struct infix_type_t::@0::@3 array_info
For INFIX_TYPE_ARRAY.
struct infix_type_t * pointee_type
The type this pointer points to.
Definition infix.h:172
struct infix_type_t * element_type
The type of elements in the array.
Definition infix.h:182
struct infix_type_t * return_type
Reverse trampoline return value.
Definition infix.h:187
struct infix_type_t::@0::@5 enum_info
For INFIX_TYPE_ENUM.
struct infix_type_t * base_type
The floating point type of the real and imaginary parts.
Definition infix.h:198
size_t num_members
Number of members in the aggregate.
Definition infix.h:178
struct infix_type_t * underlying_type
The integer type this enum is based on.
Definition infix.h:194
struct infix_type_t::@0::@8 named_reference
For INFIX_TYPE_NAMED_REFERENCE. This is an internal placeholder for a named type like @Point.
infix_primitive_type_id primitive_id
For INFIX_TYPE_PRIMITIVE.
Definition infix.h:169
size_t num_args
The total number of fixed and variadic arguments.
Definition infix.h:189
bool is_arena_allocated
If true, this type was allocated from an arena and should not be individually freed.
Definition infix.h:165
static infix_type _infix_type_sint128
Definition types.c:78
static infix_type _infix_type_double
Definition types.c:81
static infix_type _infix_type_uint32
Definition types.c:71
static infix_type _infix_type_bool
Definition types.c:66
static infix_type _infix_type_float
Definition types.c:80
infix_type * _copy_type_graph_to_arena(infix_arena_t *dest_arena, const infix_type *src_type)
Performs a deep copy of a type graph from one arena to another.
Definition types.c:610
static infix_type _infix_type_sint64
Definition types.c:74
#define INFIX_TYPE_INIT(id, T)
Definition types.c:45
static infix_type _infix_type_sint16
Definition types.c:70
static infix_type _infix_type_uint16
Definition types.c:69
static infix_type _infix_type_long_double
Definition types.c:88
static infix_type _infix_type_pointer
Definition types.c:60
static infix_type _infix_type_uint128
Definition types.c:77
static infix_type _infix_type_void
Definition types.c:57
static infix_type _infix_type_sint32
Definition types.c:72
static infix_type _infix_type_uint64
Definition types.c:73
static infix_status _create_aggregate_setup(infix_arena_t *arena, infix_type **out_type, infix_struct_member **out_arena_members, infix_struct_member *members, size_t num_members)
Definition types.c:173
static infix_type _infix_type_uint8
Definition types.c:67
static infix_type _infix_type_sint8
Definition types.c:68
A header for conditionally compiled debugging utilities.
#define INFIX_DEBUG_PRINTF(...)
Definition utility.h:100