Affix

 view release on metacpan or  search on metacpan

lib/Affix.pod  view on Meta::CPAN

Creates a wrapper around a given symbol and returns it as an anonymous C<CODE> reference. Arguments are identical to
C<affix> except you cannot provide an alias.

    my $pow = wrap $lib, 'pow', [ Double, Double ] => Double;
    my $result = $pow->( 2, 5 );

=head2 C<< typedef( $name => $type ) >>

Registers a named type alias. This makes signatures more readable and is required for recursive types and smart Enums.

    # C: typedef struct { int x; int y; } Point;
    typedef Point => Struct[ x => Int, y => Int ];

    # C: typedef double Vector3[3];
    typedef Vector3 => Array[ Double, 3 ];

    # C: typedef int* IntPtr;
    typedef IntPtr => Pointer[ Int ];

Once registered, use these types in signatures by calling them as functions: C<Point()>.

=head2 C<coerce( $type, $value )>

Explicitly hints types for L<Variadic Functions|/Variadic Functions (VarArgs)>.

    # Hint that we are passing a Float, not a Double
    coerce( Float, 1.5 );

=head1 VARIABLES & PINNING

Bind Perl scalars directly to C global variables for real-time, two-way access to C memory.

=head2 C<pin( ... )>

Binds a scalar to a C variable. Reading the scalar reads C memory; writing to it updates C memory immediately. Three
calling conventions are supported:

=over

=item B<pin( $var, $lib, $symbol, $type )>

Binds to an exported symbol. This is the most common form.

    # C: extern int errno;
    my $errno;
    pin $errno, libc(), 'errno', Int;

    $errno = 0;   # Writes directly to C memory

=item B<pin( $var, $address, $type )>

Binds to a raw memory address (e.g., from C<find_symbol> or pointer arithmetic).

    my $addr = address($some_ptr);
    pin my $val, $addr, Int;

=item B<pin( $var, $existing_pin )>

Clones the binding from an existing pin (copies the address and type).

    pin my $copy, $original_pin;

=back

=head2 C<unpin( $var )>

Removes the magic applied by C<pin>. The variable retains its last value but is no longer linked to C memory.

=head1 TYPE SYSTEM

Map C types to Perl with a rich, built-in vocabulary. Affix signatures are built using helper functions that map
precisely to C types. These are exported by default, or can be imported explicitly using the C<:types> tag.

=head2 Primitive Types

=head3 Void & Booleans

=over

=item * C<Void>: Used for functions that return nothing (C<void>).

=item * C<Bool>: Mapped to Perl's true/false values (C<stdbool.h> / C<_Bool>).

=back

=head3 Characters

=over

=item * C<Char>: Standard signed C<char> (usually 8-bit).

=item * C<SChar>: Explicitly signed C<signed char>.

=item * C<UChar>: Unsigned C<unsigned char>.

=item * C<WChar>: Wide character (C<wchar_t>), usually 16-bit on Windows and 32-bit on Linux/macOS.

=item * C<Char8>, C<Char16>, C<Char32>: Explicit-width C++ character types (C<char8_t>, etc.).

=back

=head3 Platform-Native Integers

These types map to the system's native bit-widths (e.g., C<Long> is 32-bit on Windows x64, but 64-bit on Linux x64).

=over

=item * C<Short> / C<UShort>: C<short> / C<unsigned short>.

=item * C<Int> / C<UInt>: C<int> / C<unsigned int> (typically 32-bit).

=item * C<Long> / C<ULong>: C<long> / C<unsigned long>.

=item * C<LongLong> / C<ULongLong>: C<long long> / C<unsigned long long> (guaranteed at least 64-bit).

=item * C<Size_t> / C<SSize_t>: Standard memory and array indexing types (C<size_t>, C<ssize_t>).

=back

=head3 Fixed-Width Integers

lib/Affix.pod  view on Meta::CPAN

=back

=head2 SIMD Vectors

Vectors are first-class types. You can interact with them using standard B<ArrayRefs> (convenient) or B<Packed Strings>
(high-performance, zero-overhead).

=over

=item * B<C<Vector[ $size, $type ]>>: Create a custom vector (e.g., C<Vector[ 4, Float ]>).

