Affix

 view release on metacpan or  search on metacpan

README.md  view on Meta::CPAN

`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');



( run in 2.550 seconds using v1.01-cache-2.11-cpan-788537b7465 )