Affix

 view release on metacpan or  search on metacpan

README.md  view on Meta::CPAN

`affix` except you cannot provide an alias.

```perl
my $pow = wrap $lib, 'pow', [ Double, Double ] => Double;
my $result = $pow->( 2, 5 );
```

## `direct_affix( ... )` / `direct_wrap( ... )`

**Experimental:** Bypasses standard safety checks and intermediate processing for maximum performance with simple
primitives. Generates highly specialized trampolines that read Perl SVs directly from the stack.

## `typedef( $name => $type )`

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

Affix allows you to link Perl scalars directly to global or external variables exported by C libraries.

## `pin( $var, $lib, $symbol, $type )`

Binds a scalar to a C variable. Reading the scalar reads C memory; writing to it updates C memory immediately.

```perl
# C: extern int errno;
my $errno;
pin $errno, libc(), 'errno', Int;

$errno = 0;   # Writes directly to C memory
```

## `unpin( $var )`

Removes the magic applied by `pin`. The variable retains its last value but is no longer linked to C memory.

# TYPE SYSTEM

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.
- **`WString`**: Maps to `const wchar_t*`. Affix automatically handles UTF-16/UTF-32 conversions, including Windows Surrogate Pairs.
- **`StringList`**: Maps a Perl `ArrayRef` of strings to a null-terminated `char**` array (common in C APIs like `execve` or `main(argc, argv)`).
- **`Buffer`**: Maps a mutable `char*` to the raw memory buffer of a Perl scalar. **Zero-copy**. The scalar must have pre-allocated capacity (e.g., `"\0" x 1024`).

## Pointer & Reference Types

### `Pointer[ $type ]`

A pointer to another type. When used as an argument, you can pass a **reference to a scalar** for automatic temporary
allocation and write-back.

```perl
# C: void get_val(int *val);
affix $lib, 'get_val', [ Pointer[Int] ] => Void;
my $val = 0;
get_val(\$val);
say $val; # Updated by C
```

### Specialized Pointers

- **`File`** / **`PerlIO`**: Maps Perl filehandles (Globs or IO objects) to `FILE*` or `PerlIO*`. **Must** be wrapped in a pointer: `Pointer[File]`.
- **`SockAddr`**: Specialized marshalling for packed socket strings (e.g., from `Socket::pack_sockaddr_in`) to `struct sockaddr*`.
- **`SV`**: Direct, low-level access to Perl's internal Interpreter Object (`SV*`). **Must** be wrapped in a pointer: `Pointer[SV]`.

## Aggregate Types

### `Struct[ @members ]`

A C struct, mapped to a Perl `HashRef`.

```perl
# C: typedef struct { int x; int y; } Point;
typedef Point => Struct[ x => Int, y => Int ];
```

### `Union[ @members ]`

A C union, mapped to a Perl `HashRef` with exactly one key.

```perl
# C: union { int key_code; float pressure; };
typedef Event => Union[ key_code => Int, pressure => Float ];
```

### `Packed[ $align, $aggregate ]`

Forces specific byte alignment on a Struct or Union (e.g., `#pragma pack(1)`).

```perl
# C: #pragma pack(push, 1) ...
Packed[ 1, Struct[ flag => Char, data => Int ] ];
```

### `Array[ $type, $count ]`

A fixed-size C array. Maps to a Perl `ArrayRef`.

```perl
# C: double Vector3[3];
typedef Vector3 => Array[ Double, 3 ];
```

### Bitfields

Specify bit widths using the pipe (`|`) operator within Structs/Unions. Affix handles all masking and shifting.

```perl
# C: typedef struct { uint32_t a : 1; uint32_t b : 3; } Config;
typedef Config => Struct[ a => UInt32 | 1, b => UInt32 | 3 ];
```

## Live Views (Zero-Copy Aggregates)

Standard structs and arrays copy data between Perl and C. Live views allow you to directly manipulate C memory through
Perl references.

`Live[ $type ]` Returns a live, zero-copy view of the memory as defined by `$type`.

If `$type` is a `Struct` or `Union`, it returns an `Affix::Live` tied hash. Modifying keys in this hash updates C
memory immediately.

If `$type` is an `Array`, it returns an `Affix::Pointer` object. Modifying elements (e.g. `$arr->[0] = 5`)
writes directly to memory.

```perl
# Example: Live view of a struct
my $live = cast( $ptr, Live[ Struct[ x => Int, y => Int ] ] );
$live->{x} = 42; # Updates C memory
```

### Unified Access

`Affix::Pointer` objects for aggregates 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.

README.md  view on Meta::CPAN

