Affix
view release on metacpan or search on metacpan
t/005_varargs.t view on Meta::CPAN
use v5.40;
use lib '../lib', 'lib';
use blib;
use Test2::Tools::Affix qw[:all];
use Affix qw[:all];
#
$|++;
#
my $c_code = <<'END_C';
#include "std.h"
//ext: .c
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
typedef struct {
int x, y;
} Point;
/*
* Sums values based on format string.
* i: int
* d: double
* P: Point {int, int}
*/
DLLEXPORT int var_sum(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
int total = 0;
while (*fmt) {
switch (*fmt++) {
case 'i': total += va_arg(ap, int); break;
case 'd': total += (int)va_arg(ap, double); break;
case 's': {
char* s = va_arg(ap, char*);
total += s ? strlen(s) : 0;
break;
}
case 'P': {
Point p = va_arg(ap, Point);
total += p.x + p.y;
break;
}
}
}
va_end(ap);
return total;
}
END_C
my $lib = compile_ok( $c_code, { name => 'variadic_dynamic_lib' } );
# Bind with "Empty" Variadic Signature
# We define the fixed arguments (*char) and end with a semicolon.
# We do NOT specify any optional types here. Affix must generate them at runtime.
# Signature: (*char;)->int
isa_ok my $fn = wrap( $lib, 'var_sum', [ Pointer [Char], VarArgs ] => Int ), ['Affix'];
subtest 'Runtime Type Inference' => sub {
# 3 Integers
# Affix should generate JIT for: (*char; sint64, sint64, sint64)->int
is $fn->( "iii", 10, 20, 30 ), 60, 'Inferred 3 integers';
# Floats (promoted to double)
# 1.5 -> 1, 2.5 -> 2. Sum = 3.
is $fn->( "dd", 1.5, 2.5 ), 3, 'Doubles passed correctly';
# Mixed Types
# (*char; sint64, double)->int
# Note: 2.5 cast to int is 2
is $fn->( "id", 100, 2.5 ), 102, 'Inferred mixed int/double';
# Strings (*char)
# len("Hello") = 5
is $fn->( "s", "Hello" ), 5, 'Strings passed correctly';
# Edge case where we don't pass any varargs. Like calling `printf( "Just this string, please." );`
# (*char;)->int
is $fn->(""), 0, 'Called with no variadic arguments';
};
subtest 'Runtime Coercion (Structs)' => sub {
typedef Point__ => Struct [ x => Int, y => Int ];
my $p1 = { x => 1, y => 2 }; # Sum = 3
my $p2 = { x => 3, y => 4 }; # Sum = 7
# Coerced Struct
# Affix should generate JIT for: (*char; {x:int,y:int}, {x:int,y:int})->int
is $fn->( "PP", coerce( Point__(), $p1 ), coerce( Point__(), $p2 ) ), 10, 'Dynamically generated signature for coerced structs';
};
( run in 0.771 second using v1.01-cache-2.11-cpan-fe3c2283af0 )