Affix
view release on metacpan or search on metacpan
# C: double Vector3[3];
typedef Vector3 => Array[ Double, 3 ];
```
### Bitfields
Declare bitfields inside Structs or Unions using either `Bitfield[ $type, $width ]` or the `|` operator shorthand.
Affix automatically handles masking, shifting, and boundary alignment.
```perl
# Using Bitfield[...]
typedef Config => Struct[
flag_a => Bitfield[ UInt32, 1 ],
flag_b => Bitfield[ UInt32, 3 ]
];
# Using operator shorthand (C: uint32_t a : 1; uint32_t b : 3;)
typedef Config => Struct[
a => UInt32 | 1,
b => UInt32 | 3
];
```
## 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 `cast()` to overlay a type onto a memory address, Affix does not copy the data.
Instead, it returns a magical Perl reference (blessed into `Affix::Pointer`) mapped directly to the C memory via Perl
VTables. This means zero-copy performance without the overhead of `tie`.
Modifying keys or elements in these structures updates C memory immediately, and reading them reads directly from the C
heap.
```perl
# Example: Live view of a struct
my $live = cast( $ptr, Struct[ x => Int, y => Int ] );
$live->{x} = 42; # Updates C memory
```
### Unified Access
Magical `Affix::Pointer` references allow direct field access (`$p->{field}`) without explicit casting.
```perl
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.
```
## Callbacks & Functions
- **`Callback[ [$params] => $ret ]`**: Defines the signature of a C function pointer. Allows you to pass Perl subroutines into C functions.
```perl
# C: void set_handler( void (*cb)(int) );
affix $lib, 'set_handler', [ Callback[ [Int] => Void ] ] => Void;
```
- **`ThisCall( $cb_or_sig )`**: Helper for C++-style `__thiscall` callbacks. Prepends a `Pointer[Void]` (the `this` pointer) to the signature.
## Variadic Functions (VarArgs)
Affix supports C functions that take a variable number of arguments (e.g., `printf`, `ioctl`). Use the `VarArgs`
token in the argument list to mark where variadic arguments begin.
### Basic Usage
For open variadic functions where argument types vary per call:
```perl
# C: int printf(const char* format, ...);
affix libc(), 'printf', [ String, VarArgs ] => Int;
```
For functions where the trailing arguments follow a known pattern, you can also define typed variadics:
```perl
# C: int ioctl(int fd, unsigned long request, ...);
affix libc(), 'ioctl', [ Int, ULong, VarArgs[ Pointer[Void] ] ] => Int;
```
### Explicit Type Control with `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 `coerce( $type, $value )` to explicitly tell Affix how to marshal a variadic argument.
```perl
# 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
coerce(ULong, 1000) # Explicitly pass as a platform-native unsigned long
);
```
Note: Standard C default argument promotions still apply. For example, passing a `Float` to a variadic function will
typically be promoted to a `Double` by the C runtime unless the receiving function specifically handles raw floats.
## Enumerations
```perl
# C: enum Status { OK = 0, ERROR = 1, FLAG_A = 1<<0, FLAG_B = 1<<1 };
typedef Status => Enum[
[ OK => 0 ],
'ERROR', # Auto-increments to 1
[ FLAG_A => 1 << 0 ], # Bit shifting
[ FLAG_B => '1 << 1' ] # String expression
];
```
- **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`).
( run in 2.402 seconds using v1.01-cache-2.11-cpan-b554fb43c41 )