Affix

 view release on metacpan or  search on metacpan

lib/Affix.pod  view on Meta::CPAN

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

B<Lifecycle:> Library handles are thread-safe and internally reference-counted. The underlying OS library is only
closed (e.g., via C<dlclose> or C<FreeLibrary>) when all Affix wrappers and pins relying on it are destroyed.

I<Note:> When using C<affix()> or C<wrap()>, you can safely pass the string name directly (e.g., C<affix('sqlite3',
...)>) and Affix will call C<load_library> for you internally. If you pass C<undef> instead of a library name, Affix
will search the currently running executable process.

=head3 C<locate_lib( $name, [$version] )>

Searches for a library using Affix's discovery engine and returns its absolute file path as a string. It B<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.

    # Find libssl.so.1.1 or libssl.1.1.dylib
    my $path = locate_lib('ssl', '1.1');
    say "Found SSL at: $path" if $path;

=head3 C<find_symbol( $lib_handle, $symbol_name )>

Looks up an exported symbol (function or global variable) inside an already-loaded C<Affix::Lib> handle. Returns an
unmanaged C<Affix::Pointer> (Pin) of type C<Pointer[Void]> pointing to the memory address of the symbol.

    my $lib = load_library('m');



( run in 0.808 second using v1.01-cache-2.11-cpan-788537b7465 )