diff --git a/include/dpp/event_router.h b/include/dpp/event_router.h index e20e6625ae..2a6ce5ba33 100644 --- a/include/dpp/event_router.h +++ b/include/dpp/event_router.h @@ -93,6 +93,7 @@ template class event_router_t { * @brief Thread safety mutex */ mutable std::shared_mutex lock; + /** * @brief Container of event listeners keyed by handle, * as handles are handed out sequentially they will always @@ -101,24 +102,6 @@ template class event_router_t { */ std::map> dispatch_container; - -#ifdef DPP_CORO - /** - * @brief Container for event listeners (coroutines only) - * - * Note: keep a listener's parameter as a value type, the event passed can die while a coroutine is suspended - */ - std::map> coroutine_container; -#else -#ifndef _DOXYGEN_ - /** - * @brief Dummy container to keep the struct size same - */ - std::map> dummy_container; -#endif /* _DOXYGEN_ */ -#endif /* DPP_CORO */ - - /** * @brief A function to be called whenever the method is called, to check * some condition that is required for this event to trigger correctly. @@ -163,13 +146,6 @@ template class event_router_t { listener(event); } }; -#ifdef DPP_CORO - for (const auto& [_, listener] : coroutine_container) { - if (!event.is_cancelled()) { - listener(event); - } - } -#endif /* DPP_CORO */ }; /** @@ -181,11 +157,7 @@ template class event_router_t { */ bool empty() const { std::shared_lock l(lock); -#ifdef DPP_CORO - return dispatch_container.empty() && coroutine_container.empty(); -#else return dispatch_container.empty(); -#endif /* DPP_CORO */ } /** @@ -199,69 +171,148 @@ template class event_router_t { return !empty(); } +#ifdef _DOXYGEN_ /** - * @brief Attach a lambda to the event, adding a listener. - * The lambda should follow the signature specified when declaring - * the event object and should take exactly one parameter derived - * from event_dispatch_t. - * - * @param func Function lambda to attach to event + * @brief Attach a callable to the event, adding a listener. + * The callable should either be of the form `void(const T &)` or + * `dpp::job(T)` (the latter requires DPP_CORO to be defined), + * where T is the event type for this event router. + * + * This has the exact same behavior as using attach. + * + * @see attach + * @param fun Callable to attach to event + * @return event_handle An event handle unique to this event, used to + * detach the listener from the event later if necessary. + */ + template + event_handle operator()(F&& fun); + + /** + * @brief Attach a callable to the event, adding a listener. + * The callable should either be of the form `void(const T &)` or + * `dpp::job(T)` (the latter requires DPP_CORO to be defined), + * where T is the event type for this event router. + * + * @param fun Callable to attach to event + * @return event_handle An event handle unique to this event, used to + * detach the listener from the event later if necessary. + */ + template + event_handle attach(F&& fun); +#else /* not _DOXYGEN_ */ +# ifdef DPP_CORO + /** + * @brief Attach a callable to the event, adding a listener. + * The callable should either be of the form `void(const T &)` or + * `dpp::job(T)` (the latter requires DPP_CORO to be defined), + * where T is the event type for this event router. + * + * @param fun Callable to attach to event + * @return event_handle An event handle unique to this event, used to + * detach the listener from the event later if necessary. + */ + template + requires utility::callable_returns + event_handle operator()(F&& fun) { + return this->attach(std::forward(fun)); + } + + /** + * @brief Attach a callable to the event, adding a listener. + * The callable should either be of the form `void(const T &)` or + * `dpp::job(T)` (the latter requires DPP_CORO to be defined), + * where T is the event type for this event router. + * + * @param fun Callable to attach to event + * @return event_handle An event handle unique to this event, used to + * detach the listener from the event later if necessary. + */ + template + requires std::same_as, void> + event_handle operator()(F&& fun) { + return this->attach(std::forward(fun)); + } +# else + /** + * @brief Attach a callable to the event, adding a listener. + * The callable should either be of the form `void(const T &)` or + * `dpp::job(T)` (the latter requires DPP_CORO to be defined), + * where T is the event type for this event router. + * + * @param fun Callable to attach to event * @return event_handle An event handle unique to this event, used to * detach the listener from the event later if necessary. */ - event_handle operator()(std::function func) { - return this->attach(func); + template + std::enable_if_t, void>, event_handle> operator()(F&& fun) { + return this->attach(std::forward(fun)); } +# endif /* DPP_CORO */ +# ifdef __cpp_concepts // if c++20, use requires instead of enable_if for better errors /** - * @brief Attach a lambda to the event, adding a listener. - * The lambda should follow the signature specified when declaring - * the event object and should take exactly one parameter derived - * from event_dispatch_t. + * @brief Attach a callable to the event, adding a listener. + * The callable should be able to take an event object and return void. * - * @param func Function lambda to attach to event + * @param fun Callable to attach to event * @return event_handle An event handle unique to this event, used to * detach the listener from the event later if necessary. */ - event_handle attach(std::function func) { + template + requires std::same_as, void> + event_handle attach(F&& fun) { std::unique_lock l(lock); event_handle h = next_handle++; - dispatch_container.emplace(h, func); + dispatch_container.emplace(h, std::forward(fun)); return h; } - -#ifdef DPP_CORO +# else /** - * @brief Attach a coroutine task to the event, adding a listener. - * The coroutine should follow the signature specified when declaring - * the event object and should take exactly one parameter derived - * from event_dispatch_t. + * @brief Attach a callable to the event, adding a listener. + * The callable should be able to take an event object and return void. * - * @param func Coroutine task to attack to the event. It MUST take the event by value. + * @param fun Callable to attach to event * @return event_handle An event handle unique to this event, used to * detach the listener from the event later if necessary. */ - event_handle co_attach(std::function func) { + template + std::enable_if_t, void>, event_handle> attach(F&& fun) { std::unique_lock l(lock); event_handle h = next_handle++; - coroutine_container.emplace(h, func); + dispatch_container.emplace(h, std::forward(fun)); return h; } -#endif /* DPP_CORO */ +# endif /* __cpp_concepts */ +# ifdef DPP_CORO + /** + * @brief Attach a callable to the event, adding a listener. + * The callable should be able to take an event object and return a dpp::job. + * + * @param fun Callable to attach to event + * @return event_handle An event handle unique to this event, used to + * detach the listener from the event later if necessary. + */ + template + requires utility::callable_returns + event_handle attach(F&& fun) { + std::unique_lock l(lock); + event_handle h = next_handle++; + dispatch_container.emplace(h, std::forward(fun)); + return h; + } +# endif /* DPP_CORO */ +#endif /* _DOXYGEN_ */ /** * @brief Detach a listener from the event using a previously obtained ID. - * + * * @param handle An ID obtained from event_router_t::operator() * @return true The event was successfully detached * @return false The ID is invalid (possibly already detached, or does not exist) */ bool detach(const event_handle& handle) { std::unique_lock l(lock); -#ifdef DPP_CORO - return this->dispatch_container.erase(handle) || this->coroutine_container.erase(handle); -#else return this->dispatch_container.erase(handle); -#endif /* DPP_CORO */ } }; diff --git a/include/dpp/utility.h b/include/dpp/utility.h index d2e98168cf..048e6a47e6 100644 --- a/include/dpp/utility.h +++ b/include/dpp/utility.h @@ -603,5 +603,10 @@ namespace dpp { */ void DPP_EXPORT set_thread_name(const std::string& name); +#ifdef __cpp_concepts // if c++20 + template + concept callable_returns = std::convertible_to, R>; +#endif + } // namespace utility } // namespace dpp diff --git a/src/unittest/coro.cpp b/src/unittest/coro.cpp index 1c6357b898..922e715c03 100644 --- a/src/unittest/coro.cpp +++ b/src/unittest/coro.cpp @@ -389,7 +389,7 @@ void coro_offline_tests() } void event_handler_test(dpp::cluster *bot) { - bot->on_message_create.co_attach([](dpp::message_create_t event) -> dpp::job { + bot->on_message_create([](dpp::message_create_t event) -> dpp::job { if (event.msg.content == "coro test") { dpp::cluster *bot = event.from->creator; diff --git a/src/unittest/test.cpp b/src/unittest/test.cpp index ed43199bb4..b780a39d5b 100644 --- a/src/unittest/test.cpp +++ b/src/unittest/test.cpp @@ -574,7 +574,7 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b * are sending audio later, this way if the audio receive code is plain unstable * the test suite will crash and fail. */ - bot.on_voice_receive_combined([&](auto& event) { + bot.on_voice_receive_combined([&](const auto& event) { }); std::promise ready_promise;