From 3a9d67cfd8447c0541df9518023ac8560f31256c Mon Sep 17 00:00:00 2001 From: Sander Mertens Date: Mon, 2 Oct 2023 21:41:26 -0700 Subject: [PATCH] Make it possible to create metrics for nested members --- flecs.c | 113 ++++++++++++++---- flecs.h | 27 +++++ .../addons/cpp/mixins/metrics/builder.hpp | 5 + .../flecs/addons/cpp/mixins/metrics/impl.hpp | 12 ++ include/flecs/addons/meta.h | 5 + include/flecs/addons/metrics.h | 5 + src/addons/meta/cursor.c | 18 ++- src/addons/metrics.c | 95 +++++++++++---- test/addons/project.json | 3 +- test/addons/src/Metrics.c | 67 +++++++++++ test/addons/src/main.c | 7 +- test/cpp_api/project.json | 1 + test/cpp_api/src/Misc.cpp | 47 ++++++++ test/cpp_api/src/main.cpp | 7 +- test/meta/project.json | 3 +- test/meta/src/Cursor.c | 32 +++++ test/meta/src/main.c | 7 +- 17 files changed, 397 insertions(+), 57 deletions(-) diff --git a/flecs.c b/flecs.c index 75fc09c626..ed3eaac410 100644 --- a/flecs.c +++ b/flecs.c @@ -28952,18 +28952,74 @@ int flecs_member_metric_init( ecs_entity_t metric, const ecs_metric_desc_t *desc) { - const EcsMember *m = ecs_get(world, desc->member, EcsMember); - if (!m) { - char *metric_name = ecs_get_fullpath(world, metric); - char *member_name = ecs_get_fullpath(world, desc->member); - ecs_err("entity '%s' provided for metric '%s' is not a member", - member_name, metric_name); - ecs_os_free(member_name); - ecs_os_free(metric_name); - goto error; + ecs_entity_t type = 0, member_type = 0, member = 0; + uintptr_t offset = 0; + + if (desc->dotmember) { + if (!desc->id) { + char *metric_name = ecs_get_fullpath(world, metric); + ecs_err("missing id for metric '%s' with member '%s", + metric_name, desc->dotmember); + ecs_os_free(metric_name); + goto error; + } + + if (desc->member) { + char *metric_name = ecs_get_fullpath(world, metric); + ecs_err("cannot set both member and dotmember for metric '%s'", + metric_name); + ecs_os_free(metric_name); + goto error; + } + + ecs_meta_cursor_t cur = ecs_meta_cursor(world, desc->id, NULL); + if (ecs_meta_push(&cur)) { + char *metric_name = ecs_get_fullpath(world, metric); + ecs_err("invalid type for metric '%s'", metric_name); + ecs_os_free(metric_name); + goto error; + } + if (ecs_meta_dotmember(&cur, desc->dotmember)) { + char *metric_name = ecs_get_fullpath(world, metric); + ecs_err("invalid dotmember '%s' for metric '%s'", + desc->dotmember, metric_name); + ecs_os_free(metric_name); + goto error; + } + + type = desc->id; + member_type = ecs_meta_get_type(&cur); + offset = (uintptr_t)ecs_meta_get_ptr(&cur); + member = ecs_meta_get_member_id(&cur); + } else { + const EcsMember *m = ecs_get(world, desc->member, EcsMember); + if (!m) { + char *metric_name = ecs_get_fullpath(world, metric); + char *member_name = ecs_get_fullpath(world, desc->member); + ecs_err("entity '%s' provided for metric '%s' is not a member", + member_name, metric_name); + ecs_os_free(member_name); + ecs_os_free(metric_name); + goto error; + } + + type = ecs_get_parent(world, desc->member); + if (!type) { + char *metric_name = ecs_get_fullpath(world, metric); + char *member_name = ecs_get_fullpath(world, desc->member); + ecs_err("member '%s' provided for metric '%s' is not part of a type", + member_name, metric_name); + ecs_os_free(member_name); + ecs_os_free(metric_name); + goto error; + } + + member = desc->member; + member_type = m->type; + offset = flecs_ito(uintptr_t, m->offset); } - const EcsPrimitive *p = ecs_get(world, m->type, EcsPrimitive); + const EcsPrimitive *p = ecs_get(world, member_type, EcsPrimitive); if (!p) { char *metric_name = ecs_get_fullpath(world, metric); char *member_name = ecs_get_fullpath(world, desc->member); @@ -28974,17 +29030,6 @@ int flecs_member_metric_init( goto error; } - ecs_entity_t type = ecs_get_parent(world, desc->member); - if (!type) { - char *metric_name = ecs_get_fullpath(world, metric); - char *member_name = ecs_get_fullpath(world, desc->member); - ecs_err("member '%s' provided for metric '%s' is not part of a type", - member_name, metric_name); - ecs_os_free(member_name); - ecs_os_free(metric_name); - goto error; - } - const EcsMetaType *mt = ecs_get(world, type, EcsMetaType); if (!mt) { char *metric_name = ecs_get_fullpath(world, metric); @@ -29010,7 +29055,7 @@ int flecs_member_metric_init( ctx->metric.metric = metric; ctx->metric.kind = desc->kind; ctx->type_kind = p->kind; - ctx->offset = flecs_ito(uint16_t, m->offset); + ctx->offset = flecs_uto(uint16_t, offset); ecs_observer(world, { .entity = metric, @@ -29025,7 +29070,7 @@ int flecs_member_metric_init( .ctx = ctx }); - ecs_set_pair(world, metric, EcsMetricMember, desc->member, { .ctx = ctx }); + ecs_set_pair(world, metric, EcsMetricMember, member, { .ctx = ctx }); ecs_add_pair(world, metric, EcsMetric, desc->kind); ecs_add_id(world, metric, EcsMetric); @@ -29223,8 +29268,8 @@ ecs_entity_t ecs_metric_init( #endif } - if (desc->member) { - if (desc->id) { + if (desc->member || desc->dotmember) { + if (desc->id && desc->member) { ecs_err("cannot specify both member and id for metric"); goto error; } @@ -54046,7 +54091,6 @@ ecs_meta_cursor_t ecs_meta_cursor( { ecs_check(world != NULL, ECS_INVALID_PARAMETER, NULL); ecs_check(type != 0, ECS_INVALID_PARAMETER, NULL); - ecs_check(ptr != NULL, ECS_INVALID_PARAMETER, NULL); ecs_meta_cursor_t result = { .world = world, @@ -54560,6 +54604,23 @@ const char* ecs_meta_get_member( return op->name; } +ecs_entity_t ecs_meta_get_member_id( + const ecs_meta_cursor_t *cursor) +{ + ecs_meta_scope_t *scope = flecs_meta_cursor_get_scope(cursor); + ecs_entity_t type = scope->type; + const EcsStruct *st = ecs_get(cursor->world, type, EcsStruct); + if (!st) { + return 0; + } + + ecs_meta_type_op_t *op = flecs_meta_cursor_get_op(scope); + ecs_member_t *m = ecs_vec_get_t( + &st->members, ecs_member_t, op->member_index); + + return m->member; +} + /* Utilities for type conversions and bounds checking */ static struct { int64_t min, max; diff --git a/flecs.h b/flecs.h index 6a9185a739..74534dc2fe 100644 --- a/flecs.h +++ b/flecs.h @@ -11866,6 +11866,11 @@ typedef struct ecs_metric_desc_t { * at the same time as id. Cannot be combined with EcsCounterId. */ ecs_entity_t member; + /* Member dot expression. Can be used instead of member and supports nested + * members. Must be set together with id and should not be set at the same + * time as member. */ + const char *dotmember; + /** Tracks whether entities have the specified component id. Must not be set * at the same time as member. */ ecs_id_t id; @@ -13847,6 +13852,11 @@ FLECS_API const char* ecs_meta_get_member( const ecs_meta_cursor_t *cursor); +/** Get member entity of current member */ +FLECS_API +ecs_entity_t ecs_meta_get_member_id( + const ecs_meta_cursor_t *cursor); + /* The set functions assign the field with the specified value. If the value * does not have the same type as the field, it will be cased to the field type. * If no valid conversion is available, the operation will fail. */ @@ -18287,6 +18297,11 @@ struct metric_builder { template metric_builder& member(const char *name); + metric_builder& dotmember(const char *name); + + template + metric_builder& dotmember(const char *name); + metric_builder& id(flecs::id_t the_id) { m_desc.id = the_id; return *this; @@ -30061,6 +30076,18 @@ inline metric_builder& metric_builder::member(const char *name) { return member(m); } +inline metric_builder& metric_builder::dotmember(const char *expr) { + m_desc.dotmember = expr; + return *this; +} + +template +inline metric_builder& metric_builder::dotmember(const char *expr) { + m_desc.dotmember = expr; + m_desc.id = _::cpp_type::id(m_world); + return *this; +} + inline metric_builder::operator flecs::entity() { if (!m_created) { m_created = true; diff --git a/include/flecs/addons/cpp/mixins/metrics/builder.hpp b/include/flecs/addons/cpp/mixins/metrics/builder.hpp index 6ee27903d1..754475128e 100644 --- a/include/flecs/addons/cpp/mixins/metrics/builder.hpp +++ b/include/flecs/addons/cpp/mixins/metrics/builder.hpp @@ -34,6 +34,11 @@ struct metric_builder { template metric_builder& member(const char *name); + metric_builder& dotmember(const char *name); + + template + metric_builder& dotmember(const char *name); + metric_builder& id(flecs::id_t the_id) { m_desc.id = the_id; return *this; diff --git a/include/flecs/addons/cpp/mixins/metrics/impl.hpp b/include/flecs/addons/cpp/mixins/metrics/impl.hpp index 18bbdc0a58..075626be9b 100644 --- a/include/flecs/addons/cpp/mixins/metrics/impl.hpp +++ b/include/flecs/addons/cpp/mixins/metrics/impl.hpp @@ -43,6 +43,18 @@ inline metric_builder& metric_builder::member(const char *name) { return member(m); } +inline metric_builder& metric_builder::dotmember(const char *expr) { + m_desc.dotmember = expr; + return *this; +} + +template +inline metric_builder& metric_builder::dotmember(const char *expr) { + m_desc.dotmember = expr; + m_desc.id = _::cpp_type::id(m_world); + return *this; +} + inline metric_builder::operator flecs::entity() { if (!m_created) { m_created = true; diff --git a/include/flecs/addons/meta.h b/include/flecs/addons/meta.h index 07ad67c7cc..c39391d60d 100644 --- a/include/flecs/addons/meta.h +++ b/include/flecs/addons/meta.h @@ -603,6 +603,11 @@ FLECS_API const char* ecs_meta_get_member( const ecs_meta_cursor_t *cursor); +/** Get member entity of current member */ +FLECS_API +ecs_entity_t ecs_meta_get_member_id( + const ecs_meta_cursor_t *cursor); + /* The set functions assign the field with the specified value. If the value * does not have the same type as the field, it will be cased to the field type. * If no valid conversion is available, the operation will fail. */ diff --git a/include/flecs/addons/metrics.h b/include/flecs/addons/metrics.h index 3912f8d6ff..1e19786fab 100644 --- a/include/flecs/addons/metrics.h +++ b/include/flecs/addons/metrics.h @@ -79,6 +79,11 @@ typedef struct ecs_metric_desc_t { * at the same time as id. Cannot be combined with EcsCounterId. */ ecs_entity_t member; + /* Member dot expression. Can be used instead of member and supports nested + * members. Must be set together with id and should not be set at the same + * time as member. */ + const char *dotmember; + /** Tracks whether entities have the specified component id. Must not be set * at the same time as member. */ ecs_id_t id; diff --git a/src/addons/meta/cursor.c b/src/addons/meta/cursor.c index 3e45f8ddc0..7890527adb 100644 --- a/src/addons/meta/cursor.c +++ b/src/addons/meta/cursor.c @@ -197,7 +197,6 @@ ecs_meta_cursor_t ecs_meta_cursor( { ecs_check(world != NULL, ECS_INVALID_PARAMETER, NULL); ecs_check(type != 0, ECS_INVALID_PARAMETER, NULL); - ecs_check(ptr != NULL, ECS_INVALID_PARAMETER, NULL); ecs_meta_cursor_t result = { .world = world, @@ -711,6 +710,23 @@ const char* ecs_meta_get_member( return op->name; } +ecs_entity_t ecs_meta_get_member_id( + const ecs_meta_cursor_t *cursor) +{ + ecs_meta_scope_t *scope = flecs_meta_cursor_get_scope(cursor); + ecs_entity_t type = scope->type; + const EcsStruct *st = ecs_get(cursor->world, type, EcsStruct); + if (!st) { + return 0; + } + + ecs_meta_type_op_t *op = flecs_meta_cursor_get_op(scope); + ecs_member_t *m = ecs_vec_get_t( + &st->members, ecs_member_t, op->member_index); + + return m->member; +} + /* Utilities for type conversions and bounds checking */ static struct { int64_t min, max; diff --git a/src/addons/metrics.c b/src/addons/metrics.c index 190cf4f884..4ad7950a81 100644 --- a/src/addons/metrics.c +++ b/src/addons/metrics.c @@ -430,18 +430,74 @@ int flecs_member_metric_init( ecs_entity_t metric, const ecs_metric_desc_t *desc) { - const EcsMember *m = ecs_get(world, desc->member, EcsMember); - if (!m) { - char *metric_name = ecs_get_fullpath(world, metric); - char *member_name = ecs_get_fullpath(world, desc->member); - ecs_err("entity '%s' provided for metric '%s' is not a member", - member_name, metric_name); - ecs_os_free(member_name); - ecs_os_free(metric_name); - goto error; + ecs_entity_t type = 0, member_type = 0, member = 0; + uintptr_t offset = 0; + + if (desc->dotmember) { + if (!desc->id) { + char *metric_name = ecs_get_fullpath(world, metric); + ecs_err("missing id for metric '%s' with member '%s", + metric_name, desc->dotmember); + ecs_os_free(metric_name); + goto error; + } + + if (desc->member) { + char *metric_name = ecs_get_fullpath(world, metric); + ecs_err("cannot set both member and dotmember for metric '%s'", + metric_name); + ecs_os_free(metric_name); + goto error; + } + + ecs_meta_cursor_t cur = ecs_meta_cursor(world, desc->id, NULL); + if (ecs_meta_push(&cur)) { + char *metric_name = ecs_get_fullpath(world, metric); + ecs_err("invalid type for metric '%s'", metric_name); + ecs_os_free(metric_name); + goto error; + } + if (ecs_meta_dotmember(&cur, desc->dotmember)) { + char *metric_name = ecs_get_fullpath(world, metric); + ecs_err("invalid dotmember '%s' for metric '%s'", + desc->dotmember, metric_name); + ecs_os_free(metric_name); + goto error; + } + + type = desc->id; + member_type = ecs_meta_get_type(&cur); + offset = (uintptr_t)ecs_meta_get_ptr(&cur); + member = ecs_meta_get_member_id(&cur); + } else { + const EcsMember *m = ecs_get(world, desc->member, EcsMember); + if (!m) { + char *metric_name = ecs_get_fullpath(world, metric); + char *member_name = ecs_get_fullpath(world, desc->member); + ecs_err("entity '%s' provided for metric '%s' is not a member", + member_name, metric_name); + ecs_os_free(member_name); + ecs_os_free(metric_name); + goto error; + } + + type = ecs_get_parent(world, desc->member); + if (!type) { + char *metric_name = ecs_get_fullpath(world, metric); + char *member_name = ecs_get_fullpath(world, desc->member); + ecs_err("member '%s' provided for metric '%s' is not part of a type", + member_name, metric_name); + ecs_os_free(member_name); + ecs_os_free(metric_name); + goto error; + } + + member = desc->member; + member_type = m->type; + offset = flecs_ito(uintptr_t, m->offset); } - const EcsPrimitive *p = ecs_get(world, m->type, EcsPrimitive); + const EcsPrimitive *p = ecs_get(world, member_type, EcsPrimitive); if (!p) { char *metric_name = ecs_get_fullpath(world, metric); char *member_name = ecs_get_fullpath(world, desc->member); @@ -452,17 +508,6 @@ int flecs_member_metric_init( goto error; } - ecs_entity_t type = ecs_get_parent(world, desc->member); - if (!type) { - char *metric_name = ecs_get_fullpath(world, metric); - char *member_name = ecs_get_fullpath(world, desc->member); - ecs_err("member '%s' provided for metric '%s' is not part of a type", - member_name, metric_name); - ecs_os_free(member_name); - ecs_os_free(metric_name); - goto error; - } - const EcsMetaType *mt = ecs_get(world, type, EcsMetaType); if (!mt) { char *metric_name = ecs_get_fullpath(world, metric); @@ -488,7 +533,7 @@ int flecs_member_metric_init( ctx->metric.metric = metric; ctx->metric.kind = desc->kind; ctx->type_kind = p->kind; - ctx->offset = flecs_ito(uint16_t, m->offset); + ctx->offset = flecs_uto(uint16_t, offset); ecs_observer(world, { .entity = metric, @@ -503,7 +548,7 @@ int flecs_member_metric_init( .ctx = ctx }); - ecs_set_pair(world, metric, EcsMetricMember, desc->member, { .ctx = ctx }); + ecs_set_pair(world, metric, EcsMetricMember, member, { .ctx = ctx }); ecs_add_pair(world, metric, EcsMetric, desc->kind); ecs_add_id(world, metric, EcsMetric); @@ -701,8 +746,8 @@ ecs_entity_t ecs_metric_init( #endif } - if (desc->member) { - if (desc->id) { + if (desc->member || desc->dotmember) { + if (desc->id && desc->member) { ecs_err("cannot specify both member and id for metric"); goto error; } diff --git a/test/addons/project.json b/test/addons/project.json index 3a585ec1d7..a1ce9d3d9d 100644 --- a/test/addons/project.json +++ b/test/addons/project.json @@ -1576,7 +1576,8 @@ "metric_description", "id_count", "id_target_count", - "metric_instance_has_doc_name" + "metric_instance_has_doc_name", + "metric_nested_member" ] }, { "id": "Alerts", diff --git a/test/addons/src/Metrics.c b/test/addons/src/Metrics.c index fe988cccc6..59ac2c19c7 100644 --- a/test/addons/src/Metrics.c +++ b/test/addons/src/Metrics.c @@ -1822,3 +1822,70 @@ void Metrics_metric_instance_has_doc_name(void) { ecs_fini(world); } + +void Metrics_metric_nested_member(void) { + typedef struct { + float x, y; + } Point; + + typedef struct { + float dummy; + Point position; + } Position; + + ecs_world_t *world = ecs_init(); + ECS_IMPORT(world, FlecsMetrics); + + ECS_COMPONENT(world, Point); + ECS_COMPONENT(world, Position); + + ecs_struct(world, { + .entity = ecs_id(Point), + .members = { + { "x", ecs_id(ecs_f32_t) }, + { "y", ecs_id(ecs_f32_t) }, + } + }); + + ecs_struct(world, { + .entity = ecs_id(Position), + .members = { + { "dummy", ecs_id(ecs_f32_t) }, + { "position", ecs_id(Point) }, + } + }); + + ecs_entity_t m = ecs_metric(world, { + .entity = ecs_entity(world, { .name = "metrics.position_y" }), + .id = ecs_id(Position), + .dotmember = "position.y", + .kind = EcsGauge + }); + + test_assert(m != 0); + + ecs_entity_t e1 = ecs_new_entity(world, "e1"); + ecs_set(world, e1, Position, {10, {20, 30}}); + + ecs_progress(world, 0); + + ecs_iter_t it = ecs_children(world, m); + test_bool(true, ecs_children_next(&it)); + test_uint(it.count, 1); + { + ecs_entity_t e = it.entities[0]; + test_assert(ecs_has_pair(world, e, EcsMetric, EcsGauge)); + const EcsMetricSource *src = ecs_get(world, e, EcsMetricSource); + const EcsMetricValue *inst = ecs_get(world, e, EcsMetricValue); + test_assert(src != NULL); + test_assert(inst != NULL); + test_uint(src->entity, e1); + test_int(inst->value, 30); + + test_str(ecs_doc_get_name(world, e), "e1"); + } + + test_bool(false, ecs_children_next(&it)); + + ecs_fini(world); +} diff --git a/test/addons/src/main.c b/test/addons/src/main.c index c946570608..3bd704abe7 100644 --- a/test/addons/src/main.c +++ b/test/addons/src/main.c @@ -1506,6 +1506,7 @@ void Metrics_metric_description(void); void Metrics_id_count(void); void Metrics_id_target_count(void); void Metrics_metric_instance_has_doc_name(void); +void Metrics_metric_nested_member(void); // Testsuite 'Alerts' void Alerts_one_active_alert(void); @@ -7336,6 +7337,10 @@ bake_test_case Metrics_testcases[] = { { "metric_instance_has_doc_name", Metrics_metric_instance_has_doc_name + }, + { + "metric_nested_member", + Metrics_metric_nested_member } }; @@ -7722,7 +7727,7 @@ static bake_test_suite suites[] = { "Metrics", NULL, NULL, - 27, + 28, Metrics_testcases }, { diff --git a/test/cpp_api/project.json b/test/cpp_api/project.json index 27f1f23342..11f08b1b8c 100644 --- a/test/cpp_api/project.json +++ b/test/cpp_api/project.json @@ -1233,6 +1233,7 @@ "member_metric_w_value_name", "member_metric_w_value_name_camel_case_type", "member_metric_w_custom_name", + "dotmember_metric", "counter_id_metric", "counter_target_metric", "alert", diff --git a/test/cpp_api/src/Misc.cpp b/test/cpp_api/src/Misc.cpp index c87158be52..3cdc660e5f 100644 --- a/test/cpp_api/src/Misc.cpp +++ b/test/cpp_api/src/Misc.cpp @@ -812,6 +812,53 @@ void Misc_member_metric_w_custom_name(void) { test_int(count, 2); } +void Misc_dotmember_metric(void) { + flecs::world ecs; + + struct Point { + float x; + float y; + }; + + struct Position { + float dummy; + Point position; + }; + + ecs.import(); + + ecs.component() + .member("x") + .member("y"); + + ecs.component() + .member("dummy") + .member("position"); + + ecs.metric("metrics::position_y") + .kind() + .dotmember("position.y"); + + flecs::entity e1 = ecs.entity().set({10, {20, 30}}); + + ecs.progress(); + + int32_t count = 0; + ecs.filter() + .iter([&](flecs::iter& it, flecs::metrics::Source *s, flecs::metrics::Value *i) { + count += it.count(); + + test_int(count, 1); + test_uint(s[0].entity, e1); + + test_int(i[0].value, 30); + + test_assert(it.entity(0).has()); + }); + + test_int(count, 1); +} + void Misc_counter_id_metric(void) { flecs::world ecs; diff --git a/test/cpp_api/src/main.cpp b/test/cpp_api/src/main.cpp index a079b340f6..22d9823b68 100644 --- a/test/cpp_api/src/main.cpp +++ b/test/cpp_api/src/main.cpp @@ -1179,6 +1179,7 @@ void Misc_component_mixin_member_metric_description(void); void Misc_member_metric_w_value_name(void); void Misc_member_metric_w_value_name_camel_case_type(void); void Misc_member_metric_w_custom_name(void); +void Misc_dotmember_metric(void); void Misc_counter_id_metric(void); void Misc_counter_target_metric(void); void Misc_alert(void); @@ -5849,6 +5850,10 @@ bake_test_case Misc_testcases[] = { "member_metric_w_custom_name", Misc_member_metric_w_custom_name }, + { + "dotmember_metric", + Misc_dotmember_metric + }, { "counter_id_metric", Misc_counter_id_metric @@ -6457,7 +6462,7 @@ static bake_test_suite suites[] = { "Misc", Misc_setup, NULL, - 47, + 48, Misc_testcases }, { diff --git a/test/meta/project.json b/test/meta/project.json index 46ac8e170b..1bc8f698f7 100644 --- a/test/meta/project.json +++ b/test/meta/project.json @@ -403,7 +403,8 @@ "opaque_struct_w_opaque_vec", "opaque_vec_w_opaque_elem", "next_out_of_bounds", - "set_out_of_bounds" + "set_out_of_bounds", + "get_member_id" ] }, { "id": "DeserializeFromExpr", diff --git a/test/meta/src/Cursor.c b/test/meta/src/Cursor.c index 83f5698bec..3ecf566716 100644 --- a/test/meta/src/Cursor.c +++ b/test/meta/src/Cursor.c @@ -4273,3 +4273,35 @@ void Cursor_set_out_of_bounds(void) { ecs_fini(world); } + +void Cursor_get_member_id(void) { + typedef struct { + ecs_i32_t x; + ecs_i32_t y; + } T; + + ecs_world_t *world = ecs_init(); + + ecs_entity_t t = ecs_struct_init(world, &(ecs_struct_desc_t){ + .entity = ecs_entity(world, {.name = "T"}), + .members = { + {"x", ecs_id(ecs_i32_t)}, + {"y", ecs_id(ecs_i32_t)} + } + }); + + test_assert(t != 0); + + T value; + + ecs_meta_cursor_t cur = ecs_meta_cursor(world, t, &value); + test_ok( ecs_meta_push(&cur) ); + test_assert(ecs_meta_get_member_id(&cur) != 0); + test_assert(ecs_meta_get_member_id(&cur) == ecs_lookup_fullpath(world, "T.x")); + test_ok( ecs_meta_next(&cur) ); + test_assert(ecs_meta_get_member_id(&cur) != 0); + test_assert(ecs_meta_get_member_id(&cur) == ecs_lookup_fullpath(world, "T.y")); + test_ok( ecs_meta_pop(&cur) ); + + ecs_fini(world); +} diff --git a/test/meta/src/main.c b/test/meta/src/main.c index 8d275fb4f9..71288e5930 100644 --- a/test/meta/src/main.c +++ b/test/meta/src/main.c @@ -381,6 +381,7 @@ void Cursor_opaque_struct_w_opaque_vec(void); void Cursor_opaque_vec_w_opaque_elem(void); void Cursor_next_out_of_bounds(void); void Cursor_set_out_of_bounds(void); +void Cursor_get_member_id(void); // Testsuite 'DeserializeFromExpr' void DeserializeFromExpr_bool(void); @@ -2427,6 +2428,10 @@ bake_test_case Cursor_testcases[] = { { "set_out_of_bounds", Cursor_set_out_of_bounds + }, + { + "get_member_id", + Cursor_get_member_id } }; @@ -4851,7 +4856,7 @@ static bake_test_suite suites[] = { "Cursor", NULL, NULL, - 122, + 123, Cursor_testcases }, {