Affix
view release on metacpan or search on metacpan
`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
my $free_func = find_symbol($my_lib, 'custom_free');
# When $ptr goes out of scope, Affix will call custom_free($ptr)
attach_destructor($ptr, $free_func, $my_lib);
```
### `readonly( $pin, [$bool] )`
Gets or sets the "const" status of a memory pin. If set to true, any attempt to write to that memory from Perl will
throw an exception.
```
readonly($point, 1);
$point->{x} = 20; # CRASH: Modification of a read-only C value
```
## Type Casting
### `cast( $ptr, $type )`
The most powerful tool in the memory kit. It "overlays" a C type definition onto a raw memory address.
```perl
my $mem = malloc(16);
my $point = cast($mem, Struct[ x => Int, y => Int ]);
$point->{x} = 10;
```
# POINTER UTILITIES
Navigate and inspect raw pointers with helper functions for address arithmetic, null checks, and more.
### `address( $ptr )`
Returns the virtual memory address of the pointer as a Perl Unsigned Integer (`UInt64`). Useful for passing addresses
to other FFI libraries or debugging.
```
say sprintf("Address: 0x%X", address($ptr));
```
### `ptr_add( $ptr, $offset_bytes )`
Returns a new **unmanaged alias Pin** offset by `$offset_bytes`.
```perl
my $int_arr = calloc(10, Int);
my $next_elem = ptr_add($int_arr, sizeof(Int));
```
_Note: If `$ptr` is an Array type, `ptr_add` correctly decays the returned pin into a Pointer to the element type._
### `ptr_diff( $ptr1, $ptr2 )`
Returns the byte difference (`$ptr1 - $ptr2`) between two pointers as an integer.
### `is_null( $ptr )`
Returns true if the address is `NULL` (`0x0`).
### `strnlen( $ptr, $max )`
Safe string length calculation. Checks the pointer for a `NULL` terminator, scanning at most `$max` bytes.
### `raw( $ptr, $length_in_bytes )`
Returns a Perl string containing the raw, un-decoded binary data extracted directly from the memory address. This is
the programmatic, binary equivalent of `dump()`.
### `snapshot( $pin )`
Deeply reads the C memory backing a Pin and returns a pure, non-magical native Perl data structure (ArrayRef, HashRef,
or Scalar). Because it does not apply VTable magic to the returned values, reading elements from the returned structure
in a bulk operation (like summing a 10,000 element array) is exceptionally fast.
# Raw Memory Operations
Classic C memory functions (memcpy, memset, etc.) available directly from Perl for high-performance byte manipulation.
These functions accept either Pins or raw integer addresses.
- `memcpy( $dest, $src, $bytes )`: Copies exactly `$bytes` from `$src` to `$dest`.
- `memmove( $dest, $src, $bytes )`: Copies `$bytes` from `$src` to `$dest`. Safe to use if the memory regions overlap.
- `memset( $ptr, $byte_val, $bytes )`: Fills the first `$bytes` of the memory block with the value `$byte_val`.
- `memcmp( $ptr1, $ptr2, $bytes )`: Compares the first `$bytes` of two memory blocks. Returns an integer less than, equal to, or greater than zero.
- `memchr( $ptr, $byte_val, $bytes )`: Locates the first occurrence of `$byte_val` within the first `$bytes` of the memory block. Returns a new Pin pointing to the match, or `undef`.
# `Const` & Readonly Memory
Enforce C's const contract at the Perl level. Affix intercepts writes to read-only memory and throws a fatal exception:
`Modification of a read-only C value attempted`.
## Declarative Const: `Const[ $type ]`
You can wrap any type in `Const[ ... ]` within a signature.
```perl
# C: void process(const char* name, const int* values);
affix $lib, 'process', [ Const[String], Pointer[ Const[Int] ] ] => Void;
```
## Imperative Const: `readonly( $pin, [$bool] )`
The `readonly()` function allows you to inspect or toggle the const status of a Pin or Aggregate at runtime. This acts
as an _FFI Escape Hatch_ (similar to `const_cast` in C++).
```perl
my $point = cast($addr, Struct[ x => Int, y => Int ]);
readonly($point, 1); # Lock the entire struct
$point->{x} = 10; # FATAL ERROR
```
## Recursive Protection
When an aggregate (Struct or Array) is marked as read-only, Affix automatically propagates that protection to all of
its members.
```perl
my $rect = cast($addr, Const[Struct[top => Struct[ x => Int, y => Int ], bottom => Struct[ x => Int, y => Int ] ]]);
# Even though 'x' wasn't explicitly marked Const, it inherited protection
# from the parent struct.
$rect->{top}{x} = 5; # FATAL ERROR
```
## Casting with Const
When using `cast( ... )`, you can prepend a `+` to the type signature to create an immutable view of a raw memory
address.
```perl
my $view = cast($raw_addr, Const[MyStruct]);
# $view is now a read-only HashRef mapping to C memory.
```
# Zero-copy Aggregates
Structs, unions, and arrays map directly to C memoryâno deep copies required. When C returns a pointer to an
aggregate, Affix wraps it in a magical Perl reference that reads and writes C memory in real time.
### Native Array Indexing
C Arrays are traversed using standard Perl array syntax.
```perl
typedef Task => Struct[ id => Int, name => String ];
affix $lib, 'get_tasks', [] => Pointer[ Array[ Task(), 10 ] ];
my $tasks = get_tasks();
$tasks->[5]{id} = 404; # Writes directly to C memory!
```
### Deep Null Safety
Traversing a \`NULL\` pointer in C causes a segfault. Affix wraps C memory in Perl safety rails. If you try to traverse a
\`NULL\` pointer inside a struct, Affix intercepts it and throws a standard Perl exception (`Can't use an undefined
value as a HASH reference`).
# LIBRARIES & SYMBOLS
Load and inspect dynamic libraries across platforms. Affix's smart discovery engine handles varying extensions,
prefixes, and search paths automatically.
## Library Discovery
When you provide a bare library name (e.g., `'z'`, `'ssl'`, `'user32'`) rather than an absolute path, Affix
automatically formats the name for the current platform (e.g., `libz.so`, `libz.dylib`, `z.dll`) and searches the
following locations in order:
- 1. **Standard System Paths:** Windows `System32`/`SysWOW64`; Unix `/usr/local/lib`, `/usr/lib`, `/lib`, `/usr/lib/system`.
- 2. **Environment Variables:** Paths defined in `LD_LIBRARY_PATH`, `DYLD_LIBRARY_PATH`, `DYLD_FALLBACK_LIBRARY_PATH`, or `PATH`.
- 3. **Local Paths:** The current working directory (`.`) and its `lib/` subdirectory.
## Functions
### `load_library( $path_or_name )`
Locates and loads a dynamic library into memory, returning an opaque `Affix::Lib` handle.
```perl
my $lib = load_library('sqlite3');
```
**Lifecycle:** Library handles are thread-safe and internally reference-counted. The underlying OS library is only
closed (e.g., via `dlclose` or `FreeLibrary`) when all Affix wrappers and pins relying on it are destroyed.
_Note:_ When using `affix()` or `wrap()`, you can safely pass the string name directly (e.g., `affix('sqlite3',
...)`) and Affix will call `load_library` for you internally. If you pass `undef` instead of a library name, Affix
will search the currently running executable process.
### `locate_lib( $name, [$version] )`
Searches for a library using Affix's discovery engine and returns its absolute file path as a string. It **does not**
load the library into memory. This is useful if you need to pass the library path to another tool or check for its
existence.
```perl
# Find libssl.so.1.1 or libssl.1.1.dylib
my $path = locate_lib('ssl', '1.1');
say "Found SSL at: $path" if $path;
```
### `find_symbol( $lib_handle, $symbol_name )`
Looks up an exported symbol (function or global variable) inside an already-loaded `Affix::Lib` handle. Returns an
unmanaged `Affix::Pointer` (Pin) of type `Pointer[Void]` pointing to the memory address of the symbol.
```perl
my $lib = load_library('m');
# Get the raw memory address of the 'pow' function
my $pow_ptr = find_symbol($lib, 'pow');
if ($pow_ptr) {
say sprintf("pow() is located at: 0x%X", address($pow_ptr));
}
( run in 1.504 second using v1.01-cache-2.11-cpan-b16cb0d3907 )