MODULE = FFI::Platypus PACKAGE = FFI::Platypus::TypeParser
BOOT:
{
HV *bt = get_hv("FFI::Platypus::TypeParser::basic_type", GV_ADD);
hv_stores(bt, "void", newSViv(FFI_PL_TYPE_VOID));
hv_stores(bt, "sint8", newSViv(FFI_PL_TYPE_SINT8));
hv_stores(bt, "sint16", newSViv(FFI_PL_TYPE_SINT16));
hv_stores(bt, "sint32", newSViv(FFI_PL_TYPE_SINT32));
hv_stores(bt, "sint64", newSViv(FFI_PL_TYPE_SINT64));
hv_stores(bt, "uint8", newSViv(FFI_PL_TYPE_UINT8));
hv_stores(bt, "uint16", newSViv(FFI_PL_TYPE_UINT16));
hv_stores(bt, "uint32", newSViv(FFI_PL_TYPE_UINT32));
hv_stores(bt, "uint64", newSViv(FFI_PL_TYPE_UINT64));
hv_stores(bt, "float", newSViv(FFI_PL_TYPE_FLOAT));
hv_stores(bt, "double", newSViv(FFI_PL_TYPE_DOUBLE));
hv_stores(bt, "string", newSViv(FFI_PL_TYPE_STRING));
hv_stores(bt, "opaque", newSViv(FFI_PL_TYPE_OPAQUE));
#ifdef FFI_PL_PROBE_LONGDOUBLE
hv_stores(bt, "longdouble", newSViv(FFI_PL_TYPE_LONG_DOUBLE));
#endif
#ifdef FFI_PL_PROBE_COMPLEX
hv_stores(bt, "complex_float", newSViv(FFI_PL_TYPE_COMPLEX_FLOAT));
hv_stores(bt, "complex_double", newSViv(FFI_PL_TYPE_COMPLEX_DOUBLE));
#endif
}
ffi_pl_type *
create_type_basic(self, type_code)
SV *self
int type_code
PREINIT:
ffi_pl_type *type;
CODE:
(void)self;
type = ffi_pl_type_new(0);
type->type_code |= type_code;
RETVAL = type;
OUTPUT:
RETVAL
ffi_pl_type *
create_type_record(self, is_by_value, size, record_class=NULL, meta=NULL)
SV *self
int is_by_value
size_t size
ffi_pl_string record_class
void *meta
PREINIT:
ffi_pl_type *type;
CODE:
(void)self;
type = ffi_pl_type_new(sizeof(ffi_pl_type_extra_record));
type->type_code |= is_by_value ? FFI_PL_TYPE_RECORD_VALUE : FFI_PL_TYPE_RECORD;
type->extra[0].record.size = size;
if(record_class != NULL)
{
size = strlen(record_class)+1;
type->extra[0].record.class = malloc(size);
memcpy(type->extra[0].record.class, record_class, size);
}
else
{
type->extra[0].record.class = NULL;
}
type->extra[0].record.meta = meta;
RETVAL = type;
OUTPUT:
RETVAL
ffi_pl_type*
create_type_object(self, type_code, class)
SV *self
int type_code
ffi_pl_string class
PREINIT:
ffi_pl_type *type;
size_t size;
CODE:
(void)self;
type = ffi_pl_type_new(sizeof(ffi_pl_type_extra_object));
size = strlen(class)+1;
type->extra[0].object.class = malloc(size);
memcpy(type->extra[0].object.class, class, size);
type->type_code |= type_code;
type->type_code |= FFI_PL_SHAPE_OBJECT;
RETVAL = type;
OUTPUT:
RETVAL
ffi_pl_type *
create_type_string(self, rw)
SV *self
int rw
PREINIT:
ffi_pl_type *type;
CODE:
(void)self;
type = ffi_pl_type_new(0);
type->type_code = FFI_PL_TYPE_STRING;
if(rw)
type->sub_type = FFI_PL_TYPE_STRING_RW;
else
type->sub_type = FFI_PL_TYPE_STRING_RO;
RETVAL = type;
OUTPUT:
RETVAL
ffi_pl_type *
create_type_array(self, type_code, size)
SV *self
int type_code
size_t size
PREINIT:
ffi_pl_type *type;
CODE:
(void)self;
type = ffi_pl_type_new(sizeof(ffi_pl_type_extra_array));
type->type_code |= FFI_PL_SHAPE_ARRAY | type_code;
type->extra[0].array.element_count = size;
RETVAL = type;
OUTPUT:
RETVAL
ffi_pl_type*
create_type_pointer(self, type_code)
SV *self
int type_code
PREINIT:
ffi_pl_type *type;
CODE:
(void)self;
type = ffi_pl_type_new(0);
type->type_code |= FFI_PL_SHAPE_POINTER | type_code;
RETVAL = type;
OUTPUT:
RETVAL
ffi_pl_type *
_create_type_custom(self, basis, perl_to_native, native_to_perl, perl_to_native_post, argument_count)
SV *self
ffi_pl_type* basis
SV *perl_to_native
SV *native_to_perl
SV *perl_to_native_post
int argument_count
PREINIT:
ffi_pl_type *type;
int type_code;
ffi_pl_type_extra_custom_perl *custom;
ffi_pl_type_extra_record *record;
size_t size;
CODE:
(void)self;
type = ffi_pl_type_new(sizeof(ffi_pl_type_extra_custom_perl));
type->type_code = FFI_PL_SHAPE_CUSTOM_PERL | basis->type_code;
type->extra[0].record.class = NULL;
if( (basis->type_code & FFI_PL_BASE_MASK) == (FFI_PL_TYPE_RECORD & FFI_PL_BASE_MASK)
|| (basis->type_code & FFI_PL_BASE_MASK) == (FFI_PL_TYPE_RECORD_VALUE & FFI_PL_BASE_MASK))
{
type->extra[0].record.size = basis->extra[0].record.size;
type->extra[0].record.meta = basis->extra[0].record.meta;
if(basis->extra[0].record.class)
{
size = strlen(basis->extra[0].record.class) + 1;
type->extra[0].record.class = malloc(size);
memcpy(type->extra[0].record.class, basis->extra[0].record.class, size);
}
}
custom = &type->extra[0].custom_perl;
custom->perl_to_native = SvOK(perl_to_native) ? SvREFCNT_inc_simple_NN(perl_to_native) : NULL;
custom->perl_to_native_post = SvOK(perl_to_native_post) ? SvREFCNT_inc_simple_NN(perl_to_native_post) : NULL;
custom->native_to_perl = SvOK(native_to_perl) ? SvREFCNT_inc_simple_NN(native_to_perl) : NULL;
custom->argument_count = argument_count-1;
RETVAL = type;
OUTPUT:
RETVAL
ffi_pl_type *
create_type_closure(self, abi, return_type, ...)
SV *self
int abi
ffi_pl_type *return_type
PREINIT:
ffi_pl_type *type;
int i;
SV *arg;
ffi_type *ffi_return_type;
ffi_type **ffi_argument_types;
ffi_status ffi_status;
CODE:
(void)self;
switch(return_type->type_code)
{
case FFI_PL_TYPE_VOID:
ffi_return_type = &ffi_type_void;
break;
case FFI_PL_TYPE_SINT8:
ffi_return_type = &ffi_type_sint8;
break;
case FFI_PL_TYPE_SINT16:
ffi_return_type = &ffi_type_sint16;
break;
case FFI_PL_TYPE_SINT32:
ffi_return_type = &ffi_type_sint32;
break;
case FFI_PL_TYPE_SINT64:
ffi_return_type = &ffi_type_sint64;
break;
case FFI_PL_TYPE_UINT8:
ffi_return_type = &ffi_type_uint8;
break;
case FFI_PL_TYPE_UINT16:
ffi_return_type = &ffi_type_uint16;
break;
case FFI_PL_TYPE_UINT32:
ffi_return_type = &ffi_type_uint32;
break;
case FFI_PL_TYPE_UINT64:
ffi_return_type = &ffi_type_uint64;
break;
case FFI_PL_TYPE_FLOAT:
ffi_return_type = &ffi_type_float;
break;
case FFI_PL_TYPE_DOUBLE:
ffi_return_type = &ffi_type_double;
break;
case FFI_PL_TYPE_OPAQUE:
ffi_return_type = &ffi_type_pointer;
break;
case FFI_PL_TYPE_RECORD_VALUE:
if(return_type->extra[0].record.meta == NULL)
croak("Only native types are supported as closure return types (%d)", return_type->type_code);
if(!return_type->extra[0].record.meta->can_return_from_closure)
croak("Record return type contains types that cannot be returned from a closure");
ffi_return_type = &return_type->extra[0].record.meta->ffi_type;
break;
default:
croak("Only native types are supported as closure return types (%d)", return_type->type_code);
break;
}
Newx(ffi_argument_types, items-3, ffi_type*);
type = ffi_pl_type_new(sizeof(ffi_pl_type_extra_closure) + sizeof(ffi_pl_type)*(items-3));
type->type_code = FFI_PL_TYPE_CLOSURE;
type->extra[0].closure.return_type = return_type;
type->extra[0].closure.flags = 0;
for(i=0; i<(items-3); i++)
{
arg = ST(3+i);
type->extra[0].closure.argument_types[i] = INT2PTR(ffi_pl_type*, SvIV((SV*)SvRV(arg)));
switch(type->extra[0].closure.argument_types[i]->type_code)
{
case FFI_PL_TYPE_VOID:
ffi_argument_types[i] = &ffi_type_void;
break;
case FFI_PL_TYPE_SINT8:
ffi_argument_types[i] = &ffi_type_sint8;
break;
case FFI_PL_TYPE_SINT16:
ffi_argument_types[i] = &ffi_type_sint16;
break;
case FFI_PL_TYPE_SINT32:
ffi_argument_types[i] = &ffi_type_sint32;
break;
case FFI_PL_TYPE_SINT64:
ffi_argument_types[i] = &ffi_type_sint64;
break;
case FFI_PL_TYPE_UINT8:
ffi_argument_types[i] = &ffi_type_uint8;
break;
case FFI_PL_TYPE_UINT16:
ffi_argument_types[i] = &ffi_type_uint16;
break;
case FFI_PL_TYPE_UINT32:
ffi_argument_types[i] = &ffi_type_uint32;
break;
case FFI_PL_TYPE_UINT64:
ffi_argument_types[i] = &ffi_type_uint64;
break;
case FFI_PL_TYPE_FLOAT:
ffi_argument_types[i] = &ffi_type_float;
break;
case FFI_PL_TYPE_DOUBLE:
ffi_argument_types[i] = &ffi_type_double;
break;
case FFI_PL_TYPE_OPAQUE:
case FFI_PL_TYPE_STRING:
case FFI_PL_TYPE_RECORD:
ffi_argument_types[i] = &ffi_type_pointer;
break;
case FFI_PL_TYPE_RECORD_VALUE:
if(type->extra[0].closure.argument_types[i]->extra[0].record.meta == NULL)
{
Safefree(ffi_argument_types);
croak("Only native types and strings are supported as closure argument types (%d)", type->extra[0].closure.argument_types[i]->type_code);
}
ffi_argument_types[i] = &type->extra[0].closure.argument_types[i]->extra[0].record.meta->ffi_type;
break;
default:
Safefree(ffi_argument_types);
croak("Only native types and strings are supported as closure argument types (%d)", type->extra[0].closure.argument_types[i]->type_code);
break;
}
}
ffi_status = ffi_prep_cif(
&type->extra[0].closure.ffi_cif,
abi == -1 ? FFI_DEFAULT_ABI : abi,
items-3,
ffi_return_type,
ffi_argument_types
);
if(ffi_status != FFI_OK)
{
Safefree(type);
Safefree(ffi_argument_types);
if(ffi_status == FFI_BAD_TYPEDEF)
croak("bad typedef");
else if(ffi_status == FFI_BAD_ABI)
croak("bad abi");
else
croak("unknown error with ffi_prep_cif");
}
if( items-3 == 0 )
{
type->extra[0].closure.flags |= G_NOARGS;
}
if(type->extra[0].closure.return_type->type_code == FFI_PL_TYPE_VOID)
{
type->extra[0].closure.flags |= G_DISCARD | G_VOID;
}
else
{
type->extra[0].closure.flags |= G_SCALAR;
}
RETVAL = type;
OUTPUT:
RETVAL