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 )