refactor(events): Simplify ScopedCallback creation with type deduction
Introduce a new template overload for `makeScopedCallback` that
automatically deduces the event type from the provided callback's
signature. This is achieved using a `function_traits` helper to inspect
the lambda's arguments.
Previously, creating a scoped callback was verbose:
auto handle = android::base::makeScopedCallback<
SomeCallbackSource<MyEvent>, MyEvent>
(source, [](const MyEvent& event) {});
Now, the compiler can deduce the template arguments automatically:
auto handle = android::base::makeScopedCallback(
source, [](const MyEvent& event) {});
Change-Id: I4a95ba8715ea331d964c7a302afd65b31adcae55
diff --git a/base/include/aemu/base/events/CallbackEventSupport.h b/base/include/aemu/base/events/CallbackEventSupport.h
index 704e0cf..8acea21 100644
--- a/base/include/aemu/base/events/CallbackEventSupport.h
+++ b/base/include/aemu/base/events/CallbackEventSupport.h
@@ -439,5 +439,24 @@
typename ScopedEventCallback<EventSystem, T>::EventCallback callback) {
return std::make_unique<ScopedEventCallback<EventSystem, T>>(system, std::move(callback));
}
+
+// Helper to deduce the event type from a lambda's signature
+template <typename T> struct function_traits;
+template <typename ClassType, typename ReturnType, typename Arg>
+struct function_traits<ReturnType (ClassType::*)(Arg) const> { using event_type = std::decay_t<Arg>; };
+template <typename ClassType, typename ReturnType>
+struct function_traits<ReturnType (ClassType::*)() const> { using event_type = void; };
+
+/**
+ * @brief Helper function to create a ScopedEventCallback with automatic type deduction.
+ * @param system Reference to the event system
+ * @param callback The callback function
+ * @return A new ScopedEventCallback instance
+ */
+template <typename EventSystem, typename F>
+auto makeScopedCallback(EventSystem& system, F&& callback) {
+ using T = typename function_traits<decltype(&F::operator())>::event_type;
+ return std::make_unique<ScopedEventCallback<EventSystem, T>>(system, std::forward<F>(callback));
+}
} // namespace base
} // namespace android
\ No newline at end of file
diff --git a/base/tests/CallbackEvent_unittest.cpp b/base/tests/CallbackEvent_unittest.cpp
index 3a28900..537cbf6 100644
--- a/base/tests/CallbackEvent_unittest.cpp
+++ b/base/tests/CallbackEvent_unittest.cpp
@@ -86,7 +86,7 @@
int count = 0;
{
auto scoped =
- makeScopedCallback<TestEventSystem, int>(events, [&count](const int&) { count++; });
+ makeScopedCallback(events, [&count](const int&) { count++; });
EXPECT_EQ(events.callbackCount(), 1);
events.triggerEvent(42);
@@ -101,7 +101,7 @@
TEST_F(CallbackTests, ScopedCallbackMove) {
int count = 0;
auto scoped =
- makeScopedCallback<TestEventSystem, int>(events, [&count](const int&) { count++; });
+ makeScopedCallback(events, [&count](const int&) { count++; });
// Move the callback
auto moved = std::move(scoped);
@@ -197,7 +197,7 @@
// Memory leak tests (requires running with sanitizers)
TEST_F(CallbackTests, NoMemoryLeaks) {
for (int i = 0; i < 1000; ++i) {
- auto scoped = makeScopedCallback<TestEventSystem, int>(events, [](const int&) {});
+ auto scoped = makeScopedCallback(events, [](const int&) {});
events.triggerEvent(42);
}
EXPECT_EQ(events.callbackCount(), 0);