Affix

 view release on metacpan or  search on metacpan

lib/Affix.pod  view on Meta::CPAN

    # Raw pointer: Bind a specific memory address (e.g., from dlsym or JIT)
    affix undef,[ $ptr => 'my_func' ], [Int] => Void;

On success, installs the subroutine and returns the generated code reference.

=head2 C<wrap( $lib, $symbol, $params, $return )>

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<direct_affix( ... )> / C<direct_wrap( ... )>

B<Experimental:> Bypasses standard safety checks and intermediate processing for maximum performance with simple
primitives. Generates highly specialized trampolines that read Perl SVs directly from the stack.

=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

Affix allows you to link Perl scalars directly to global or external variables exported by C libraries.

=head2 C<pin( $var, $lib, $symbol, $type )>

Binds a scalar to a C variable. Reading the scalar reads C memory; writing to it updates C memory immediately.

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

    $errno = 0;   # Writes directly to C memory

=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

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

Use these when a C library explicitly requests a C<stdint.h> type.

=over

=item * C<Int8> / C<SInt8> / C<UInt8>: 8-bit integers (C<int8_t>, C<uint8_t>).

=item * C<Int16> / C<SInt16> / C<UInt16>: 16-bit integers (C<int16_t>, C<uint16_t>).

=item * C<Int32> / C<SInt32> / C<UInt32>: 32-bit integers (C<int32_t>, C<uint32_t>).

=item * C<Int64> / C<SInt64> / C<UInt64>: 64-bit integers (C<int64_t>, C<uint64_t>).

=item * C<Int128> / C<SInt128> / C<UInt128>: 128-bit integers. I<Note: Because standard Perl scalars cannot hold 128-bit numbers natively, these must be passed to/from Affix as decimal strings.>

=back

=head3 Floating Point

=over

=item * C<Float16>: Half-precision 16-bit float (IEEE 754).

=item * C<Float> / C<Float32>: Standard 32-bit C<float>.

=item * C<Double> / C<Float64>: Standard 64-bit C<double>.

=item * C<LongDouble>: Platform-specific extended precision (typically 80-bit on x86 or 128-bit).

=back

=head3 Complex Numbers

=over

=item * C<Complex[ $type ]>: C99 complex numbers (e.g., C<Complex[Double]>). In Perl, these map to an C<ArrayRef> of two numbers: C<[ $real, $imaginary ]>.

=back

=head2 String Types

=over

=item * B<C<String>>: Maps to C<const char*>. Affix handles UTF-8 encoding (Perl to C) and decoding (C to Perl) automatically.

=item * B<C<WString>>: Maps to C<const wchar_t*>. Affix automatically handles UTF-16/UTF-32 conversions, including Windows Surrogate Pairs.

=item * B<C<StringList>>: Maps a Perl C<ArrayRef> of strings to a null-terminated C<char**> array (common in C APIs like C<execve> or C<main(argc, argv)>).

=item * B<C<Buffer>>: Maps a mutable C<char*> to the raw memory buffer of a Perl scalar. B<Zero-copy>. The scalar must have pre-allocated capacity (e.g., C<"\0" x 1024>).

=back

=head2 Pointer & Reference Types

=head3 C<Pointer[ $type ]>

A pointer to another type. When used as an argument, you can pass a B<reference to a scalar> for automatic temporary
allocation and write-back.

    # C: void get_val(int *val);
    affix $lib, 'get_val', [ Pointer[Int] ] => Void;
    my $val = 0;
    get_val(\$val);
    say $val; # Updated by C

=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[ $align, $aggregate ]>

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

    # C: #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)

Standard structs and arrays copy data between Perl and C. Live views allow you to directly manipulate C memory through
Perl references.

C<Live[ $type ]> Returns a live, zero-copy view of the memory as defined by C<$type>.

If C<$type> is a C<Struct> or C<Union>, it returns an C<Affix::Live> tied hash. Modifying keys in this hash updates C
memory immediately.

If C<$type> is an C<Array>, it returns an C<Affix::Pointer> object. Modifying elements (e.g. C<< $arr->[0] = 5 >>)
writes directly to memory.

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

=head3 Unified Access

C<Affix::Pointer> objects for aggregates 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;

lib/Affix.pod  view on Meta::CPAN

=over

=item 1. B<Prevent Mangling:> Wrap your exported functions in C<extern "C"> to ensure they have predictable names.

    extern "C" {
        int add(int a, int b) { return a + b; }
    }

