Affix
view release on metacpan or search on metacpan
lib/Affix.pod view on Meta::CPAN
typically be promoted to a C<Double> by the C runtime unless the receiving function specifically handles raw floats.
=head2 Enumerations
# 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
];
=over
=item * B<Constants:> C<typedef> installs constants (e.g., C<OK() == 0>) into your package.
=item * B<Dualvars:> Values returned from C act as dualvars. They print as strings (C<"OK">) but evaluate mathematically as integers (C<0>).
=item * B<String Marshalling:> You can pass the string name of an element (C<"OK">) directly to functions that expect
that enum type.
=item * B<Aliases:> You can also use C<IntEnum[ ... ]>, C<CharEnum[ ... ]>, and C<UIntEnum[ ... ]> to force the underlying integer size.
=back
=head2 SIMD Vectors
Vectors are first-class types. You can interact with them using standard B<ArrayRefs> (convenient) or B<Packed Strings>
(high-performance, zero-overhead).
=over
=item * B<C<Vector[ $size, $type ]>>: Create a custom vector (e.g., C<Vector[ 4, Float ]>).
=item * B<Aliases>: C<M256>, C<M256d>, C<M512>, C<M512d>, C<M512i>.
=back
# 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 );
=head1 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 B<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.
=head2 Managed vs. Unmanaged Memory
Memory in Affix is handled by life lines.
=over
=item * B<Affix::Memory:> Created via C<malloc()> or C<calloc()>. These are root objects. When the Perl variable is destroyed, C<safefree()> is called automatically.
=item * B<Pins:> Created via C<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.
=back
=head2 Allocation & Deallocation
These functions allocate memory on the C heap. Memory allocated via these functions is B<managed by Perl> by default.
=head3 C<malloc( $size )>
Allocates C<$size> bytes of uninitialized memory. Returns a C<Pointer[Void]> pin.
my $ptr = malloc(1024); # Allocates 1KB
=head3 C<calloc( $count, $size )>
Allocates zero-initialized memory for C<$count> elements of C<$size>. Returns a C<Pointer[Void]> pin.
my $ptr = calloc( 10, sizeof(Int) );
my $arr = cast( $ptr, Array[Int, 10] );
=head3 C<realloc( $ptr, $new_size )>
Resizes the memory area pointed to by C<$ptr> to C<$new_size> bytes. The original pin is updated automatically
in-place.
$ptr = realloc( $ptr, 2048 );
=head3 C<strdup( $string )>
Allocates managed memory and copies the Perl string (along with a C<NULL> terminator) into it. Returns a managed
C<Pointer[Char]> pin.
my $str_ptr = strdup("Hello C!");
=head3 C<free( $ptr )>
Manually releases memory.
B<Warning:> Only use this on memory that you exclusively own (e.g., allocated via C<malloc>). Do not call C<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);
=head3 C<own( $pin )>
Returns true if the given pin is an owned C<Affix::Memory> object (i.e., memory allocated via C<malloc> or C<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.";
}
=head3 C<is_pin( $var )>
Returns true if the variable is currently bound to C memory via C<pin>, C<cast>, or pointer dereferencing. Returns
false for ordinary Perl scalars.
my $x = 42;
say is_pin($x); # false
lib/Affix.pod view on Meta::CPAN
=head3 C<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 C<dump()>.
=head3 C<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.
=head1 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.
=over
=item * C<memcpy( $dest, $src, $bytes )>: Copies exactly C<$bytes> from C<$src> to C<$dest>.
=item * C<memmove( $dest, $src, $bytes )>: Copies C<$bytes> from C<$src> to C<$dest>. Safe to use if the memory regions overlap.
=item * C<memset( $ptr, $byte_val, $bytes )>: Fills the first C<$bytes> of the memory block with the value C<$byte_val>.
=item * C<memcmp( $ptr1, $ptr2, $bytes )>: Compares the first C<$bytes> of two memory blocks. Returns an integer less than, equal to, or greater than zero.
=item * C<memchr( $ptr, $byte_val, $bytes )>: Locates the first occurrence of C<$byte_val> within the first C<$bytes> of the memory block. Returns a new Pin pointing to the match, or C<undef>.
=back
=head1 C<Const> & Readonly Memory
Enforce C's const contract at the Perl level. Affix intercepts writes to read-only memory and throws a fatal exception:
C<Modification of a read-only C value attempted>.
=head2 Declarative Const: C<Const[ $type ]>
You can wrap any type in C<Const[ ... ]> within a signature.
# C: void process(const char* name, const int* values);
affix $lib, 'process', [ Const[String], Pointer[ Const[Int] ] ] => Void;
=head2 Imperative Const: C<readonly( $pin, [$bool] )>
The C<readonly()> function allows you to inspect or toggle the const status of a Pin or Aggregate at runtime. This acts
as an I<FFI Escape Hatch> (similar to C<const_cast> in C++).
my $point = cast($addr, Struct[ x => Int, y => Int ]);
readonly($point, 1); # Lock the entire struct
$point->{x} = 10; # FATAL ERROR
=head2 Recursive Protection
When an aggregate (Struct or Array) is marked as read-only, Affix automatically propagates that protection to all of
its members.
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
=head2 Casting with Const
When using C<cast( ... )>, you can prepend a C<+> to the type signature to create an immutable view of a raw memory
address.
my $view = cast($raw_addr, Const[MyStruct]);
# $view is now a read-only HashRef mapping to C memory.
=head1 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.
=head3 Native Array Indexing
C Arrays are traversed using standard Perl array syntax.
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!
=head3 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 (C<Can't use an undefined
value as a HASH reference>).
=head1 LIBRARIES & SYMBOLS
Load and inspect dynamic libraries across platforms. Affix's smart discovery engine handles varying extensions,
prefixes, and search paths automatically.
=head2 Library Discovery
When you provide a bare library name (e.g., C<'z'>, C<'ssl'>, C<'user32'>) rather than an absolute path, Affix
automatically formats the name for the current platform (e.g., C<libz.so>, C<libz.dylib>, C<z.dll>) and searches the
following locations in order:
=over
=item 1. B<Standard System Paths:> Windows C<System32>/C<SysWOW64>; Unix C</usr/local/lib>, C</usr/lib>, C</lib>, C</usr/lib/system>.
=item 2. B<Environment Variables:> Paths defined in C<LD_LIBRARY_PATH>, C<DYLD_LIBRARY_PATH>, C<DYLD_FALLBACK_LIBRARY_PATH>, or C<PATH>.
=item 3. B<Local Paths:> The current working directory (C<.>) and its C<lib/> subdirectory.
=back
=head2 Functions
=head3 C<load_library( $path_or_name )>
Locates and loads a dynamic library into memory, returning an opaque C<Affix::Lib> handle.
my $lib = load_library('sqlite3');
( run in 1.858 second using v1.01-cache-2.11-cpan-364913b4093 )