Affix
view release on metacpan or search on metacpan
Registers a named type alias. This makes signatures more readable and is required for recursive types and smart Enums.
```perl
# 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: `Point()`.
## `coerce( $type, $value )`
Explicitly hints types for [Variadic Functions](#variadic-functions-varargs).
```
# Hint that we are passing a Float, not a Double
coerce( Float, 1.5 );
```
# VARIABLES & PINNING
Bind Perl scalars directly to C global variables for real-time, two-way access to C memory.
## `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:
- **pin( $var, $lib, $symbol, $type )**
Binds to an exported symbol. This is the most common form.
```perl
# C: extern int errno;
my $errno;
pin $errno, libc(), 'errno', Int;
$errno = 0; # Writes directly to C memory
```
- **pin( $var, $address, $type )**
Binds to a raw memory address (e.g., from `find_symbol` or pointer arithmetic).
```perl
my $addr = address($some_ptr);
pin my $val, $addr, Int;
```
- **pin( $var, $existing\_pin )**
Clones the binding from an existing pin (copies the address and type).
```perl
pin my $copy, $original_pin;
```
## `unpin( $var )`
Removes the magic applied by `pin`. The variable retains its last value but is no longer linked to C memory.
# 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 `:types` tag.
## Primitive Types
### Void & Booleans
- `Void`: Used for functions that return nothing (`void`).
- `Bool`: Mapped to Perl's true/false values (`stdbool.h` / `_Bool`).
### Characters
- `Char`: Standard signed `char` (usually 8-bit).
- `SChar`: Explicitly signed `signed char`.
- `UChar`: Unsigned `unsigned char`.
- `WChar`: Wide character (`wchar_t`), usually 16-bit on Windows and 32-bit on Linux/macOS.
- `Char8`, `Char16`, `Char32`: Explicit-width C++ character types (`char8_t`, etc.).
### Platform-Native Integers
These types map to the system's native bit-widths (e.g., `Long` is 32-bit on Windows x64, but 64-bit on Linux x64).
- `Short` / `UShort`: `short` / `unsigned short`.
- `Int` / `UInt`: `int` / `unsigned int` (typically 32-bit).
- `Long` / `ULong`: `long` / `unsigned long`.
- `LongLong` / `ULongLong`: `long long` / `unsigned long long` (guaranteed at least 64-bit).
- `Size_t` / `SSize_t`: Standard memory and array indexing types (`size_t`, `ssize_t`).
### Fixed-Width Integers
Use these when a C library explicitly requests a `stdint.h` type.
- `Int8` / `SInt8` / `UInt8`: 8-bit integers (`int8_t`, `uint8_t`).
- `Int16` / `SInt16` / `UInt16`: 16-bit integers (`int16_t`, `uint16_t`).
- `Int32` / `SInt32` / `UInt32`: 32-bit integers (`int32_t`, `uint32_t`).
- `Int64` / `SInt64` / `UInt64`: 64-bit integers (`int64_t`, `uint64_t`).
- `Int128` / `SInt128` / `UInt128`: 128-bit integers. _Note: Because standard Perl scalars cannot hold 128-bit numbers natively, these must be passed to/from Affix as decimal strings._
### Floating Point
- `Float16`: Half-precision 16-bit float (IEEE 754).
- `Float` / `Float32`: Standard 32-bit `float`.
- `Double` / `Float64`: Standard 64-bit `double`.
- `LongDouble`: Platform-specific extended precision (typically 80-bit on x86 or 128-bit).
### Complex Numbers
- `Complex[ $type ]`: C99 complex numbers (e.g., `Complex[Double]`). In Perl, these map to an `ArrayRef` of two numbers: `[ $real, $imaginary ]`.
## String Types
- **`String`**: Maps to `const char*`. Affix handles UTF-8 encoding (Perl to C) and decoding (C to Perl) automatically.
- **Constants:** `typedef` installs constants (e.g., `OK() == 0`) into your package.
- **Dualvars:** Values returned from C act as dualvars. They print as strings (`"OK"`) but evaluate mathematically as integers (`0`).
- **String Marshalling:** You can pass the string name of an element (`"OK"`) directly to functions that expect
that enum type.
- **Aliases:** You can also use `IntEnum[ ... ]`, `CharEnum[ ... ]`, and `UIntEnum[ ... ]` to force the underlying integer size.
## SIMD Vectors
Vectors are first-class types. You can interact with them using standard **ArrayRefs** (convenient) or **Packed Strings**
(high-performance, zero-overhead).
- **`Vector[ $size, $type ]`**: Create a custom vector (e.g., `Vector[ 4, Float ]`).
- **Aliases**: `M256`, `M256d`, `M512`, `M512d`, `M512i`.
```perl
# 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 );
```
# 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 **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.
## Managed vs. Unmanaged Memory
Memory in Affix is handled by life lines.
- **Affix::Memory:** Created via `malloc()` or `calloc()`. These are root objects. When the Perl variable is destroyed, `safefree()` is called automatically.
- **Pins:** Created via `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.
## Allocation & Deallocation
These functions allocate memory on the C heap. Memory allocated via these functions is **managed by Perl** by default.
### `malloc( $size )`
Allocates `$size` bytes of uninitialized memory. Returns a `Pointer[Void]` pin.
```perl
my $ptr = malloc(1024); # Allocates 1KB
```
### `calloc( $count, $size )`
Allocates zero-initialized memory for `$count` elements of `$size`. Returns a `Pointer[Void]` pin.
```perl
my $ptr = calloc( 10, sizeof(Int) );
my $arr = cast( $ptr, Array[Int, 10] );
```
### `realloc( $ptr, $new_size )`
Resizes the memory area pointed to by `$ptr` to `$new_size` bytes. The original pin is updated automatically
in-place.
```
$ptr = realloc( $ptr, 2048 );
```
### `strdup( $string )`
Allocates managed memory and copies the Perl string (along with a `NULL` terminator) into it. Returns a managed
`Pointer[Char]` pin.
```perl
my $str_ptr = strdup("Hello C!");
```
### `free( $ptr )`
Manually releases memory.
**Warning:** Only use this on memory that you exclusively own (e.g., allocated via `malloc`). Do not call `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);
```
### `own( $pin )`
Returns true if the given pin is an owned `Affix::Memory` object (i.e., memory allocated via `malloc` or `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.";
}
```
### `is_pin( $var )`
Returns true if the variable is currently bound to C memory via `pin`, `cast`, or pointer dereferencing. Returns
false for ordinary Perl scalars.
```perl
my $x = 42;
say is_pin($x); # false
pin $x, libc(), 'errno', Int;
say is_pin($x); # true
```
## Lifecycle & Ownership
### `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., `SDL_DestroyWindow`, `sqlite3_free`).
```perl
# Find the address of the library's custom free function
( run in 1.506 second using v1.01-cache-2.11-cpan-5c0b1e786e0 )