// Generated by nim-ffi Kotlin/JNI codegen. Do not edit by hand. // // JNI bridge exposing the library's native (zero-serialization) C ABI to Kotlin. // The library calls back on its own FFI thread; each bridge function blocks on a // condvar until the callback fires, then returns a plain Java value — so the // Kotlin side sees a simple synchronous API. A struct return is read out of the // typed C-POD inside the callback (valid only there). #include "my_timer.h" #include #include #include #include typedef struct { int ret, done; char text[1024]; // string return / error text char fields[2][256]; // string fields of a struct return pthread_mutex_t mu; pthread_cond_t cv; } Resp; static void resp_init(Resp *r) { memset(r, 0, sizeof(*r)); pthread_mutex_init(&r->mu, NULL); pthread_cond_init(&r->cv, NULL); } static void resp_destroy(Resp *r) { pthread_mutex_destroy(&r->mu); pthread_cond_destroy(&r->cv); } static void resp_wait(Resp *r) { pthread_mutex_lock(&r->mu); while (!r->done) pthread_cond_wait(&r->cv, &r->mu); pthread_mutex_unlock(&r->mu); } static void copy_raw(char *dst, size_t cap, const char *msg, size_t len) { size_t n = len < cap - 1 ? len : cap - 1; if (msg && n) memcpy(dst, msg, n); dst[n] = '\0'; } static void ack_cb(int ret, const char *msg, size_t len, void *ud) { Resp *r = ud; pthread_mutex_lock(&r->mu); r->ret = ret; if (ret == RET_ERR) copy_raw(r->text, sizeof(r->text), msg, len); r->done = 1; pthread_cond_signal(&r->cv); pthread_mutex_unlock(&r->mu); } static void string_cb(int ret, const char *msg, size_t len, void *ud) { Resp *r = ud; pthread_mutex_lock(&r->mu); r->ret = ret; copy_raw(r->text, sizeof(r->text), msg, len); r->done = 1; pthread_cond_signal(&r->cv); pthread_mutex_unlock(&r->mu); } static void echo_cb(int ret, const char *msg, size_t len, void *ud) { Resp *r = ud; pthread_mutex_lock(&r->mu); r->ret = ret; if (ret == RET_OK) { const EchoResponse *e = (const EchoResponse *)msg; strncpy(r->fields[0], e->echoed, sizeof(r->fields[0]) - 1); strncpy(r->fields[1], e->timerName, sizeof(r->fields[1]) - 1); } else { copy_raw(r->text, sizeof(r->text), msg, len); } r->done = 1; pthread_cond_signal(&r->cv); pthread_mutex_unlock(&r->mu); } JNIEXPORT jlong JNICALL Java_org_logos_mytimer_MyTimerNode_nativeCreate(JNIEnv *env, jobject thiz, jstring j_name) { const char *name = (*env)->GetStringUTFChars(env, j_name, NULL); TimerConfig config = {.name = name}; Resp r; resp_init(&r); void *ctx = my_timer_create(config, ack_cb, &r); resp_wait(&r); (*env)->ReleaseStringUTFChars(env, j_name, name); resp_destroy(&r); (void)thiz; return (jlong)(intptr_t)ctx; } JNIEXPORT jobjectArray JNICALL Java_org_logos_mytimer_MyTimerNode_nativeEcho(JNIEnv *env, jobject thiz, jlong ctx, jstring j_message, jlong delayMs) { const char *message = (*env)->GetStringUTFChars(env, j_message, NULL); EchoRequest req = {.message = message, .delayMs = (int64_t)delayMs}; Resp r; resp_init(&r); if (my_timer_echo((void *)(intptr_t)ctx, echo_cb, &r, req) == RET_OK) resp_wait(&r); (*env)->ReleaseStringUTFChars(env, j_message, message); jclass strClass = (*env)->FindClass(env, "java/lang/String"); jobjectArray arr = (*env)->NewObjectArray(env, 2, strClass, NULL); (*env)->SetObjectArrayElement(env, arr, 0, (*env)->NewStringUTF(env, r.fields[0])); (*env)->SetObjectArrayElement(env, arr, 1, (*env)->NewStringUTF(env, r.fields[1])); resp_destroy(&r); (void)thiz; return arr; } JNIEXPORT jstring JNICALL Java_org_logos_mytimer_MyTimerNode_nativeVersion(JNIEnv *env, jobject thiz, jlong ctx) { Resp r; resp_init(&r); if (my_timer_version((void *)(intptr_t)ctx, string_cb, &r) == RET_OK) resp_wait(&r); jstring out = (*env)->NewStringUTF(env, r.text); resp_destroy(&r); (void)thiz; return out; } JNIEXPORT void JNICALL Java_org_logos_mytimer_MyTimerNode_nativeDestroy(JNIEnv *env, jobject thiz, jlong ctx) { my_timer_destroy((void *)(intptr_t)ctx); (void)env; (void)thiz; }