From ef52875c14cb198f6cad2472560a27b407d76996 Mon Sep 17 00:00:00 2001 From: Sander Mertens Date: Mon, 13 Dec 2021 20:28:18 +0000 Subject: [PATCH] #124 implement event data API --- flecs.c | 2 +- flecs.h | 70 ++++++++++++--- include/flecs.h | 2 +- include/flecs/addons/cpp/iter.hpp | 9 ++ .../flecs/addons/cpp/mixins/event/builder.hpp | 46 ++++++++-- .../flecs/addons/cpp/mixins/event/decl.hpp | 9 +- .../flecs/addons/cpp/mixins/event/impl.hpp | 4 +- src/observable.c | 2 +- test/cpp_api/project.json | 5 +- test/cpp_api/src/Event.cpp | 85 +++++++++++++++++++ test/cpp_api/src/main.cpp | 17 +++- 11 files changed, 223 insertions(+), 28 deletions(-) diff --git a/flecs.c b/flecs.c index 0fde83c773..7c59a8b5e2 100644 --- a/flecs.c +++ b/flecs.c @@ -13884,7 +13884,7 @@ void ecs_emit( .other_table = desc->other_table, .offset = row, .count = count, - .param = desc->param + .param = (void*)desc->param }; world->event_id ++; diff --git a/flecs.h b/flecs.h index 47a671b550..c90c191ae2 100644 --- a/flecs.h +++ b/flecs.h @@ -5881,7 +5881,7 @@ typedef struct ecs_event_desc_t { int32_t count; /* Optional context. Assigned to iter param member */ - void *param; + const void *param; /* Observable (usually the world) */ ecs_poly_t *observable; @@ -11392,8 +11392,9 @@ using filter_m_world = filter_m; namespace flecs { // Event builder interface -struct event_builder { - event_builder(flecs::world_t *world, flecs::entity_t event) +template +struct event_builder_base { + event_builder_base(flecs::world_t *world, flecs::entity_t event) : m_world(world) , m_desc{} , m_ids{} @@ -11404,7 +11405,7 @@ struct event_builder { /** Add component to trigger on */ template - event_builder& id() { + Base& id() { m_ids.array = m_ids_array; m_ids.array[m_ids.count] = _::cpp_type().id(m_world); m_ids.count ++; @@ -11412,7 +11413,7 @@ struct event_builder { } /** Add (component) id to trigger on */ - event_builder& id(flecs::id_t id) { + Base& id(flecs::id_t id) { m_ids.array = m_ids_array; m_ids.array[m_ids.count] = id; m_ids.count ++; @@ -11420,7 +11421,7 @@ struct event_builder { } /** Set entity for which to trigger */ - event_builder& entity(flecs::entity_t e) { + Base& entity(flecs::entity_t e) { ecs_record_t *r = ecs_record_find(m_world, e); /* can't trigger for empty entity */ @@ -11434,13 +11435,19 @@ struct event_builder { } /* Set table for which to trigger */ - event_builder& table(flecs::table_t *t, int32_t offset = 0, int32_t count = 0) { + Base& table(flecs::table_t *t, int32_t offset = 0, int32_t count = 0) { m_desc.table = t; m_desc.offset = offset; m_desc.count = count; return *this; } + /* Set event data */ + Base& ctx(const E* ptr) { + m_desc.param = ptr; + return *this; + } + void emit() { ecs_assert(m_ids.count != 0, ECS_INVALID_PARAMETER, NULL); ecs_assert(m_desc.table != nullptr, ECS_INVALID_PARAMETER, NULL); @@ -11450,11 +11457,36 @@ struct event_builder { ecs_emit(m_world, &m_desc); } -private: +protected: flecs::world_t *m_world; ecs_event_desc_t m_desc; flecs::ids_t m_ids; flecs::id_t m_ids_array[ECS_EVENT_DESC_ID_COUNT_MAX]; + +private: + operator Base&() { + return *static_cast(this); + } +}; + +struct event_builder : event_builder_base { + using event_builder_base::event_builder_base; +}; + +template +struct event_builder_typed : event_builder_base, E> { +private: + using Class = event_builder_typed; + using Base = event_builder_base; + +public: + using Base::event_builder_base; + + /* Set event data */ + Class& ctx(const E& ptr) { + this->m_desc.param = &ptr; + return *this; + } }; } @@ -11464,6 +11496,9 @@ namespace flecs { struct event_builder; +template +struct event_builder_typed; + template struct event_m : mixin { }; @@ -11474,16 +11509,18 @@ struct event_m : mixin { /** Create a new event. * + * @param evt The event id. * @return Event builder. */ - flecs::event_builder event(flecs::entity_t event) const; + flecs::event_builder event(flecs::entity_t evt) const; /** Create a new event. * + * @tparam E The event type. * @return Event builder. */ template - flecs::event_builder event() const; + flecs::event_builder_typed event() const; }; using event_m_world = event_m; @@ -13515,6 +13552,15 @@ struct iter { return m_iter->param; } + /** Access param. + * param contains the pointer passed to the param argument of system::run + */ + template + T* param() { + /* TODO: type check */ + return static_cast(m_iter->param); + } + /** Obtain mutable handle to entity being iterated over. * * @param row Row being iterated over. @@ -17883,8 +17929,8 @@ inline flecs::event_builder event_m_world::event(flecs::entity_t evt) const { } template -inline flecs::event_builder event_m_world::event() const { - return flecs::event_builder(this->me(), _::cpp_type().id(this->me())); +inline flecs::event_builder_typed event_m_world::event() const { + return flecs::event_builder_typed(this->me(), _::cpp_type().id(this->me())); } } // namespace flecs diff --git a/include/flecs.h b/include/flecs.h index 134f3dec71..9db87fa3e4 100644 --- a/include/flecs.h +++ b/include/flecs.h @@ -2982,7 +2982,7 @@ typedef struct ecs_event_desc_t { int32_t count; /* Optional context. Assigned to iter param member */ - void *param; + const void *param; /* Observable (usually the world) */ ecs_poly_t *observable; diff --git a/include/flecs/addons/cpp/iter.hpp b/include/flecs/addons/cpp/iter.hpp index 3223d5e152..b44e250f75 100644 --- a/include/flecs/addons/cpp/iter.hpp +++ b/include/flecs/addons/cpp/iter.hpp @@ -219,6 +219,15 @@ struct iter { return m_iter->param; } + /** Access param. + * param contains the pointer passed to the param argument of system::run + */ + template + T* param() { + /* TODO: type check */ + return static_cast(m_iter->param); + } + /** Obtain mutable handle to entity being iterated over. * * @param row Row being iterated over. diff --git a/include/flecs/addons/cpp/mixins/event/builder.hpp b/include/flecs/addons/cpp/mixins/event/builder.hpp index f67b2ea20b..07aaadd116 100644 --- a/include/flecs/addons/cpp/mixins/event/builder.hpp +++ b/include/flecs/addons/cpp/mixins/event/builder.hpp @@ -5,8 +5,9 @@ namespace flecs { // Event builder interface -struct event_builder { - event_builder(flecs::world_t *world, flecs::entity_t event) +template +struct event_builder_base { + event_builder_base(flecs::world_t *world, flecs::entity_t event) : m_world(world) , m_desc{} , m_ids{} @@ -17,7 +18,7 @@ struct event_builder { /** Add component to trigger on */ template - event_builder& id() { + Base& id() { m_ids.array = m_ids_array; m_ids.array[m_ids.count] = _::cpp_type().id(m_world); m_ids.count ++; @@ -25,7 +26,7 @@ struct event_builder { } /** Add (component) id to trigger on */ - event_builder& id(flecs::id_t id) { + Base& id(flecs::id_t id) { m_ids.array = m_ids_array; m_ids.array[m_ids.count] = id; m_ids.count ++; @@ -33,7 +34,7 @@ struct event_builder { } /** Set entity for which to trigger */ - event_builder& entity(flecs::entity_t e) { + Base& entity(flecs::entity_t e) { ecs_record_t *r = ecs_record_find(m_world, e); /* can't trigger for empty entity */ @@ -47,13 +48,19 @@ struct event_builder { } /* Set table for which to trigger */ - event_builder& table(flecs::table_t *t, int32_t offset = 0, int32_t count = 0) { + Base& table(flecs::table_t *t, int32_t offset = 0, int32_t count = 0) { m_desc.table = t; m_desc.offset = offset; m_desc.count = count; return *this; } + /* Set event data */ + Base& ctx(const E* ptr) { + m_desc.param = ptr; + return *this; + } + void emit() { ecs_assert(m_ids.count != 0, ECS_INVALID_PARAMETER, NULL); ecs_assert(m_desc.table != nullptr, ECS_INVALID_PARAMETER, NULL); @@ -63,11 +70,36 @@ struct event_builder { ecs_emit(m_world, &m_desc); } -private: +protected: flecs::world_t *m_world; ecs_event_desc_t m_desc; flecs::ids_t m_ids; flecs::id_t m_ids_array[ECS_EVENT_DESC_ID_COUNT_MAX]; + +private: + operator Base&() { + return *static_cast(this); + } +}; + +struct event_builder : event_builder_base { + using event_builder_base::event_builder_base; +}; + +template +struct event_builder_typed : event_builder_base, E> { +private: + using Class = event_builder_typed; + using Base = event_builder_base; + +public: + using Base::event_builder_base; + + /* Set event data */ + Class& ctx(const E& ptr) { + this->m_desc.param = &ptr; + return *this; + } }; } diff --git a/include/flecs/addons/cpp/mixins/event/decl.hpp b/include/flecs/addons/cpp/mixins/event/decl.hpp index 7e7e914e53..f1a7b98f6b 100644 --- a/include/flecs/addons/cpp/mixins/event/decl.hpp +++ b/include/flecs/addons/cpp/mixins/event/decl.hpp @@ -6,6 +6,9 @@ namespace flecs { struct event_builder; +template +struct event_builder_typed; + template struct event_m : mixin { }; @@ -16,16 +19,18 @@ struct event_m : mixin { /** Create a new event. * + * @param evt The event id. * @return Event builder. */ - flecs::event_builder event(flecs::entity_t event) const; + flecs::event_builder event(flecs::entity_t evt) const; /** Create a new event. * + * @tparam E The event type. * @return Event builder. */ template - flecs::event_builder event() const; + flecs::event_builder_typed event() const; }; using event_m_world = event_m; diff --git a/include/flecs/addons/cpp/mixins/event/impl.hpp b/include/flecs/addons/cpp/mixins/event/impl.hpp index 935a3bc104..38368763a3 100644 --- a/include/flecs/addons/cpp/mixins/event/impl.hpp +++ b/include/flecs/addons/cpp/mixins/event/impl.hpp @@ -12,8 +12,8 @@ inline flecs::event_builder event_m_world::event(flecs::entity_t evt) const { } template -inline flecs::event_builder event_m_world::event() const { - return flecs::event_builder(this->me(), _::cpp_type().id(this->me())); +inline flecs::event_builder_typed event_m_world::event() const { + return flecs::event_builder_typed(this->me(), _::cpp_type().id(this->me())); } } // namespace flecs diff --git a/src/observable.c b/src/observable.c index 9b2b40f37f..00ba39288c 100644 --- a/src/observable.c +++ b/src/observable.c @@ -116,7 +116,7 @@ void ecs_emit( .other_table = desc->other_table, .offset = row, .count = count, - .param = desc->param + .param = (void*)desc->param }; world->event_id ++; diff --git a/test/cpp_api/project.json b/test/cpp_api/project.json index 09d3f3b109..7f7fc12878 100644 --- a/test/cpp_api/project.json +++ b/test/cpp_api/project.json @@ -345,7 +345,10 @@ "evt_2_ids_table", "evt_type", "evt_1_component", - "evt_2_components" + "evt_2_components", + "evt_void_ctx", + "evt_typed_ctx", + "evt_implicit_typed_ctx" ] }, { "id": "Trigger", diff --git a/test/cpp_api/src/Event.cpp b/test/cpp_api/src/Event.cpp index 3bf9da77ec..237f220c40 100644 --- a/test/cpp_api/src/Event.cpp +++ b/test/cpp_api/src/Event.cpp @@ -209,3 +209,88 @@ void Event_evt_2_components() { test_int(count, 2); } + +struct EvtData { + int value; +}; + +void Event_evt_void_ctx() { + flecs::world ecs; + + auto evt = ecs.entity(); + auto id = ecs.entity(); + auto e1 = ecs.entity().add(id); + + int32_t count = 0; + + ecs.trigger() + .event(evt) + .id(id) + .iter([&](flecs::iter& it) { + test_assert(it.entity(0) == e1); + test_int(it.param()->value, 10); + count ++; + }); + + EvtData data = {10}; + + ecs.event(evt) + .id(id) + .entity(e1) + .ctx(&data) + .emit(); + + test_int(count, 1); +} + +void Event_evt_typed_ctx() { + flecs::world ecs; + + auto id = ecs.entity(); + auto e1 = ecs.entity().add(id); + + int32_t count = 0; + + ecs.trigger() + .event() + .id(id) + .iter([&](flecs::iter& it) { + test_assert(it.entity(0) == e1); + test_int(it.param()->value, 10); + count ++; + }); + + ecs.event() + .id(id) + .entity(e1) + .ctx(EvtData{10}) + .emit(); + + test_int(count, 1); +} + +void Event_evt_implicit_typed_ctx() { + flecs::world ecs; + + auto id = ecs.entity(); + auto e1 = ecs.entity().add(id); + + int32_t count = 0; + + ecs.trigger() + .event() + .id(id) + .iter([&](flecs::iter& it) { + test_assert(it.entity(0) == e1); + test_int(it.param()->value, 10); + count ++; + }); + + ecs.event() + .id(id) + .entity(e1) + .ctx({10}) + .emit(); + + test_int(count, 1); +} diff --git a/test/cpp_api/src/main.cpp b/test/cpp_api/src/main.cpp index 0603123326..8a6e707a6e 100644 --- a/test/cpp_api/src/main.cpp +++ b/test/cpp_api/src/main.cpp @@ -328,6 +328,9 @@ void Event_evt_2_ids_table(void); void Event_evt_type(void); void Event_evt_1_component(void); void Event_evt_2_components(void); +void Event_evt_void_ctx(void); +void Event_evt_typed_ctx(void); +void Event_evt_implicit_typed_ctx(void); // Testsuite 'Trigger' void Trigger_on_add(void); @@ -2002,6 +2005,18 @@ bake_test_case Event_testcases[] = { { "evt_2_components", Event_evt_2_components + }, + { + "evt_void_ctx", + Event_evt_void_ctx + }, + { + "evt_typed_ctx", + Event_evt_typed_ctx + }, + { + "evt_implicit_typed_ctx", + Event_evt_implicit_typed_ctx } }; @@ -3676,7 +3691,7 @@ static bake_test_suite suites[] = { "Event", NULL, NULL, - 7, + 10, Event_testcases }, {