Affix
view release on metacpan or search on metacpan
lib/Affix.pod view on Meta::CPAN
Specify bit widths using the pipe (C<|>) operator within Structs/Unions. Affix handles all masking and shifting.
# C: typedef struct { uint32_t a : 1; uint32_t b : 3; } Config;
typedef Config => Struct[ a => UInt32 | 1, b => UInt32 | 3 ];
=head2 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.
C<Live[ $type ]> Returns a live, zero-copy view of the memory as defined by C<$type>.
If C<$type> is a C<Struct> or C<Union>, it returns an C<Affix::Live> tied hash. Modifying keys in this hash updates C
memory immediately.
If C<$type> is an C<Array>, it returns an C<Affix::Pointer> object. Modifying elements (e.g. C<< $arr->[0] = 5 >>)
writes directly to memory.
# Example: Live view of a struct
my $live = cast( $ptr, Live[ Struct[ x => Int, y => Int ] ] );
$live->{x} = 42; # Updates C memory
=head3 Unified Access
C<Affix::Pointer> objects for aggregates allow direct field access (C<< $p->{field} >>) without explicit casting.
affix $lib, 'get_ptr', [] => Pointer[Point];
my $p = get_ptr();
say $p->{x}; # Unified access! Reads directly from C memory.
$p->{y} = 50; # Writes directly to C memory.
=head2 Callbacks & Functions
=over
=item * B<C<< Callback[ [$params] => $ret ] >>>: Defines the signature of a C function pointer. Allows you to pass Perl subroutines into C functions.
# C: void set_handler( void (*cb)(int) );
affix $lib, 'set_handler', [ Callback[ [Int] => Void ] ] => Void;
=item * B<C<ThisCall( $cb_or_sig )>>: Helper for C++-style C<__thiscall> callbacks. Prepends a C<Pointer[Void]> (the C<this> pointer) to the signature.
=back
=head2 Variadic Functions (VarArgs)
Affix supports C functions that take a variable number of arguments (e.g., C<printf>, C<ioctl>). When defining a
signature, use the C<VarArgs> token at the end of the argument list.
=head3 Basic Usage
# C: int printf(const char* format, ...);
affix libc(), ['printf' => 'my_printf'], [ String, VarArgs ] => Int;
# Basic types are marshalled automatically based on Perl's internal state
my_printf("Integer: %d, String: %s\n", 42, "Hello");
=head3 Explicit Type Control with C<coerce()>
In variadic functions, C relies on the caller to pass data in the exact format the function expects. While Affix
attempts to guess the correct C type for Perl scalars, these guesses might not always match the library's expectations
like passing a 64-bit integer where a 32-bit one is expected, or a float instead of a double.
Use C<coerce( $type, $value )> to explicitly tell Affix how to marshal a variadic argument.
# Suppose we have a variadic log function that expects specific bit-widths
# C: void custom_log(int level, ...);
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 C<Float> to a variadic function will
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 );
( run in 0.755 second using v1.01-cache-2.11-cpan-5735350b133 )