Affix

 view release on metacpan or  search on metacpan

README.md  view on Meta::CPAN

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`).
- **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.";

README.md  view on Meta::CPAN


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



( run in 1.131 second using v1.01-cache-2.11-cpan-364913b4093 )