=item 2. B<Or Use Mangled Names:> If you cannot change the C++ source, you must look up the exact mangled name (e.g., C<_Z3addii>) using tools like C<nm> or C<objdump>, and bind to that.

=item 3. B<Object Methods:> Calling an object's method requires passing the object instance pointer (the C<this> pointer) as the first argument. Use the C<ThisCall( ... )> wrapper around your callback/signature to automatically insert C<Pointer[Void]...

=back

=head2 Rust

Rust does not use the C ABI by default. You must explicitly instruct the compiler to format the function correctly.

=over

=item 1. B<Exporting:> Use C<#[no_mangle]> and C<pub extern "C">.

    #[no_mangle]
    pub extern "C" fn add(a: i32, b: i32) -> i32 { a + b }

=item 2. B<Structs:> Rust structs must be annotated with C<#[repr(C)]> to guarantee their memory layout matches C (and thus Affix's C<Struct>).

=item 3. B<Strings:> Rust strings are not null-terminated. You must receive C<String> arguments as C<*const std::os::raw::c_char> and convert them using C<CStr::from_ptr>.

=back

=head2 Fortran

Fortran relies heavily on pass-by-reference.

=over

=item 1. B<Pointers Everywhere:> Unless a parameter uses the modern Fortran C<VALUE> attribute, you must pass everything as a pointer. If the function expects a Float, your Affix signature must be C<Pointer[Float]>.

=item 2. B<Name Mangling:> Most Fortran compilers convert subroutine names to lowercase and append an underscore. A Fortran subroutine named C<CALC_STRESS> will likely be exported as C<calc_stress_>.

=item 3. B<Strings:> Fortran does not use null-terminated strings. When passing character arrays, Fortran compilers silently append hidden "length" parameters at the B<end> of the argument list (passed by value as integers).

=back

=head2 Assembly

When writing raw Assembly (NASM/GAS), you must manually adhere to the calling convention of your target platform:

=over

=item * B<Linux/macOS (System V AMD64 ABI):> Arguments are passed in C<rdi, rsi, rdx, rcx, r8, r9>, with the rest on the stack.

=item * B<Windows (Microsoft x64):> Arguments are passed in C<rcx, rdx, r8, r9>, with "shadow space" reserved on the stack.

=back

=head2 Go

Go libraries can be loaded if they are compiled with C<-buildmode=c-shared>. Note that Go slices and strings contain
internal metadata (length/capacity) and do not map directly to C arrays or C<char*>. Use the C<C> package inside Go
(C<import "C">) and C<*C.char> to bridge the boundary.

=head1 ERROR HANDLING & DEBUGGING

Bridging two entirely different runtimes can lead to spectacular crashes if types or memory boundaries are mismatched.
Affix provides built-in tools to help you identify what went wrong.

=head2 Error Handling

=head3 C<errno()>

Accesses the system error code from the most recent FFI or standard library call (reads C<errno> on Unix and
C<GetLastError> on Windows).

This function returns a B<dualvar>. It behaves as an integer in numeric context, and magically resolves to the
human-readable system error message (via C<strerror> or C<FormatMessage>) in string context.

    # Suppose a C file-open function fails
    my $fd = c_open("/does/not/exist");
    if (!$fd) {
        my $err = errno();

        # String context
        say "Failed to open: $err"; # "No such file or directory"

        # Numeric context
        if (int($err) == 2) {
            say "Code 2 specifically triggered.";
        }
    }

B<Note:> You must call C<errno()> immediately after the C function invokes, as subsequent Perl operations (like
printing to STDOUT) might overwrite the system's error register.

=head2 Memory Inspection

=head3 C<dump( $pin, $length_in_bytes )>

Prints a formatted hex dump of the memory pointed to by a Pin directly to C<STDOUT>. This is an invaluable tool for
verifying that C structs or buffers contain the data you expect.

    my $ptr = strdup("Affix Debugging");
    dump($ptr, 16);

    # Output:
    # Dumping 16 bytes from 0x55E9A8A5 at script.pl line 42
    #  000  41 66 66 69 78 20 44 65 62 75 67 67 69 6e 67 00 | Affix Debugging.

=head3 C<sv_dump( $scalar )>

Dumps Perl's internal interpreter structure (SV) for a given scalar to C<STDOUT>. This exposes the raw flags, reference
counts, and memory layout of the Perl variable itself.

    my $val = 42;
    sv_dump($val);
    # Exposes IV flags, memory addresses of the SV head, etc.

=head2 Advanced Debugging

=head3 C<set_destruct_level( $level )>



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