=item * B<Aliases>: C<M256>, C<M256d>, C<M512>, C<M512d>, C<M512i>.

=back

    # C: __m256 add_vecs(__m256 a, __m256 b);
    affix $lib, 'add_vecs', [ M256, M256 ] => M256;
    my $v1 = pack('f8', 1..8);
    my $v2 = pack('f8', 10, 20, 30, 40, 50, 60, 70, 80);
    my $packed_res = add_vecs( $v1, $v2 );

=head1 MEMORY MANAGEMENT

Allocate, cast, and manage C memory safely from Perl using zero-copy VTable magic. When bridging Perl and C, handling
raw memory safely is critical. Affix uses B<Pins> to manage this boundary.

Affix now features a completely reimagined memory access system using Perl's internal magic to map Perl variables
directly to native C memory. This provides zero-copy performance with the ergonomics of native Perl Hashes and Arrays.

=head2 Managed vs. Unmanaged Memory

Memory in Affix is handled by life lines.

=over

=item * B<Affix::Memory:> Created via C<malloc()> or C<calloc()>. These are root objects. When the Perl variable is destroyed, C<safefree()> is called automatically.

=item * B<Pins:> Created via C<cast()> or pointer dereferencing. These variables do not own the memory, but they hold a reference to a life line to prevent the parent memory from being freed prematurely.

=back

=head2 Allocation & Deallocation

These functions allocate memory on the C heap. Memory allocated via these functions is B<managed by Perl> by default.

=head3 C<malloc( $size )>

Allocates C<$size> bytes of uninitialized memory. Returns a C<Pointer[Void]> pin.

    my $ptr = malloc(1024); # Allocates 1KB

=head3 C<calloc( $count, $size )>

Allocates zero-initialized memory for C<$count> elements of C<$size>. Returns a C<Pointer[Void]> pin.

    my $ptr = calloc( 10, sizeof(Int) );
    my $arr = cast( $ptr, Array[Int, 10] );

=head3 C<realloc( $ptr, $new_size )>

Resizes the memory area pointed to by C<$ptr> to C<$new_size> bytes. The original pin is updated automatically
in-place.

    $ptr = realloc( $ptr, 2048 );

=head3 C<strdup( $string )>

Allocates managed memory and copies the Perl string (along with a C<NULL> terminator) into it. Returns a managed
C<Pointer[Char]> pin.

    my $str_ptr = strdup("Hello C!");

=head3 C<free( $ptr )>

Manually releases memory.

B<Warning:> Only use this on memory that you exclusively own (e.g., allocated via C<malloc>). Do not call C<free> on
unmanaged pointers returned by C libraries unless the library explicitly transfers ownership to you, or you will cause
a segmentation fault.

    free($ptr);

=head3 C<own( $pin )>

Returns true if the given pin is an owned C<Affix::Memory> object (i.e., memory allocated via C<malloc> or C<calloc>
that Perl manages directly). Returns false for unmanaged pins or raw scalars.

    if (own($ptr)) {
        say "Perl owns this memory; it will be freed automatically.";
    }

=head3 C<is_pin( $var )>

Returns true if the variable is currently bound to C memory via C<pin>, C<cast>, or pointer dereferencing. Returns
false for ordinary Perl scalars.

    my $x = 42;
    say is_pin($x); # false

    pin $x, libc(), 'errno', Int;
    say is_pin($x); # true

=head2 Lifecycle & Ownership

=head3 C<attach_destructor( $pin, $func_ptr, [$lib] )>

Attaches a custom C function to be called when the Pin is destroyed. This is incredibly useful for C libraries that
require specific cleanup routines (e.g., C<SDL_DestroyWindow>, C<sqlite3_free>).

    # Find the address of the library's custom free function
    my $free_func = find_symbol($my_lib, 'custom_free');

    # When $ptr goes out of scope, Affix will call custom_free($ptr)
    attach_destructor($ptr, $free_func, $my_lib);

=head3 C<readonly( $pin, [$bool] )>

Gets or sets the "const" status of a memory pin. If set to true, any attempt to write to that memory from Perl will
throw an exception.

    readonly($point, 1);



( run in 0.912 second using v1.01-cache-2.11-cpan-5c0b1e786e0 )