Add support for 0-element arrays in FFI.

Allows for flexible array member construct mapping.
This commit is contained in:
Calvin Rose 2022-06-19 16:29:55 -05:00
parent 0a15a5ee56
commit eecc388ebd
1 changed files with 13 additions and 13 deletions

View File

@ -99,7 +99,7 @@ static const JanetFFIPrimInfo janet_ffi_type_info[] = {
struct JanetFFIType { struct JanetFFIType {
JanetFFIStruct *st; JanetFFIStruct *st;
JanetFFIPrimType prim; JanetFFIPrimType prim;
size_t array_count; ssize_t array_count;
}; };
typedef struct { typedef struct {
@ -223,12 +223,12 @@ static JanetFFIType prim_type(JanetFFIPrimType pt) {
JanetFFIType t; JanetFFIType t;
t.prim = pt; t.prim = pt;
t.st = NULL; t.st = NULL;
t.array_count = 0; t.array_count = -1;
return t; return t;
} }
static size_t type_size(JanetFFIType t) { static size_t type_size(JanetFFIType t) {
size_t count = t.array_count ? t.array_count : 1; size_t count = t.array_count < 0 ? 1 : (size_t) t.array_count;
if (t.prim == JANET_FFI_TYPE_STRUCT) { if (t.prim == JANET_FFI_TYPE_STRUCT) {
return t.st->size * count; return t.st->size * count;
} else { } else {
@ -294,6 +294,7 @@ static JanetFFIPrimType decode_ffi_prim(const uint8_t *name) {
if (!janet_cstrcmp(name, "int")) return JANET_FFI_TYPE_INT32; if (!janet_cstrcmp(name, "int")) return JANET_FFI_TYPE_INT32;
if (!janet_cstrcmp(name, "long")) return JANET_FFI_TYPE_INT64; if (!janet_cstrcmp(name, "long")) return JANET_FFI_TYPE_INT64;
if (!janet_cstrcmp(name, "byte")) return JANET_FFI_TYPE_UINT8; if (!janet_cstrcmp(name, "byte")) return JANET_FFI_TYPE_UINT8;
if (!janet_cstrcmp(name, "uchar")) return JANET_FFI_TYPE_UINT8;
if (!janet_cstrcmp(name, "ushort")) return JANET_FFI_TYPE_UINT16; if (!janet_cstrcmp(name, "ushort")) return JANET_FFI_TYPE_UINT16;
if (!janet_cstrcmp(name, "uint")) return JANET_FFI_TYPE_UINT32; if (!janet_cstrcmp(name, "uint")) return JANET_FFI_TYPE_UINT32;
if (!janet_cstrcmp(name, "ulong")) return JANET_FFI_TYPE_UINT64; if (!janet_cstrcmp(name, "ulong")) return JANET_FFI_TYPE_UINT64;
@ -374,7 +375,7 @@ static JanetFFIType decode_ffi_type(Janet x) {
return prim_type(decode_ffi_prim(janet_unwrap_keyword(x))); return prim_type(decode_ffi_prim(janet_unwrap_keyword(x)));
} }
JanetFFIType ret; JanetFFIType ret;
ret.array_count = 0; ret.array_count = -1;
ret.prim = JANET_FFI_TYPE_STRUCT; ret.prim = JANET_FFI_TYPE_STRUCT;
if (janet_checkabstract(x, &janet_struct_type)) { if (janet_checkabstract(x, &janet_struct_type)) {
ret.st = janet_unwrap_abstract(x); ret.st = janet_unwrap_abstract(x);
@ -384,10 +385,9 @@ static JanetFFIType decode_ffi_type(Janet x) {
const Janet *els; const Janet *els;
if (janet_indexed_view(x, &els, &len)) { if (janet_indexed_view(x, &els, &len)) {
if (janet_checktype(x, JANET_ARRAY)) { if (janet_checktype(x, JANET_ARRAY)) {
if (len != 2) janet_panicf("array type must be of form @[type count], got %v", x); if (len != 2 && len != 1) janet_panicf("array type must be of form @[type count], got %v", x);
int32_t array_count = janet_getnat(els, 1);
if (array_count == 0) janet_panic("vla not supported");
ret = decode_ffi_type(els[0]); ret = decode_ffi_type(els[0]);
int32_t array_count = len == 1 ? 0 : janet_getnat(els, 1);
ret.array_count = array_count; ret.array_count = array_count;
} else { } else {
ret.st = build_struct_type(len, els); ret.st = build_struct_type(len, els);
@ -447,12 +447,12 @@ static void *janet_ffi_getpointer(const Janet *argv, int32_t n) {
* The alignment and space available is assumed to already be sufficient */ * The alignment and space available is assumed to already be sufficient */
static void janet_ffi_write_one(void *to, const Janet *argv, int32_t n, JanetFFIType type, int recur) { static void janet_ffi_write_one(void *to, const Janet *argv, int32_t n, JanetFFIType type, int recur) {
if (recur == 0) janet_panic("recursion too deep"); if (recur == 0) janet_panic("recursion too deep");
if (type.array_count) { if (type.array_count >= 0) {
JanetFFIType el_type = type; JanetFFIType el_type = type;
el_type.array_count = 0; el_type.array_count = -1;
size_t el_size = type_size(el_type); size_t el_size = type_size(el_type);
JanetView els = janet_getindexed(argv, n); JanetView els = janet_getindexed(argv, n);
if ((size_t) els.len != type.array_count) { if (els.len != type.array_count) {
janet_panicf("bad array length, expected %d, got %d", type.array_count, els.len); janet_panicf("bad array length, expected %d, got %d", type.array_count, els.len);
} }
char *cursor = to; char *cursor = to;
@ -528,12 +528,12 @@ static void janet_ffi_write_one(void *to, const Janet *argv, int32_t n, JanetFFI
* size of the data is correct. */ * size of the data is correct. */
static Janet janet_ffi_read_one(const uint8_t *from, JanetFFIType type, int recur) { static Janet janet_ffi_read_one(const uint8_t *from, JanetFFIType type, int recur) {
if (recur == 0) janet_panic("recursion too deep"); if (recur == 0) janet_panic("recursion too deep");
if (type.array_count) { if (type.array_count >= 0) {
JanetFFIType el_type = type; JanetFFIType el_type = type;
el_type.array_count = 0; el_type.array_count = -1;
size_t el_size = type_size(el_type); size_t el_size = type_size(el_type);
JanetArray *array = janet_array(type.array_count); JanetArray *array = janet_array(type.array_count);
for (size_t i = 0; i < type.array_count; i++) { for (ssize_t i = 0; i < type.array_count; i++) {
janet_array_push(array, janet_ffi_read_one(from, el_type, recur - 1)); janet_array_push(array, janet_ffi_read_one(from, el_type, recur - 1));
from += el_size; from += el_size;
} }