ruapu/erlang/c_src/ruapu.c
2024-03-04 21:45:40 +08:00

136 lines
3.5 KiB
C

#include <erl_nif.h>
#include <stdbool.h>
#include <stdint.h>
#define RUAPU_IMPLEMENTATION
#include "ruapu.h"
ERL_NIF_TERM atom(ErlNifEnv *env, const char *msg) {
ERL_NIF_TERM a;
if (enif_make_existing_atom(env, msg, &a, ERL_NIF_LATIN1)) {
return a;
} else {
return enif_make_atom(env, msg);
}
}
ERL_NIF_TERM error(ErlNifEnv *env, const char *msg) {
ERL_NIF_TERM error_atom = atom(env, "error");
ERL_NIF_TERM msg_term = enif_make_string(env, msg, ERL_NIF_LATIN1);
return enif_make_tuple2(env, error_atom, msg_term);
}
ERL_NIF_TERM ok(ErlNifEnv *env) { return atom(env, "ok"); }
ERL_NIF_TERM ok_tuple(ErlNifEnv *env, ERL_NIF_TERM term) {
return enif_make_tuple2(env, atom(env, "ok"), term);
}
const char *get_string(ErlNifEnv *env, ERL_NIF_TERM term) {
char *result = NULL;
unsigned len;
int ret = enif_get_list_length(env, term, &len);
if (ret) {
result = (char *)enif_alloc(sizeof(char) * (len + 1));
ret = enif_get_string(env, term, result, len + 1, ERL_NIF_LATIN1);
if (ret > 0) {
return result;
} else {
enif_free((void *)result);
return NULL;
}
}
ErlNifBinary bin;
ret = enif_inspect_binary(env, term, &bin);
if (ret) {
result = (char *)enif_alloc(sizeof(char) * (bin.size + 1));
if (result == NULL) {
return NULL;
}
memcpy(result, bin.data, bin.size);
result[bin.size] = '\0';
return result;
}
ret = enif_get_atom_length(env, term, &len, ERL_NIF_LATIN1);
if (ret) {
result = (char *)enif_alloc(sizeof(char) * (len + 1));
ret = enif_get_atom(env, term, result, len + 1, ERL_NIF_LATIN1);
if (ret) {
return result;
} else {
enif_free((void *)result);
return NULL;
}
}
return NULL;
}
static ERL_NIF_TERM nif_supports(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
const char *isa = get_string(env, argv[0]);
if (isa == NULL) {
return enif_make_badarg(env);
}
int supports = ruapu_supports(isa);
enif_free((void *)isa);
if (supports) {
return atom(env, "true");
} else {
return atom(env, "false");
}
}
static ERL_NIF_TERM nif_rua(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
const char *const *supported = ruapu_rua();
const char *const *supported_start = supported;
uint32_t count = 0;
while (*supported_start) {
supported_start++;
count++;
}
if (count == 0) {
ERL_NIF_TERM list = enif_make_list(env, 0, NULL);
return ok_tuple(env, list);
}
ERL_NIF_TERM *terms =
(ERL_NIF_TERM *)enif_alloc(sizeof(ERL_NIF_TERM) * count);
if (terms == NULL) {
return error(env, "enif_alloc failed");
}
supported_start = supported;
for (uint32_t i = 0; i < count; i++) {
terms[i] = enif_make_string(env, *supported_start, ERL_NIF_LATIN1);
supported_start++;
}
ERL_NIF_TERM list = enif_make_list_from_array(env, terms, count);
enif_free(terms);
return ok_tuple(env, list);
}
static int on_load(ErlNifEnv *env, void **_sth1, ERL_NIF_TERM _sth2) {
ruapu_init();
return 0;
}
static int on_reload(ErlNifEnv *_sth0, void **_sth1, ERL_NIF_TERM _sth2) {
return 0;
}
static int on_upgrade(ErlNifEnv *_sth0, void **_sth1, void **_sth2,
ERL_NIF_TERM _sth3) {
return 0;
}
static ErlNifFunc nif_functions[] = {
{"supports", 1, nif_supports, ERL_NIF_DIRTY_JOB_CPU_BOUND},
{"rua", 0, nif_rua, ERL_NIF_DIRTY_JOB_CPU_BOUND},
};
ERL_NIF_INIT(ruapu_nif, nif_functions, on_load, on_reload, on_upgrade, NULL);