Skip to content

Commit

Permalink
unions working
Browse files Browse the repository at this point in the history
Signed-off-by: Pantelis Antoniou <[email protected]>
  • Loading branch information
pantoniou committed Jan 17, 2025
1 parent 4dc5eec commit e8fad77
Showing 1 changed file with 114 additions and 17 deletions.
131 changes: 114 additions & 17 deletions src/tool/fy-tool.c
Original file line number Diff line number Diff line change
Expand Up @@ -2151,6 +2151,7 @@ struct reflection_field_data {
bool omit_on_emit;
bool required;
bool is_counter; /* is a counter of another field */
bool is_selector; /* is a selector of another field */
const char *counter; /* set to the sibling field that contains the counter */
struct fy_document *yaml_annotation; /* of the field */
const char *yaml_annotation_str; /* the annotation as a string */
Expand Down Expand Up @@ -2189,8 +2190,9 @@ struct reflection_type_data {
const char *flat_field; /* set to field which flattens us */
const char *key_field; /* set to the key field of a map */
bool skip_unknown; /* allowed to skip unknown fields */
const char *selector; /* union selector */
struct reflection_type_data *rtd_selector; /* selector type for unions */
int selector_field_idx; /* the index of the selector in the parent struct*/
int union_field_idx; /* the index of the union in the parent struct */
struct fy_document *yaml_annotation; /* the yaml annotation */
const char *yaml_annotation_str; /* the annotation as a string */

Expand Down Expand Up @@ -2386,6 +2388,11 @@ struct reflection_type_data *
reflection_type_data_ref(struct reflection_type_data *rtd);
void reflection_type_data_unref(struct reflection_type_data *rtd);

int reflection_field_data_index(struct reflection_field_data *rfd)
{
return rfd ? fy_field_info_index(rfd->fi) : -1;
}

struct reflection_field_data *
reflection_type_data_lookup_field(struct reflection_type_data *rtd, const char *field)
{
Expand Down Expand Up @@ -3749,12 +3756,11 @@ static int struct_fill_in_field(struct reflection_object *ro, struct fy_parser *

static int struct_finish(struct reflection_object *ro, struct fy_parser *fyp, struct fy_event *fye, struct fy_path *path)
{
struct reflection_type_data *rtd;
struct reflection_type_data *rtd, *rtd_parent;
struct reflection_field_data *rfd;
struct struct_instance_data *id;
bool is_present;
int i;
int rc;
int i, rc, field_start_idx, field_end_idx;

id = &ro->id_struct;
assert(id);
Expand All @@ -3763,9 +3769,24 @@ static int struct_finish(struct reflection_object *ro, struct fy_parser *fyp, st
if (id->rfd_flatten)
return struct_handle_finish_flatten(ro, fyp, fye, path);

if (id->is_union && id->union_field_idx < 0) {
fy_event_report(fyp, fye, FYEP_VALUE, FYET_ERROR,
"no union data was found");
goto err_out;
}

rc = 0;
rtd = ro->rtd;
for (i = 0; i < rtd->fields_count; i++) {

if (!id->is_union) {
field_start_idx = 0;
field_end_idx = rtd->fields_count;
} else {
field_start_idx = 0;
field_end_idx = field_start_idx + 1;
}

for (i = field_start_idx; i < field_end_idx; i++) {

rfd = rtd->fields[i];

Expand Down Expand Up @@ -3795,6 +3816,16 @@ static int struct_finish(struct reflection_object *ro, struct fy_parser *fyp, st
"missing required field '%s' of struct '%s'",
rfd->field_name, rtd->ti->name);
rc = -1;
goto err_out;
}

if (id->is_union && i == id->union_field_idx) {
rtd_parent = ro->parent->rtd;

fprintf(stderr, A_WHITE "%s %s:%d commit union field %d" A_RESET "\n", __func__, __FILE__, __LINE__, i);
rc = struct_fill_in_field(ro->parent, fyp, fye, path, rtd_parent->fields[i], rfd->fyn_union_select, rfd->union_select_value);
if (rc)
goto err_out;
}
}

Expand Down Expand Up @@ -3890,7 +3921,7 @@ struct_setup_child(struct reflection_object *ro, struct reflection_object *ro_pa

if (id->is_union && id->union_field_idx >= 0) {
fy_parser_report(fyp, FYET_ERROR, fyt_key,
"multiple union field '%s' found in %s '%s'", field, print_type, rtd->ti->name);
"multiple union field cannot be set '%s' found in %s '%s'", field, print_type, rtd->ti->name);
goto err_out;
}

Expand Down Expand Up @@ -3931,6 +3962,7 @@ struct_setup_child(struct reflection_object *ro, struct reflection_object *ro_pa
}

struct_set_field_present(ro_parent, field_idx);

if (id->is_union)
id->union_field_idx = field_idx;

Expand All @@ -3942,6 +3974,51 @@ struct_setup_child(struct reflection_object *ro, struct reflection_object *ro_pa
return -1;
}

static int
get_union_selection_index(struct reflection_type_data *rtd, const void *data,
struct reflection_type_data *rtd_parent)
{
struct reflection_field_data *rfd, *rfd_selector, *rfd_union;
const struct fy_field_info *fi_selector, *fi_union;
const void *parent_data, *field_data;
uintmax_t bitfield_data;
int i;

assert(rtd_parent);
assert(rtd->rtd_selector);

rfd_selector = rtd_parent->fields[rtd->selector_field_idx];
assert(rfd_selector);

rfd_union = rtd_parent->fields[rtd->union_field_idx];
assert(rfd_union);

fi_selector = rfd_selector->fi;
fi_union = rfd_union->fi;

/* retreive the parent data area */
parent_data = data - fi_union->offset;

/* point field data to the selector */
if (!(fi_selector->flags & FYFIF_BITFIELD)) {
field_data = parent_data + fi_selector->offset;
} else {
bitfield_data = load_bitfield_le(data, fi_selector->bit_offset, fi_selector->bit_width, rfd_selector->signess < 0);
field_data = &bitfield_data;
}

/* iterate until there's a match */
for (i = 0; i < rtd->fields_count; i++) {
rfd = rtd->fields[i];

assert(rfd->union_select_value);
if (!reflection_type_data_value_cmp(rtd->rtd_selector, field_data, rfd->union_select_value))
break;

}
return i < rtd->fields_count ? i : -1;
}

int struct_emit(struct reflection_type_data *rtd, struct fy_emitter *fye, const void *data, size_t data_size,
struct reflection_type_data *rtd_parent, void *parent_addr)
{
Expand Down Expand Up @@ -4001,7 +4078,12 @@ int struct_emit(struct reflection_type_data *rtd, struct fy_emitter *fye, const
field_start_idx = 0;
field_end_idx = rtd->fields_count;
} else {
field_start_idx = 0;
field_start_idx = get_union_selection_index(rtd, data, rtd_parent);
if (field_start_idx < 0) {
/* no match found */
fprintf(stderr, A_RED "%s %s:%d goto err_out;" A_RESET "\n", __func__, __FILE__, __LINE__);
goto err_out;
}
field_end_idx = field_start_idx + 1;
}

Expand All @@ -4016,7 +4098,7 @@ int struct_emit(struct reflection_type_data *rtd, struct fy_emitter *fye, const
continue;

/* field that should not appear */
if (rfd->omit_on_emit || rfd->is_counter)
if (rfd->omit_on_emit || rfd->is_counter || rfd->is_selector)
continue;

rtd_field = rfd->rtd;
Expand Down Expand Up @@ -4060,7 +4142,12 @@ void struct_dtor(struct reflection_type_data *rtd, void *data,
field_start_idx = 0;
field_end_idx = rtd->fields_count;
} else {
field_start_idx = 0;
field_start_idx = get_union_selection_index(rtd, data, rtd_parent);
if (field_start_idx < 0) {
/* no match found */
fprintf(stderr, A_RED "%s %s:%d goto err_out;" A_RESET "\n", __func__, __FILE__, __LINE__);
return;
}
field_end_idx = field_start_idx + 1;
}

Expand Down Expand Up @@ -5465,7 +5552,9 @@ bool reflection_type_data_equal(const struct reflection_type_data *rtd1,
str_null_eq(rtd1->flat_field, rtd2->flat_field) &&
str_null_eq(rtd1->key_field, rtd2->key_field) &&
rtd1->skip_unknown == rtd2->skip_unknown &&
str_null_eq(rtd1->selector, rtd2->selector) &&
reflection_type_data_equal(rtd1->rtd_selector, rtd2->rtd_selector) &&
rtd1->selector_field_idx == rtd2->selector_field_idx &&
rtd1->union_field_idx == rtd2->union_field_idx &&
str_null_eq(rtd1->yaml_annotation_str, rtd2->yaml_annotation_str) &&
rtd1->fields_count == rtd2->fields_count;

Expand Down Expand Up @@ -6184,8 +6273,7 @@ reflection_field_data_specialize(struct reflection_field_data *rfd,
}

case FYTK_UNION:
break;

rfd->rtd->union_field_idx = reflection_field_data_index(rfd);
break;

default:
Expand Down Expand Up @@ -6236,7 +6324,7 @@ reflection_type_data_specialize(struct reflection_type_data *rtd,
struct reflection_type_data_stack *rtds)
{
struct reflection_type_data *rtd_parent;
struct reflection_field_data *rfd, *rfd_flatten, *rfd_key, *rfd_selector;
struct reflection_field_data *rfd, *rfd_flatten, *rfd_key, *rfd_selector, *rfdt;
const struct reflection_type_ops *ops;
const char *flatten_field, *key_field, *selector;
enum reflection_type_data_flags dep_flags;
Expand Down Expand Up @@ -6344,15 +6432,21 @@ reflection_type_data_specialize(struct reflection_type_data *rtd,
fprintf(stderr, A_RED "%s %s:%d goto err_out;" A_RESET "\n", __func__, __FILE__, __LINE__);
goto err_out;
}
/* single selector */
if (rfd_selector->is_selector) {
fprintf(stderr, A_RED "%s %s:%d goto err_out;" A_RESET "\n", __func__, __FILE__, __LINE__);
goto err_out;
}
rfd_selector->is_selector = true;
rtd->rtd_selector = reflection_type_data_ref(rfd_selector->rtd);
rtd->selector = selector;
rtd->selector_field_idx = reflection_field_data_index(rfd_selector);

/* for each field in the union a select must exist */
for (i = 0; i < rtd->fields_count; i++) {

rfd = rtd->fields[i];
rfdt = rtd->fields[i];

rc = reflection_field_data_generate_values(rfd, rtd->rtd_selector, "select", &rfd->fyn_union_select, &rfd->union_select_value);
rc = reflection_field_data_generate_values(rfdt, rtd->rtd_selector, "select", &rfdt->fyn_union_select, &rfdt->union_select_value);
if (rc) {
fprintf(stderr, A_RED "%s %s:%d goto err_out;" A_RESET "\n", __func__, __FILE__, __LINE__);
goto err_out;
Expand Down Expand Up @@ -6459,6 +6553,9 @@ reflection_setup_type(struct reflection_type_system *rts,
rtd->yaml_annotation = fy_type_info_get_yaml_annotation(rtd->ti);
rtd->yaml_annotation_str = fy_type_info_get_yaml_comment(rtd->ti);

rtd->selector_field_idx = -1;
rtd->union_field_idx = -1;

if (rtd->fields_count > 0) {
rtd->fields = malloc(sizeof(*rtd->fields) * rtd->fields_count);
if (!rtd->fields) {
Expand Down Expand Up @@ -6761,7 +6858,7 @@ reflection_compose_process_event(struct fy_parser *fyp, struct fy_event *fye, st
assert(rd);

#ifndef NDEBUG
fy_parser_info(fyp, "%s: %c%c%c%c%c %3d - %-32s\n",
fy_parser_debug(fyp, "%s: %c%c%c%c%c %3d - %-32s\n",
fy_event_type_get_text(fye->type),
fy_path_in_root(path) ? 'R' : '-',
fy_path_in_sequence(path) ? 'S' : '-',
Expand Down

0 comments on commit e8fad77

Please sign in to comment.