chore: remove trailing whitespace from README.md line 42
This commit is contained in:
+216
@@ -0,0 +1,216 @@
|
||||
#include "loader.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
RavaNativeRegistry_t* rava_native_registry_create(void) {
|
||||
RavaNativeRegistry_t *registry = calloc(1, sizeof(RavaNativeRegistry_t));
|
||||
if (!registry) return NULL;
|
||||
registry->library_count = 0;
|
||||
registry->cache_count = 0;
|
||||
return registry;
|
||||
}
|
||||
|
||||
void rava_native_registry_destroy(RavaNativeRegistry_t *registry) {
|
||||
if (!registry) return;
|
||||
for (size_t i = 0; i < registry->library_count; i++) {
|
||||
rava_native_library_unload(registry, registry->libraries[i]);
|
||||
}
|
||||
free(registry);
|
||||
}
|
||||
|
||||
static uint32_t _hash_method_name(const char *class_name, const char *method_name) {
|
||||
uint32_t hash = 5381;
|
||||
for (const char *p = class_name; *p; p++) {
|
||||
hash = ((hash << 5) + hash) + (uint32_t)*p;
|
||||
}
|
||||
hash = ((hash << 5) + hash) + '.';
|
||||
for (const char *p = method_name; *p; p++) {
|
||||
hash = ((hash << 5) + hash) + (uint32_t)*p;
|
||||
}
|
||||
return hash % RAVA_MAX_NATIVE_METHODS;
|
||||
}
|
||||
|
||||
RavaNativeLibrary_t* rava_native_library_load(RavaNativeRegistry_t *registry, const char *path) {
|
||||
if (!registry || !path) return NULL;
|
||||
if (registry->library_count >= RAVA_MAX_NATIVE_LIBRARIES) return NULL;
|
||||
|
||||
void *handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
|
||||
if (!handle) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RavaNativeLibrary_t *lib = calloc(1, sizeof(RavaNativeLibrary_t));
|
||||
if (!lib) {
|
||||
dlclose(handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lib->path = strdup(path);
|
||||
lib->handle = handle;
|
||||
lib->method_count = 0;
|
||||
lib->method_capacity = 16;
|
||||
lib->methods = calloc(lib->method_capacity, sizeof(RavaNativeMethod_t));
|
||||
|
||||
const char *name_start = strrchr(path, '/');
|
||||
if (name_start) {
|
||||
name_start++;
|
||||
} else {
|
||||
name_start = path;
|
||||
}
|
||||
|
||||
if (strncmp(name_start, "lib", 3) == 0) {
|
||||
name_start += 3;
|
||||
}
|
||||
|
||||
size_t name_len = strlen(name_start);
|
||||
if (name_len > 3 && strcmp(name_start + name_len - 3, ".so") == 0) {
|
||||
lib->name = strndup(name_start, name_len - 3);
|
||||
} else {
|
||||
lib->name = strdup(name_start);
|
||||
}
|
||||
|
||||
RavaLibraryRegisterFn register_fn = (RavaLibraryRegisterFn)dlsym(handle, RAVA_LIBRARY_REGISTER_SYMBOL);
|
||||
if (register_fn) {
|
||||
register_fn(registry);
|
||||
}
|
||||
|
||||
registry->libraries[registry->library_count++] = lib;
|
||||
return lib;
|
||||
}
|
||||
|
||||
void rava_native_library_unload(RavaNativeRegistry_t *registry, RavaNativeLibrary_t *lib) {
|
||||
if (!registry || !lib) return;
|
||||
|
||||
for (size_t i = 0; i < lib->method_count; i++) {
|
||||
free(lib->methods[i].class_name);
|
||||
free(lib->methods[i].method_name);
|
||||
}
|
||||
free(lib->methods);
|
||||
|
||||
if (lib->handle) {
|
||||
dlclose(lib->handle);
|
||||
}
|
||||
|
||||
free(lib->name);
|
||||
free(lib->path);
|
||||
free(lib);
|
||||
}
|
||||
|
||||
bool rava_native_register_method(RavaNativeRegistry_t *registry,
|
||||
const char *class_name,
|
||||
const char *method_name,
|
||||
RavaNativeType_e return_type,
|
||||
RavaNativeType_e *param_types,
|
||||
size_t param_count,
|
||||
RavaNativeFunction_fn function,
|
||||
void *user_data) {
|
||||
if (!registry || !class_name || !method_name || !function) return false;
|
||||
if (param_count > RAVA_MAX_METHOD_PARAMS) return false;
|
||||
if (registry->cache_count >= RAVA_MAX_NATIVE_METHODS) return false;
|
||||
|
||||
RavaNativeMethod_t *method = calloc(1, sizeof(RavaNativeMethod_t));
|
||||
if (!method) return false;
|
||||
|
||||
method->class_name = strdup(class_name);
|
||||
method->method_name = strdup(method_name);
|
||||
method->return_type = return_type;
|
||||
method->param_count = param_count;
|
||||
method->function = function;
|
||||
method->user_data = user_data;
|
||||
|
||||
for (size_t i = 0; i < param_count; i++) {
|
||||
method->param_types[i] = param_types[i];
|
||||
}
|
||||
|
||||
uint32_t hash = _hash_method_name(class_name, method_name);
|
||||
|
||||
while (registry->method_cache[hash] != NULL) {
|
||||
hash = (hash + 1) % RAVA_MAX_NATIVE_METHODS;
|
||||
}
|
||||
|
||||
registry->method_cache[hash] = method;
|
||||
registry->cache_count++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RavaNativeMethod_t* rava_native_find_method(RavaNativeRegistry_t *registry,
|
||||
const char *class_name,
|
||||
const char *method_name) {
|
||||
if (!registry || !class_name || !method_name) return NULL;
|
||||
|
||||
uint32_t hash = _hash_method_name(class_name, method_name);
|
||||
uint32_t start = hash;
|
||||
|
||||
do {
|
||||
RavaNativeMethod_t *method = registry->method_cache[hash];
|
||||
if (!method) return NULL;
|
||||
|
||||
if (strcmp(method->class_name, class_name) == 0 &&
|
||||
strcmp(method->method_name, method_name) == 0) {
|
||||
return method;
|
||||
}
|
||||
|
||||
hash = (hash + 1) % RAVA_MAX_NATIVE_METHODS;
|
||||
} while (hash != start);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RavaNativeValue_t rava_native_invoke(RavaNativeMethod_t *method,
|
||||
RavaNativeValue_t *args,
|
||||
size_t arg_count) {
|
||||
if (!method || !method->function) {
|
||||
return rava_native_void();
|
||||
}
|
||||
return method->function(args, arg_count, method->user_data);
|
||||
}
|
||||
|
||||
RavaNativeValue_t rava_native_int(int32_t val) {
|
||||
RavaNativeValue_t native;
|
||||
native.type = RAVA_NATIVE_INT;
|
||||
native.data.int_val = val;
|
||||
return native;
|
||||
}
|
||||
|
||||
RavaNativeValue_t rava_native_long(int64_t val) {
|
||||
RavaNativeValue_t native;
|
||||
native.type = RAVA_NATIVE_LONG;
|
||||
native.data.long_val = val;
|
||||
return native;
|
||||
}
|
||||
|
||||
RavaNativeValue_t rava_native_double(double val) {
|
||||
RavaNativeValue_t native;
|
||||
native.type = RAVA_NATIVE_DOUBLE;
|
||||
native.data.double_val = val;
|
||||
return native;
|
||||
}
|
||||
|
||||
RavaNativeValue_t rava_native_boolean(bool val) {
|
||||
RavaNativeValue_t native;
|
||||
native.type = RAVA_NATIVE_BOOLEAN;
|
||||
native.data.bool_val = val;
|
||||
return native;
|
||||
}
|
||||
|
||||
RavaNativeValue_t rava_native_string(const char *val) {
|
||||
RavaNativeValue_t native;
|
||||
native.type = RAVA_NATIVE_STRING;
|
||||
native.data.string_val = val ? strdup(val) : NULL;
|
||||
return native;
|
||||
}
|
||||
|
||||
RavaNativeValue_t rava_native_void(void) {
|
||||
RavaNativeValue_t native;
|
||||
native.type = RAVA_NATIVE_VOID;
|
||||
return native;
|
||||
}
|
||||
|
||||
RavaNativeValue_t rava_native_null(void) {
|
||||
RavaNativeValue_t native;
|
||||
native.type = RAVA_NATIVE_OBJECT;
|
||||
native.data.object_val = NULL;
|
||||
return native;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
#ifndef RAVA_LOADER_H
|
||||
#define RAVA_LOADER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define RAVA_MAX_NATIVE_METHODS 256
|
||||
#define RAVA_MAX_NATIVE_LIBRARIES 32
|
||||
#define RAVA_MAX_METHOD_PARAMS 16
|
||||
|
||||
typedef enum {
|
||||
RAVA_NATIVE_VOID,
|
||||
RAVA_NATIVE_INT,
|
||||
RAVA_NATIVE_LONG,
|
||||
RAVA_NATIVE_DOUBLE,
|
||||
RAVA_NATIVE_BOOLEAN,
|
||||
RAVA_NATIVE_STRING,
|
||||
RAVA_NATIVE_OBJECT,
|
||||
RAVA_NATIVE_ARRAY
|
||||
} RavaNativeType_e;
|
||||
|
||||
typedef struct {
|
||||
RavaNativeType_e type;
|
||||
union {
|
||||
int32_t int_val;
|
||||
int64_t long_val;
|
||||
double double_val;
|
||||
bool bool_val;
|
||||
char *string_val;
|
||||
void *object_val;
|
||||
void *array_val;
|
||||
} data;
|
||||
} RavaNativeValue_t;
|
||||
|
||||
typedef RavaNativeValue_t (*RavaNativeFunction_fn)(RavaNativeValue_t *args, size_t arg_count, void *user_data);
|
||||
|
||||
typedef struct {
|
||||
char *class_name;
|
||||
char *method_name;
|
||||
RavaNativeType_e return_type;
|
||||
RavaNativeType_e param_types[RAVA_MAX_METHOD_PARAMS];
|
||||
size_t param_count;
|
||||
RavaNativeFunction_fn function;
|
||||
void *user_data;
|
||||
} RavaNativeMethod_t;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
char *path;
|
||||
void *handle;
|
||||
RavaNativeMethod_t *methods;
|
||||
size_t method_count;
|
||||
size_t method_capacity;
|
||||
} RavaNativeLibrary_t;
|
||||
|
||||
typedef struct {
|
||||
RavaNativeLibrary_t *libraries[RAVA_MAX_NATIVE_LIBRARIES];
|
||||
size_t library_count;
|
||||
RavaNativeMethod_t *method_cache[RAVA_MAX_NATIVE_METHODS];
|
||||
size_t cache_count;
|
||||
} RavaNativeRegistry_t;
|
||||
|
||||
RavaNativeRegistry_t* rava_native_registry_create(void);
|
||||
void rava_native_registry_destroy(RavaNativeRegistry_t *registry);
|
||||
|
||||
RavaNativeLibrary_t* rava_native_library_load(RavaNativeRegistry_t *registry, const char *path);
|
||||
void rava_native_library_unload(RavaNativeRegistry_t *registry, RavaNativeLibrary_t *lib);
|
||||
|
||||
bool rava_native_register_method(RavaNativeRegistry_t *registry,
|
||||
const char *class_name,
|
||||
const char *method_name,
|
||||
RavaNativeType_e return_type,
|
||||
RavaNativeType_e *param_types,
|
||||
size_t param_count,
|
||||
RavaNativeFunction_fn function,
|
||||
void *user_data);
|
||||
|
||||
RavaNativeMethod_t* rava_native_find_method(RavaNativeRegistry_t *registry,
|
||||
const char *class_name,
|
||||
const char *method_name);
|
||||
|
||||
RavaNativeValue_t rava_native_invoke(RavaNativeMethod_t *method,
|
||||
RavaNativeValue_t *args,
|
||||
size_t arg_count);
|
||||
|
||||
|
||||
RavaNativeValue_t rava_native_int(int32_t val);
|
||||
RavaNativeValue_t rava_native_long(int64_t val);
|
||||
RavaNativeValue_t rava_native_double(double val);
|
||||
RavaNativeValue_t rava_native_boolean(bool val);
|
||||
RavaNativeValue_t rava_native_string(const char *val);
|
||||
RavaNativeValue_t rava_native_void(void);
|
||||
RavaNativeValue_t rava_native_null(void);
|
||||
|
||||
typedef void (*RavaLibraryRegisterFn)(RavaNativeRegistry_t *registry);
|
||||
#define RAVA_LIBRARY_REGISTER_SYMBOL "rava_library_register"
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user