Affix

 view release on metacpan or  search on metacpan

lib/Affix.pod  view on Meta::CPAN

If C<$type> is C<Void>, the pointer is "terminal." Dereferencing it will return C<undef>. In this case, use C<cast()>
or C<address()> to work with the raw memory address.

=head3 Specialized Pointers

=over

=item * B<C<File>> / B<C<PerlIO>>: Maps Perl filehandles (Globs or IO objects) to C<FILE*> or C<PerlIO*>. B<Must> be wrapped in a pointer: C<Pointer[File]>.

=item * B<C<SockAddr>>: Specialized marshalling for packed socket strings (e.g., from C<Socket::pack_sockaddr_in>) to C<struct sockaddr*>.

=item * B<C<SV>>: Direct, low-level access to Perl's internal Interpreter Object (C<SV*>). B<Must> be wrapped in a pointer: C<Pointer[SV]>.

=back

=head2 Aggregate Types

=head3 C<Struct[ @members ]>

A C struct, mapped to a Perl C<HashRef>.

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

=head3 C<Union[ @members ]>

A C union, mapped to a Perl C<HashRef> with exactly one key.

    # C: union { int key_code; float pressure; };
    typedef Event => Union[ key_code => Int, pressure => Float ];

=head3 C<Packed[ $aggregate ]> / C<Packed[ $align, $aggregate ]>

Forces specific byte alignment on a Struct or Union (e.g., C<#pragma pack(1)>).

    # Without explicit alignment (default):
    Packed[ Struct[ flag => Char, data => Int ] ];

    # With explicit alignment (e.g., #pragma pack(push, 1)):
    Packed( 1, Struct[ flag => Char, data => Int ] );

=head3 C<Array[ $type, $count ]>

A fixed-size C array. Maps to a Perl C<ArrayRef>.

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

=head3 Bitfields

Specify bit widths using the pipe (C<|>) operator within Structs/Unions. Affix handles all masking and shifting.

    # C: typedef struct { uint32_t a : 1; uint32_t b : 3; } Config;
    typedef Config => Struct[ a => UInt32 | 1, b => UInt32 | 3 ];

=head2 Live Views (Zero-Copy Aggregates)

In Affix, memory structures are live by design. When C returns a pointer to an aggregate (Struct, Union, or Array), or
when you use C<cast()> to overlay a type onto a memory address, Affix does not copy the data.

Instead, it returns a magical Perl reference (blessed into C<Affix::Pointer>) mapped directly to the C memory via Perl
VTables. This means zero-copy performance without the overhead of C<tie>.

Modifying keys or elements in these structures updates C memory immediately, and reading them reads directly from the C
heap.

    # Example: Live view of a struct
    my $live = cast( $ptr, Struct[ x => Int, y => Int ] );
    $live->{x} = 42; # Updates C memory

=head3 Unified Access

Magical C<Affix::Pointer> references allow direct field access (C<< $p->{field} >>) without explicit casting.

    affix $lib, 'get_ptr', [] => Pointer[Point];
    my $p = get_ptr();
    say $p->{x};  # Unified access! Reads directly from C memory.
    $p->{y} = 50; # Writes directly to C memory.

=head2 Callbacks & Functions

=over

=item * B<C<< Callback[ [$params] => $ret ] >>>: Defines the signature of a C function pointer. Allows you to pass Perl subroutines into C functions.

    # C: void set_handler( void (*cb)(int) );
    affix $lib, 'set_handler', [ Callback[ [Int] => Void ] ] => Void;

=item * B<C<ThisCall( $cb_or_sig )>>: Helper for C++-style C<__thiscall> callbacks. Prepends a C<Pointer[Void]> (the C<this> pointer) to the signature.

=back

=head2 Variadic Functions (VarArgs)

Affix supports C functions that take a variable number of arguments (e.g., C<printf>, C<ioctl>). When defining a
signature, use the C<VarArgs> token at the end of the argument list.

=head3 Basic Usage

    # C: int printf(const char* format, ...);
    affix libc(), ['printf' => 'my_printf'], [ String, VarArgs ] => Int;

    # Basic types are marshalled automatically based on Perl's internal state
    my_printf("Integer: %d, String: %s\n", 42, "Hello");

=head3 Explicit Type Control with C<coerce()>

In variadic functions, C relies on the caller to pass data in the exact format the function expects. While Affix
attempts to guess the correct C type for Perl scalars, these guesses might not always match the library's expectations
like passing a 64-bit integer where a 32-bit one is expected, or a float instead of a double.

Use C<coerce( $type, $value )> to explicitly tell Affix how to marshal a variadic argument.

    # Suppose we have a variadic log function that expects specific bit-widths
    # C: void custom_log(int level, ...);
    affix $lib, 'custom_log', [ Int, VarArgs ] => Void;

    custom_log(
        1,
        coerce(Short, 10),    # Explicitly pass as a 16-bit signed int
        coerce(Float, 1.5),    # Explicitly pass as a 32-bit float



( run in 1.211 second using v1.01-cache-2.11-cpan-a49fcb8fa48 )