Packages
vix
0.12.0
0.40.0
0.39.0
0.38.0
0.37.0
0.36.0
0.35.0
0.34.0
0.33.1
0.33.0
0.32.0
0.31.1
0.31.0
0.30.0
0.29.0
0.28.0
0.27.0
0.26.0
0.25.0
0.24.0
0.23.1
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.1
0.15.0
0.14.0
0.13.0
0.12.0
0.11.0
0.10.1
0.10.0
0.9.0
0.8.0
0.7.0
0.6.1
0.6.0
0.5.0
0.4.0
0.3.0
0.2.1
0.2.0
retired
0.1.0
NIF based bindings for libvips
Current section
Files
Jump to
Current section
Files
c_src/g_object/g_value.c
#include <glib-object.h>
#include "../utils.h"
#include "g_boxed.h"
#include "g_object.h"
#include "g_value.h"
static VixResult set_enum(ErlNifEnv *env, ERL_NIF_TERM term, GValue *gvalue) {
int value;
VixResult res;
if (!enif_get_int(env, term, &value)) {
SET_ERROR_RESULT(env, "failed to get enum int value from erl term", res);
return res;
}
g_value_set_enum(gvalue, value);
SET_VIX_RESULT(res, ATOM_OK);
return res;
}
static VixResult set_flags(ErlNifEnv *env, ERL_NIF_TERM term, GValue *gvalue) {
int value;
VixResult res;
if (!enif_get_int(env, term, &value)) {
SET_ERROR_RESULT(env, "failed to get flag int value from erl term", res);
return res;
}
g_value_set_flags(gvalue, value);
SET_VIX_RESULT(res, ATOM_OK);
return res;
}
static VixResult set_boolean(ErlNifEnv *env, ERL_NIF_TERM term,
GValue *gvalue) {
char atom[10] = {0};
bool boolean_value;
VixResult res;
if (enif_get_atom(env, term, atom, 9, ERL_NIF_LATIN1) < 1) {
SET_ERROR_RESULT(env, "failed to get atom", res);
return res;
}
if (strcmp(atom, "true") == 0) {
boolean_value = true;
} else if (strcmp(atom, "false") == 0) {
boolean_value = false;
} else {
SET_ERROR_RESULT(env, "invalid atom value, value must be :true or :false",
res);
return res;
}
g_value_set_boolean(gvalue, boolean_value);
SET_VIX_RESULT(res, ATOM_OK);
return res;
}
static VixResult set_int(ErlNifEnv *env, ERL_NIF_TERM term, GValue *gvalue) {
int int_value;
VixResult res;
if (!enif_get_int(env, term, &int_value)) {
SET_ERROR_RESULT(env, "failed to get int from erl term", res);
return res;
}
g_value_set_int(gvalue, int_value);
SET_VIX_RESULT(res, ATOM_OK);
return res;
}
static VixResult set_uint(ErlNifEnv *env, ERL_NIF_TERM term, GValue *gvalue) {
unsigned int uint_value;
VixResult res;
if (!enif_get_uint(env, term, &uint_value)) {
SET_ERROR_RESULT(env, "failed to get uint from erl term", res);
return res;
}
g_value_set_uint(gvalue, uint_value);
SET_VIX_RESULT(res, ATOM_OK);
return res;
}
static VixResult set_int64(ErlNifEnv *env, ERL_NIF_TERM term, GValue *gvalue) {
long int64_value;
VixResult res;
if (!enif_get_int64(env, term, &int64_value)) {
SET_ERROR_RESULT(env, "failed to get int64 from erl term", res);
return res;
}
g_value_set_int64(gvalue, int64_value);
SET_VIX_RESULT(res, ATOM_OK);
return res;
}
static VixResult set_string(ErlNifEnv *env, ERL_NIF_TERM term, GValue *gvalue) {
ErlNifBinary bin;
VixResult res;
if (!enif_inspect_iolist_as_binary(env, term, &bin)) {
SET_ERROR_RESULT(env, "failed to get string from erl term", res);
return res;
}
// we ensure that data is appended with NULL while passing string from elixir
g_value_set_string(gvalue, (const gchar *)bin.data);
SET_VIX_RESULT(res, ATOM_OK);
return res;
}
static VixResult set_uint64(ErlNifEnv *env, ERL_NIF_TERM term, GValue *gvalue) {
unsigned long uint64_value;
VixResult res;
if (!enif_get_uint64(env, term, &uint64_value)) {
SET_ERROR_RESULT(env, "failed to get uint64 from erl term", res);
return res;
}
g_value_set_uint64(gvalue, uint64_value);
SET_VIX_RESULT(res, ATOM_OK);
return res;
}
static VixResult set_double(ErlNifEnv *env, ERL_NIF_TERM term, GValue *gvalue) {
double double_value;
VixResult res;
if (!enif_get_double(env, term, &double_value)) {
SET_ERROR_RESULT(env, "failed to get double from erl term", res);
return res;
}
g_value_set_double(gvalue, double_value);
SET_VIX_RESULT(res, ATOM_OK);
return res;
}
static VixResult set_boxed(ErlNifEnv *env, ERL_NIF_TERM term, GValue *gvalue) {
gpointer ptr = NULL;
VixResult res;
if (!erl_term_to_g_boxed(env, term, &ptr)) {
SET_ERROR_RESULT(env, "failed to get boxed pointer from erl term", res);
return res;
}
g_value_set_boxed(gvalue, ptr);
SET_VIX_RESULT(res, ATOM_OK);
return res;
}
static VixResult set_g_object(ErlNifEnv *env, ERL_NIF_TERM term,
GValue *gvalue) {
GObject *obj;
VixResult res;
if (!erl_term_to_g_object(env, term, &obj)) {
SET_ERROR_RESULT(env, "failed to get GObject argument", res);
return res;
}
g_value_set_object(gvalue, obj);
SET_VIX_RESULT(res, ATOM_OK);
return res;
}
VixResult set_g_value_from_erl_term(ErlNifEnv *env, GParamSpec *pspec,
ERL_NIF_TERM term, GValue *gvalue) {
VixResult res;
g_value_init(gvalue, G_PARAM_SPEC_VALUE_TYPE(pspec));
if (G_IS_PARAM_SPEC_ENUM(pspec))
return set_enum(env, term, gvalue);
else if (G_IS_PARAM_SPEC_BOOLEAN(pspec))
return set_boolean(env, term, gvalue);
else if (G_IS_PARAM_SPEC_UINT64(pspec))
return set_uint64(env, term, gvalue);
else if (G_IS_PARAM_SPEC_DOUBLE(pspec))
return set_double(env, term, gvalue);
else if (G_IS_PARAM_SPEC_INT(pspec))
return set_int(env, term, gvalue);
else if (G_IS_PARAM_SPEC_UINT(pspec))
return set_uint(env, term, gvalue);
else if (G_IS_PARAM_SPEC_INT64(pspec))
return set_int64(env, term, gvalue);
else if (G_IS_PARAM_SPEC_STRING(pspec))
return set_string(env, term, gvalue);
else if (G_IS_PARAM_SPEC_BOXED(pspec))
return set_boxed(env, term, gvalue);
else if (G_IS_PARAM_SPEC_OBJECT(pspec))
return set_g_object(env, term, gvalue);
else if (G_IS_PARAM_SPEC_FLAGS(pspec))
return set_flags(env, term, gvalue);
else {
SET_ERROR_RESULT(env, "unknown pspec", res);
return res;
}
}
static VixResult get_enum(ErlNifEnv *env, GValue *gvalue) {
gint enum_int;
enum_int = g_value_get_enum(gvalue);
return vix_result(enif_make_int(env, enum_int));
}
static VixResult get_enum_as_atom(ErlNifEnv *env, GValue *gvalue) {
gint enum_int;
ERL_NIF_TERM enum_term;
GEnumClass *enum_class;
GEnumValue *enum_value;
enum_class = g_type_class_ref(G_VALUE_TYPE(gvalue));
enum_int = g_value_get_enum(gvalue);
enum_value = g_enum_get_value(enum_class, enum_int);
enum_term = enif_make_atom(env, enum_value->value_name);
g_type_class_unref(enum_class);
return vix_result(enum_term);
}
static VixResult get_flags(ErlNifEnv *env, GValue *gvalue) {
gint flags_int;
flags_int = g_value_get_flags(gvalue);
return vix_result(enif_make_int(env, flags_int));
}
static VixResult get_flags_as_atoms(ErlNifEnv *env, GValue *gvalue) {
guint flags;
guint flag;
ERL_NIF_TERM flags_list;
ERL_NIF_TERM flag_term;
GFlagsClass *flags_class;
GFlagsValue *flags_value;
int bit_pos;
flags_list = enif_make_list(env, 0);
flags_class = g_type_class_ref(G_VALUE_TYPE(gvalue));
flags = g_value_get_flags(gvalue);
bit_pos = 0;
while (flags > 0) {
if (flags & 0x01) {
flag = 1 << bit_pos;
flags_value = g_flags_get_first_value(flags_class, flag);
flag_term = enif_make_atom(env, flags_value->value_name);
flags_list = enif_make_list_cell(env, flag_term, flags_list);
}
bit_pos++;
flags = flags >> 1;
}
g_type_class_unref(flags_class);
return vix_result(flags_list);
}
static VixResult get_boolean(ErlNifEnv *env, GValue *gvalue) {
bool bool_value;
bool_value = g_value_get_boolean(gvalue);
if (bool_value)
return vix_result(ATOM_TRUE);
else
return vix_result(ATOM_FALSE);
}
static VixResult get_int(ErlNifEnv *env, GValue *gvalue) {
int int_value;
int_value = g_value_get_int(gvalue);
return vix_result(enif_make_int(env, int_value));
}
static VixResult get_uint(ErlNifEnv *env, GValue *gvalue) {
unsigned int uint_value;
uint_value = g_value_get_uint(gvalue);
return vix_result(enif_make_int(env, uint_value));
}
static VixResult get_int64(ErlNifEnv *env, GValue *gvalue) {
long int64_value;
int64_value = g_value_get_int64(gvalue);
return vix_result(enif_make_int(env, int64_value));
}
static VixResult get_string_as_binary(ErlNifEnv *env, GValue *gvalue) {
const gchar *str;
ERL_NIF_TERM bin;
ssize_t length;
unsigned char *temp;
VixResult res;
str = g_value_get_string(gvalue);
if (str != NULL) {
length = strlen(str);
temp = enif_make_new_binary(env, length, &bin);
memcpy(temp, str, length);
SET_VIX_RESULT(res, bin);
} else {
res.is_success = false;
res.result = ATOM_NULL_VALUE;
}
return res;
}
static VixResult get_uint64(ErlNifEnv *env, GValue *gvalue) {
unsigned long uint64_value;
uint64_value = g_value_get_uint64(gvalue);
return vix_result(enif_make_int(env, uint64_value));
}
static VixResult get_double(ErlNifEnv *env, GValue *gvalue) {
double double_value;
double_value = g_value_get_double(gvalue);
/*
* NOTE: erlang does not support NaN & infinity, we only handle finite double
* value. see: https://erlang.org/doc/man/erl_nif.html#enif_make_double
*/
return vix_result(enif_make_double(env, double_value));
}
static VixResult get_boxed(ErlNifEnv *env, GValue *gvalue) {
gpointer ptr;
GType type;
VixResult res;
// duplicate value so that we can free it ourselves
ptr = g_value_dup_boxed(gvalue);
if (ptr != NULL) {
type = G_VALUE_TYPE(gvalue);
SET_VIX_RESULT(res, boxed_to_erl_term(env, ptr, type));
} else {
res.is_success = false;
res.result = ATOM_NULL_VALUE;
}
return res;
}
static VixResult get_g_object(ErlNifEnv *env, GValue *gvalue) {
GObject *obj;
VixResult res;
obj = g_value_get_object(gvalue);
if (obj != NULL) {
// explicitly get a ref for the output property so that we can
// unref all output objects of the operation at once
g_object_ref(obj);
SET_VIX_RESULT(res, g_object_to_erl_term(env, obj));
} else {
res.is_success = false;
res.result = ATOM_NULL_VALUE;
}
return res;
}
VixResult get_erl_term_from_g_object_property(ErlNifEnv *env, GObject *obj,
const char *name,
GParamSpec *pspec) {
GValue gvalue = {0};
VixResult res;
g_value_init(&gvalue, G_PARAM_SPEC_VALUE_TYPE(pspec));
g_object_get_property(obj, name, &gvalue);
if (G_IS_PARAM_SPEC_ENUM(pspec))
res = get_enum(env, &gvalue);
else if (G_IS_PARAM_SPEC_BOOLEAN(pspec))
res = get_boolean(env, &gvalue);
else if (G_IS_PARAM_SPEC_UINT64(pspec))
res = get_uint64(env, &gvalue);
else if (G_IS_PARAM_SPEC_DOUBLE(pspec))
res = get_double(env, &gvalue);
else if (G_IS_PARAM_SPEC_INT(pspec))
res = get_int(env, &gvalue);
else if (G_IS_PARAM_SPEC_UINT(pspec))
res = get_uint(env, &gvalue);
else if (G_IS_PARAM_SPEC_INT64(pspec))
res = get_int64(env, &gvalue);
else if (G_IS_PARAM_SPEC_STRING(pspec))
res = get_string_as_binary(env, &gvalue);
else if (G_IS_PARAM_SPEC_BOXED(pspec))
res = get_boxed(env, &gvalue);
else if (G_IS_PARAM_SPEC_OBJECT(pspec))
res = get_g_object(env, &gvalue);
else if (G_IS_PARAM_SPEC_FLAGS(pspec))
res = get_flags(env, &gvalue);
else
SET_ERROR_RESULT(env, "unknown pspec", res);
g_value_unset(&gvalue);
return res;
}
VixResult g_value_to_erl_term(ErlNifEnv *env, GValue gvalue) {
VixResult res;
GType type;
type = G_VALUE_TYPE(&gvalue);
debug("G_VALUE_TYPE: %s", g_type_name(type));
if (type == G_TYPE_BOOLEAN)
res = get_boolean(env, &gvalue);
else if (type == G_TYPE_UINT64)
res = get_uint64(env, &gvalue);
else if (type == G_TYPE_DOUBLE)
res = get_double(env, &gvalue);
else if (type == G_TYPE_INT)
res = get_int(env, &gvalue);
else if (type == G_TYPE_UINT)
res = get_uint(env, &gvalue);
else if (type == G_TYPE_INT64)
res = get_int64(env, &gvalue);
else if (type == G_TYPE_STRING)
res = get_string_as_binary(env, &gvalue);
else if (G_TYPE_IS_BOXED(type))
res = get_boxed(env, &gvalue);
else if (G_TYPE_IS_ENUM(type))
res = get_enum_as_atom(env, &gvalue);
else if (G_TYPE_IS_OBJECT(type))
res = get_g_object(env, &gvalue);
else if (G_TYPE_IS_FLAGS(type))
res = get_flags_as_atoms(env, &gvalue);
else
SET_ERROR_RESULT(env, "specified GValue type is not supported", res);
g_value_unset(&gvalue);
return res;
}
VixResult erl_term_to_g_value(ErlNifEnv *env, GType type, ERL_NIF_TERM term,
GValue *gvalue) {
VixResult res;
debug("G_VALUE_TYPE: %s", g_type_name(type));
g_value_init(gvalue, type);
if (type == G_TYPE_BOOLEAN)
return set_boolean(env, term, gvalue);
else if (type == G_TYPE_UINT64)
return set_uint64(env, term, gvalue);
else if (type == G_TYPE_DOUBLE)
return set_double(env, term, gvalue);
else if (type == G_TYPE_INT)
return set_int(env, term, gvalue);
else if (type == G_TYPE_UINT)
return set_uint(env, term, gvalue);
else if (type == G_TYPE_INT64)
return set_int64(env, term, gvalue);
else if (type == G_TYPE_STRING)
return set_string(env, term, gvalue);
else if (G_TYPE_IS_BOXED(type))
return set_boxed(env, term, gvalue);
else if (G_TYPE_IS_ENUM(type))
return set_enum(env, term, gvalue);
else if (G_TYPE_IS_OBJECT(type))
return set_g_object(env, term, gvalue);
else if (G_TYPE_IS_FLAGS(type))
return set_flags(env, term, gvalue);
else {
SET_ERROR_RESULT(env, "specified GValue type is not supported", res);
return res;
}
}