• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #ifndef META_API_EVENT_HANDLER_H
16 #define META_API_EVENT_HANDLER_H
17 
18 #include <meta/api/deferred_callback.h>
19 #include <meta/api/make_callback.h>
20 #include <meta/base/interface_macros.h>
21 #include <meta/base/namespace.h>
22 #include <meta/interface/intf_task_queue_registry.h>
23 #include <meta/interface/property/intf_property.h>
24 
META_BEGIN_NAMESPACE()25 META_BEGIN_NAMESPACE()
26 
27 /**
28  * @brief The EventHandler class is a helper class for adding event handlers to events.
29  *
30  *        EventHandler takes care of removing the event handler automatically
31  *        when the target event changes or when the EventHandler object is destroyed.
32  *
33  *        Calling Subscribe when already subscribed will remove the old subscription.
34  */
35 class EventHandler {
36 public:
37     META_NO_COPY(EventHandler)
38     EventHandler() noexcept = default;
39     virtual ~EventHandler()
40     {
41         Unsubscribe();
42     }
43 
44     EventHandler(EventHandler&& other) noexcept
45         : event_ { BASE_NS::move(other.event_) }, token_ { BASE_NS::exchange(other.token_, {}) }
46     {}
47 
48     EventHandler& operator=(EventHandler&& other) noexcept
49     {
50         if (&other != this) {
51             Unsubscribe();
52             event_ = BASE_NS::move(other.event_);
53             token_ = BASE_NS::exchange(other.token_, {});
54         }
55         return *this;
56     }
57 
58     template<typename EventType>
59     EventHandler(const Event<EventType>& event, const typename EventType::InterfaceTypePtr& func,
60         const ITaskQueue::Ptr& queue = nullptr)
61     {
62         Subscribe(event, func, queue);
63     }
64 
65     template<typename EventType>
66     EventHandler(
67         const Event<EventType>& event, const typename EventType::InterfaceTypePtr& func, const BASE_NS::Uid& queueId)
68     {
69         Subscribe(event, func, queueId);
70     }
71 
72     EventHandler(const BASE_NS::shared_ptr<IEvent>& event, const ICallable::Ptr& func)
73     {
74         TypelessSubscribe(event, func);
75     }
76 
77     template<typename EventType, typename Func,
78         typename = EnableIfCanInvokeWithArguments<Func, typename EventType::FunctionType>>
79     EventHandler(const Event<EventType>& event, Func func, const ITaskQueue::Ptr& queue = nullptr)
80     {
81         Subscribe(event, BASE_NS::move(func), queue);
82     }
83 
84     template<typename EventType, typename Func,
85         typename = EnableIfCanInvokeWithArguments<Func, typename EventType::FunctionType>>
86     EventHandler(
87         const Event<EventType>& event, const typename EventType::InterfaceTypePtr& func, const BASE_NS::Uid& queueId)
88     {
89         Subscribe(event, BASE_NS::move(func), queueId);
90     }
91 
92     /**
93      * @brief Check if this handler has subscribed to an event
94      */
95     bool IsValid() const
96     {
97         return !event_.expired();
98     }
99 
100     /**
101      * @brief Subscribe to an event.
102      * @param event Event to subscribe to.
103      * @param func Callable to invoke when event is triggered.
104      * @return True if the successfully subscribed.
105      */
106     bool TypelessSubscribe(const IEvent::Ptr& event, const ICallable::Ptr& func)
107     {
108         if (!event) {
109             CORE_LOG_E("Cannot subscribe to null event");
110             return false;
111         }
112         Unsubscribe();
113         token_ = event->AddHandler(func);
114         if (token_) {
115             event_ = event;
116         }
117         return token_;
118     }
119 
120     /**
121      * @brief Subscribe to an event.
122      * @param event Event to subscribe to.
123      * @param func Callable to invoke when event is triggered.
124      * @oaram queue Optional queue where 'func' is invoked, if null, invoked directly.
125      * @return True if the successfully subscribed.
126      */
127     template<typename EventType>
128     bool Subscribe(const Event<EventType>& event, const typename EventType::InterfaceTypePtr& func,
129         const ITaskQueue::Ptr& queue = nullptr)
130     {
131         return queue ? TypelessSubscribe(event,
132                            MakeDeferred<typename EventType::InterfaceType>(
133                                [func](auto&&... args) { func->Invoke(BASE_NS::forward<decltype(args)>(args)...); },
134                                queue))
135                      : TypelessSubscribe(event, func);
136     }
137 
138     /**
139      * @brief Subscribe to an event.
140      * @param event Event to subscribe to.
141      * @param func Callable to invoke when event is triggered.
142      * @param queueId Queue id where 'func' is invoked. Fails if no such queue exists.
143      * @return True if the successfully subscribed.
144      */
145     template<typename EventType>
146     bool Subscribe(
147         const Event<EventType>& event, const typename EventType::InterfaceTypePtr& func, const BASE_NS::Uid& queueId)
148     {
149         auto queue = GetTaskQueueRegistry().GetTaskQueue(queueId);
150         if (!queue) {
151             CORE_LOG_E("Cannot initialize event handler for queue %s: Queue not registered.",
152                 BASE_NS::to_string(queueId).c_str());
153         }
154         return queue && Subscribe(event, func, queue);
155     }
156 
157     /**
158      * @brief Subscribe to an event. See above Subscribe function for parameters
159      */
160     template<typename EventType, typename Func,
161         typename = EnableIfCanInvokeWithArguments<Func, typename EventType::FunctionType>>
162     bool Subscribe(const Event<EventType>& event, Func func, const ITaskQueue::Ptr& queue = nullptr)
163     {
164         return Subscribe(event, MakeCallback<EventType>(BASE_NS::move(func)), queue);
165     }
166 
167     /**
168      * @brief Subscribe to an event. See above Subscribe function for parameters
169      */
170     template<typename EventType, typename Func,
171         typename = EnableIfCanInvokeWithArguments<Func, typename EventType::FunctionType>>
172     bool Subscribe(const Event<EventType>& event, Func func, const BASE_NS::Uid& queueId)
173     {
174         return Subscribe(event, MakeCallback<EventType>(BASE_NS::move(func)), queueId);
175     }
176 
177     /**
178      * @brief Subscribe to an event. See above Subscribe function for parameters
179      */
180     template<typename EventType, typename Func,
181         typename = EnableIfCanInvokeWithArguments<Func, typename EventType::FunctionType>>
182     bool Subscribe(const BASE_NS::shared_ptr<IEvent>& event, Func func, const ITaskQueue::Ptr& queue = nullptr)
183     {
184         auto ev = interface_pointer_cast<EventType>(event);
185         return ev && Subscribe<EventType>(event, MakeCallback<EventType>(BASE_NS::move(func)), queue);
186     }
187 
188     /**
189      * @brief Subscribe to an event. See above Subscribe function for parameters
190      */
191     template<typename EventType, typename Func,
192         typename = EnableIfCanInvokeWithArguments<Func, typename EventType::FunctionType>>
193     bool Subscribe(const BASE_NS::shared_ptr<IEvent>& event, Func func, const BASE_NS::Uid& queueId)
194     {
195         auto ev = interface_pointer_cast<EventType>(event);
196         return ev && Subscribe<EventType>(event, MakeCallback<EventType>(BASE_NS::move(func)), queueId);
197     }
198 
199     /**
200      * @brief Unsubscribe from the event.
201      */
202     void Unsubscribe()
203     {
204         if (auto e = event_.lock()) {
205             e->RemoveHandler(token_);
206             event_ = nullptr;
207             token_ = {};
208         }
209     }
210 
211 protected:
212     IEvent::WeakPtr event_;
213     IEvent::Token token_ {};
214 };
215 
216 META_END_NAMESPACE()
217 
218 #endif
219