my @known_types = types();
say "Registered types: " . join(', ', @known_types);
```

# INTERFACING WITH OTHER LANGUAGES

Because Affix dynamically loads symbols according to the C Application Binary Interface (C ABI), it can interact with
libraries written in almost any language, provided they expose their functions correctly. Companion modules like
[Affix::Build](https://metacpan.org/pod/Affix%3A%3ABuild) make compiling these languages seamless.

Here are the requirements and quirks for interfacing with non-C languages.

## C++

C++ uses "name mangling" to support function overloading and namespaces, which alters the final symbol name inside the
compiled library.

- 1. **Prevent Mangling:** Wrap your exported functions in `extern "C"` to ensure they have predictable names.

    ```
    extern "C" {
        int add(int a, int b) { return a + b; }
    }
    ```

- 2. **Or Use Mangled Names:** If you cannot change the C++ source, you must look up the exact mangled name (e.g., `_Z3addii`) using tools like `nm` or `objdump`, and bind to that.
- 3. **Object Methods:** Calling an object's method requires passing the object instance pointer (the `this` pointer) as the first argument. Use the `ThisCall( ... )` wrapper around your callback/signature to automatically insert `Pointer[Void]` at t...

## Rust

Rust does not use the C ABI by default. You must explicitly instruct the compiler to format the function correctly.

- 1. **Exporting:** Use `#[no_mangle]` and `pub extern "C"`.

    ```rust
    #[no_mangle]
    pub extern "C" fn add(a: i32, b: i32) -> i32 { a + b }
    ```

- 2. **Structs:** Rust structs must be annotated with `#[repr(C)]` to guarantee their memory layout matches C (and thus Affix's `Struct`).
- 3. **Strings:** Rust strings are not null-terminated. You must receive `String` arguments as `*const std::os::raw::c_char` and convert them using `CStr::from_ptr`.

## Fortran

Fortran relies heavily on pass-by-reference.

- 1. **Pointers Everywhere:** Unless a parameter uses the modern Fortran `VALUE` attribute, you must pass everything as a pointer. If the function expects a Float, your Affix signature must be `Pointer[Float]`.
- 2. **Name Mangling:** Most Fortran compilers convert subroutine names to lowercase and append an underscore. A Fortran subroutine named `CALC_STRESS` will likely be exported as `calc_stress_`.
- 3. **Strings:** Fortran does not use null-terminated strings. When passing character arrays, Fortran compilers silently append hidden "length" parameters at the **end** of the argument list (passed by value as integers).

## Assembly

When writing raw Assembly (NASM/GAS), you must manually adhere to the calling convention of your target platform:

- **Linux/macOS (System V AMD64 ABI):** Arguments are passed in `rdi, rsi, rdx, rcx, r8, r9`, with the rest on the stack.
- **Windows (Microsoft x64):** Arguments are passed in `rcx, rdx, r8, r9`, with "shadow space" reserved on the stack.

## Go

Go libraries can be loaded if they are compiled with `-buildmode=c-shared`. Note that Go slices and strings contain
internal metadata (length/capacity) and do not map directly to C arrays or `char*`. Use the `C` package inside Go
(`import "C"`) and `*C.char` to bridge the boundary.

# ERROR HANDLING & DEBUGGING

Bridging two entirely different runtimes can lead to spectacular crashes if types or memory boundaries are mismatched.
Affix provides built-in tools to help you identify what went wrong.

## Error Handling

### `errno()`

Accesses the system error code from the most recent FFI or standard library call (reads `errno` on Unix and
`GetLastError` on Windows).

This function returns a **dualvar**. It behaves as an integer in numeric context, and magically resolves to the
human-readable system error message (via `strerror` or `FormatMessage`) in string context.

```perl
# Suppose a C file-open function fails
my $fd = c_open("/does/not/exist");
if (!$fd) {
    my $err = errno();

    # String context
    say "Failed to open: $err"; # "No such file or directory"

    # Numeric context
    if (int($err) == 2) {
        say "Code 2 specifically triggered.";
    }
}
```

**Note:** You must call `errno()` immediately after the C function invokes, as subsequent Perl operations (like
printing to STDOUT) might overwrite the system's error register.

## Memory Inspection

### `dump( $pin, $length_in_bytes )`

Prints a formatted hex dump of the memory pointed to by a Pin directly to `STDOUT`. This is an invaluable tool for
verifying that C structs or buffers contain the data you expect.

```perl
my $ptr = strdup("Affix Debugging");
dump($ptr, 16);

# Output:
# Dumping 16 bytes from 0x55E9A8A5 at script.pl line 42
#  000  41 66 66 69 78 20 44 65 62 75 67 67 69 6e 67 00 | Affix Debugging.
```

### `sv_dump( $scalar )`

Dumps Perl's internal interpreter structure (SV) for a given scalar to `STDOUT`. This exposes the raw flags, reference
counts, and memory layout of the Perl variable itself.

```perl
my $val = 42;
sv_dump($val);



( run in 1.231 second using v1.01-cache-2.11-cpan-39bf76dae61 )