1
0
mirror of https://github.com/janet-lang/janet synced 2025-11-17 15:57:12 +00:00

Get a GTK example working. Good proof of concept.

This commit is contained in:
Calvin Rose
2022-06-11 14:47:35 -05:00
parent 0bc96304a9
commit 0cc53a8964
2 changed files with 114 additions and 6 deletions

View File

@@ -328,14 +328,22 @@ JANET_CORE_FN(cfun_ffi_struct,
static void *janet_ffi_getpointer(const Janet *argv, int32_t n) {
switch (janet_type(argv[n])) {
default:
janet_panicf("bad slot #%d, expected pointer convertable type, got %v", argv[n]);
janet_panicf("bad slot #%d, expected ffi pointer convertable type, got %v", argv[n]);
case JANET_POINTER:
case JANET_STRING:
case JANET_KEYWORD:
case JANET_SYMBOL:
case JANET_ABSTRACT:
return janet_unwrap_pointer(argv[n]);
case JANET_BUFFER:
return janet_unwrap_buffer(argv[n])->data;
case JANET_FUNCTION:
/* Users may pass in a function. Any function passed is almost certainly
* being used as a callback, so we add it to the root set. */
janet_gcroot(argv[n]);
return janet_unwrap_pointer(argv[n]);
case JANET_NIL:
return NULL;
}
}
@@ -609,6 +617,25 @@ JANET_CORE_FN(cfun_ffi_signature,
return janet_wrap_abstract(abst);
}
/* A common callback function signature. To avoid runtime code generation, which is prohibited
* on many platforms, often buggy (see libffi), and generally complicated, instead provide
* a single (or small set of commonly used function signatures). All callbacks should
* eventually call this. */
void janet_ffi_trampoline(void *ctx, void *userdata) {
if (NULL == userdata) {
/* Userdata not set. */
janet_eprintf("no userdata found for janet callback");
return;
}
Janet context = janet_wrap_pointer(ctx);
JanetFunction *fun = userdata;
janet_call(fun, 1, &context);
}
static void janet_ffi_sysv64_standard_callback(void *ctx, void *userdata) {
janet_ffi_trampoline(ctx, userdata);
}
static Janet janet_ffi_sysv64(JanetFFISignature *signature, void *function_pointer, const Janet *argv) {
uint64_t ret[2];
uint64_t regs[6];
@@ -741,14 +768,37 @@ JANET_CORE_FN(cfun_ffi_buffer_write,
JANET_CORE_FN(cfun_ffi_buffer_read,
"(native-read ffi-type bytes &opt offset)",
"Parse a native struct out of a buffer and convert it to normal Janet data structures. "
"This function is the inverse of `native-write`.") {
"This function is the inverse of `native-write`. `bytes` can also be a raw pointer, although "
"this is unsafe.") {
janet_arity(argc, 2, 3);
JanetFFIType type = decode_ffi_type(argv[0]);
size_t el_size = type_size(type);
JanetByteView bytes = janet_getbytes(argv, 1);
size_t offset = (size_t) janet_optnat(argv, argc, 2, 0);
if ((size_t) bytes.len < offset + el_size) janet_panic("read out of range");
return janet_ffi_read_one(bytes.bytes, type, JANET_FFI_MAX_RECUR);
if (janet_checktype(argv[1], JANET_POINTER)) {
uint8_t *ptr = janet_unwrap_pointer(argv[1]);
return janet_ffi_read_one(ptr + offset, type, JANET_FFI_MAX_RECUR);
} else {
size_t el_size = type_size(type);
JanetByteView bytes = janet_getbytes(argv, 1);
if ((size_t) bytes.len < offset + el_size) janet_panic("read out of range");
return janet_ffi_read_one(bytes.bytes + offset, type, JANET_FFI_MAX_RECUR);
}
}
JANET_CORE_FN(cfun_ffi_get_callback_trampoline,
"(native-trampoline cc)",
"Get a native function pointer that can be used as a callback and passed to C libraries. "
"This callback trampoline has the signature `void trampoline(void *ctx, void *userdata)` in "
"the given calling convention. This is the only function signature supported. "
"It is up to the programmer to ensure that the `userdata` argument contains a janet function "
"the will be called with one argument, `ctx` which is an opaque pointer. This pointer can "
"be further inspected with `native-read`.") {
janet_fixarity(argc, 1);
JanetFFICallingConvention cc = decode_ffi_cc(janet_getkeyword(argv, 0));
switch (cc) {
default:
case JANET_FFI_CC_SYSV_64:
return janet_wrap_pointer(janet_ffi_sysv64_standard_callback);
}
}
void janet_lib_ffi(JanetTable *env) {
@@ -758,6 +808,7 @@ void janet_lib_ffi(JanetTable *env) {
JANET_CORE_REG("native-struct", cfun_ffi_struct),
JANET_CORE_REG("native-write", cfun_ffi_buffer_write),
JANET_CORE_REG("native-read", cfun_ffi_buffer_read),
JANET_CORE_REG("native-trampoline", cfun_ffi_get_callback_trampoline),
JANET_REG_END
};
janet_core_cfuns_ext(env, NULL, ffi_cfuns);