Skip to content

Commit

Permalink
filterx: implement argument parsing of set_fields()
Browse files Browse the repository at this point in the history
Signed-off-by: Attila Szakacs <attila.szakacs@axoflow.com>
  • Loading branch information
alltilla committed Nov 28, 2024
1 parent ebe30fe commit acc9b3c
Showing 1 changed file with 221 additions and 1 deletion.
222 changes: 221 additions & 1 deletion lib/filterx/func-set-fields.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@
*/

#include "filterx/func-set-fields.h"
#include "filterx/object-string.h"
#include "filterx/object-dict-interface.h"
#include "filterx/expr-literal.h"
#include "filterx/expr-literal-generator.h"
#include "filterx/filterx-object-istype.h"
#include "filterx/filterx-eval.h"

#include <string.h>

#define FILTERX_FUNC_SET_FIELDS_USAGE "set_fields(dict, overrides={\"field\":[...], ...}, defaults={\"field\":[...], ...})"

typedef struct Field_
{
Expand Down Expand Up @@ -113,6 +123,8 @@ _field_add_default(Field *self, FilterXExpr *def)
typedef struct FilterXFunctionSetFields_
{
FilterXFunction super;
FilterXExpr *dict;
GArray *fields;
} FilterXFunctionSetFields;

static FilterXObject *
Expand All @@ -127,6 +139,24 @@ _init(FilterXExpr *s, GlobalConfig *cfg)
{
FilterXFunctionSetFields *self = (FilterXFunctionSetFields *) s;

if (!filterx_expr_init(self->dict, cfg))
return FALSE;

for (guint i = 0; i < self->fields->len; i++)
{
Field *field = &g_array_index(self->fields, Field, i);
if (!_field_init(field, cfg))
{
for (guint j = 0; j < i; j++)
{
field = &g_array_index(self->fields, Field, j);
_field_deinit(field, cfg);
}
filterx_expr_deinit(self->dict, cfg);
return FALSE;
}
}

return filterx_function_init_method(&self->super, cfg);
}

Expand All @@ -135,6 +165,14 @@ _deinit(FilterXExpr *s, GlobalConfig *cfg)
{
FilterXFunctionSetFields *self = (FilterXFunctionSetFields *) s;

filterx_expr_deinit(self->dict, cfg);

for (guint i = 0; i < self->fields->len; i++)
{
Field *field = &g_array_index(self->fields, Field, i);
_field_deinit(field, cfg);
}

filterx_function_deinit_method(&self->super, cfg);
}

Expand All @@ -143,13 +181,193 @@ _free(FilterXExpr *s)
{
FilterXFunctionSetFields *self = (FilterXFunctionSetFields *) s;

filterx_expr_unref(self->dict);

for (guint i = 0; i < self->fields->len; i++)
{
Field *field = &g_array_index(self->fields, Field, i);
_field_destroy(field);
}
g_array_free(self->fields, TRUE);

filterx_function_free_method(&self->super);
}

static FilterXObject *
_extract_field_key_obj(FilterXExpr *key, GError **error)
{
FilterXObject *key_obj = NULL;

if (!filterx_expr_is_literal(key))
goto exit;

key_obj = filterx_expr_eval(key);
if (!filterx_object_is_type(key_obj, &FILTERX_TYPE_NAME(string)))
{
filterx_object_unref(key_obj);
key_obj = NULL;
goto exit;
}

exit:
if (!key_obj)
g_set_error(error, FILTERX_FUNCTION_ERROR, FILTERX_FUNCTION_ERROR_CTOR_FAIL,
"field name must be a string literal. " FILTERX_FUNC_SET_FIELDS_USAGE);
return key_obj;
}

static gboolean
_are_field_keys_equal(FilterXObject *key_a, FilterXObject *key_b)
{
gsize len_a, len_b;
const gchar *key_a_str = filterx_string_get_value_ref(key_a, &len_a);
const gchar *key_b_str = filterx_string_get_value_ref(key_b, &len_b);

return len_a == len_b && strcmp(key_a_str, key_b_str) == 0;
}

static gboolean
_add_override(gsize index, FilterXExpr *value, gpointer user_data)
{
Field *field = (Field *) user_data;
_field_add_override(field, value);
return TRUE;
}

static gboolean
_load_override(FilterXExpr *key, FilterXExpr *value, gpointer user_data)
{
FilterXFunctionSetFields *self = ((gpointer *) user_data)[0];
GError **error = ((gpointer *) user_data)[1];

Field field = { 0 };

field.key = _extract_field_key_obj(key, error);
if (!field.key)
return FALSE;

if (filterx_expr_is_literal_list_generator(value))
g_assert(filterx_literal_list_generator_foreach(value, _add_override, &field));
else
_field_add_override(&field, value);

g_array_append_val(self->fields, field);
return TRUE;
}

static gboolean
_extract_overrides_arg(FilterXFunctionSetFields *self, FilterXFunctionArgs *args, GError **error)
{
FilterXExpr *overrides = filterx_function_args_get_named_expr(args, "overrides");
if (!overrides)
return TRUE;

gboolean success = FALSE;

if (!filterx_expr_is_literal_dict_generator(overrides))
{
g_set_error(error, FILTERX_FUNCTION_ERROR, FILTERX_FUNCTION_ERROR_CTOR_FAIL,
"overrides argument must a literal dict. " FILTERX_FUNC_SET_FIELDS_USAGE);
goto exit;
}

gpointer user_data[] = { self, error };
success = filterx_literal_dict_generator_foreach(overrides, _load_override, user_data);

exit:
filterx_expr_unref(overrides);
return success;
}

static gboolean
_add_default(gsize index, FilterXExpr *value, gpointer user_data)
{
Field *field = (Field *) user_data;
_field_add_default(field, value);
return TRUE;
}

static gboolean
_load_default(FilterXExpr *key, FilterXExpr *value, gpointer user_data)
{
FilterXFunctionSetFields *self = ((gpointer *) user_data)[0];
GError **error = ((gpointer *) user_data)[1];

FilterXObject *key_obj = _extract_field_key_obj(key, error);
if (!key_obj)
return FALSE;

Field *field = NULL;

for (guint i = 0; i < self->fields->len; i++)
{
Field *possible_field = &g_array_index(self->fields, Field, i);
if (_are_field_keys_equal(key_obj, possible_field->key))
{
field = possible_field;
break;
}
}

if (!field)
{
Field new_field = { 0 };
g_array_append_val(self->fields, new_field);
field = &g_array_index(self->fields, Field, self->fields->len - 1);
field->key = filterx_object_ref(key_obj);
}

if (filterx_expr_is_literal_list_generator(value))
g_assert(filterx_literal_list_generator_foreach(value, _add_default, field));
else
_field_add_default(field, value);

filterx_object_unref(key_obj);
return TRUE;
}

static gboolean
_extract_defaults_arg(FilterXFunctionSetFields *self, FilterXFunctionArgs *args, GError **error)
{
FilterXExpr *defaults = filterx_function_args_get_named_expr(args, "defaults");
if (!defaults)
return TRUE;

gboolean success = FALSE;

if (!filterx_expr_is_literal_dict_generator(defaults))
{
g_set_error(error, FILTERX_FUNCTION_ERROR, FILTERX_FUNCTION_ERROR_CTOR_FAIL,
"defaults argument must be a literal dict. " FILTERX_FUNC_SET_FIELDS_USAGE);
goto exit;
}

gpointer user_data[] = { self, error };
success = filterx_literal_dict_generator_foreach(defaults, _load_default, user_data);

exit:
filterx_expr_unref(defaults);
return success;
}

static gboolean
_extract_args(FilterXFunctionSetFields *self, FilterXFunctionArgs *args, GError **error)
{
// TODO: implement
if (filterx_function_args_len(args) != 1)
{
g_set_error(error, FILTERX_FUNCTION_ERROR, FILTERX_FUNCTION_ERROR_CTOR_FAIL,
"invalid number of arguments. " FILTERX_FUNC_SET_FIELDS_USAGE);
return FALSE;
}

self->dict = filterx_function_args_get_expr(args, 0);

if (!_extract_overrides_arg(self, args, error))
return FALSE;

if (!_extract_defaults_arg(self, args, error))
return FALSE;

return TRUE;
}

Expand All @@ -164,6 +382,8 @@ filterx_function_set_fields_new(FilterXFunctionArgs *args, GError **error)
self->super.super.deinit = _deinit;
self->super.super.free_fn = _free;

self->fields = g_array_new(FALSE, FALSE, sizeof(Field));

if (!_extract_args(self, args, error) ||
!filterx_function_args_check(args, error))
goto error;
Expand Down

0 comments on commit acc9b3c

Please sign in to comment.