• 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_EXT_EVENT_IMPL_H
16 #define META_EXT_EVENT_IMPL_H
17 
18 #include <base/containers/type_traits.h>
19 #include <base/containers/vector.h>
20 #include <core/log.h>
21 
22 #include <meta/api/function.h>
23 #include <meta/api/threading/mutex.h>
24 #include <meta/base/interface_traits.h>
25 #include <meta/interface/interface_helpers.h>
26 #include <meta/interface/intf_cloneable.h>
27 #include <meta/interface/intf_event.h>
28 #include <meta/interface/object_macros.h>
29 #include <meta/interface/property/property_events.h>
30 
31 META_BEGIN_NAMESPACE()
32 
33 template<typename EventType>
34 struct EventImplTraits {
IsCompatibleInterfaceEventImplTraits35     static bool IsCompatibleInterface(const ICallable::Ptr& c)
36     {
37         if (auto f = interface_pointer_cast<IFunction>(c)) {
38             return IsFunctionCompatible<typename EventType::FunctionType>(f);
39         }
40         return c->GetInterface(EventType::UID) != nullptr || c->GetInterface(IOnChanged::UID) != nullptr;
41     }
42     template<typename... Args>
CallEventImplTraits43     static void Call(const ICallable::Ptr& p, Args&... args)
44     {
45         if (const auto f = interface_pointer_cast<IFunction>(p)) {
46             if constexpr ((true && ... && HasUid_v<PlainType_t<Args>>)) {
47                 CallMetaFunction<void>(f, BASE_NS::forward<Args>(args)...);
48             } else {
49                 CORE_LOG_E("Invalid function signature for meta function call");
50             }
51         } else {
52             if (const auto i = interface_cast<typename EventType::InterfaceType>(p)) {
53                 i->Invoke(args...);
54             } else {
55                 // Allow to always call IOnChanged that takes no parameters, this allows to add handlers for unknown
56                 // event types
57                 if (auto ai = interface_cast<IOnChanged::InterfaceType>(p)) {
58                     ai->Invoke();
59                 } else {
60                     CORE_LOG_E("Invalid callable type for event callback");
61                 }
62             }
63         }
64     }
65 };
66 
67 template<typename BaseClass, typename signature = typename BaseClass::FunctionType>
68 class EventImpl;
69 
70 template<typename BaseClass, typename R, typename... ARG>
71 class EventImpl<BaseClass, R(ARG...)> final : public IntroduceInterfaces<BaseClass, IObject, IEvent, ICloneable> {
72     static_assert(BASE_NS::is_void_v<R>, "EventHandler callable must return void");
73 
74     using Token = typename IEvent::Token;
75     using Traits = EventImplTraits<BaseClass>;
76 
GetClone()77     BASE_NS::shared_ptr<CORE_NS::IInterface> GetClone() const override
78     {
79         BASE_NS::shared_ptr<EventImpl> p(new EventImpl(*this));
80         return interface_pointer_cast<CORE_NS::IInterface>(p);
81     }
82 
EventImpl(const EventImpl & e)83     EventImpl(const EventImpl& e) : handlers_(e.handlers_), name_(e.name_) {}
84 
85 public:
name_(BASE_NS::move (name))86     explicit EventImpl(BASE_NS::string name = {}) : name_(BASE_NS::move(name)) {}
~EventImpl()87     ~EventImpl() override
88     {
89         // check that the invocation doesn't destroy its event impl
90         CORE_ASSERT_MSG(threadId_ == CORE_NS::ThreadId {}, "EventImpl not allowed to destroy itself when invoked");
91         Reset();
92     }
93 
94     EventImpl& operator=(const EventImpl&) = delete;
META_NO_MOVE(EventImpl)95     META_NO_MOVE(EventImpl)
96 
97     void Reset() override
98     {
99         CORE_NS::UniqueLock lock { mutex_ };
100         handlers_.clear();
101     }
102 
IsCompatibleWith(const ICallable::Ptr & p)103     bool IsCompatibleWith(const ICallable::Ptr& p) const override
104     {
105         return Traits::IsCompatibleInterface(p);
106     }
107 
108     using IEvent::AddHandler;
AddHandler(const ICallable::Ptr & p,Token userToken)109     Token AddHandler(const ICallable::Ptr& p, Token userToken) override
110     {
111         if (Traits::IsCompatibleInterface(p)) {
112             Token newToken = userToken ? userToken : (uintptr_t)p.get();
113             CORE_NS::UniqueLock lock { mutex_ };
114             for (auto it = handlers_.begin(); it != handlers_.end(); ++it) {
115                 if (newToken == it->token) {
116                     // Already connected.
117                     ++it->count;
118                     return newToken;
119                 }
120             }
121             handlers_.push_back(HandlerData { newToken, p });
122             return newToken;
123         }
124         CORE_LOG_F("%s: Tried to add a non-matching handler", name_.c_str());
125         return 0;
126     }
127 
EnableHandler(Token p,bool enabled)128     void EnableHandler(Token p, bool enabled) override
129     {
130         if (p == 0) {
131             return;
132         }
133         CORE_NS::UniqueLock lock { mutex_ };
134         for (auto it = handlers_.begin(); it != handlers_.end(); ++it) {
135             if (p == it->token) {
136                 if (!enabled) {
137                     ++it->disabled;
138                 } else if (it->disabled > 0) {
139                     --it->disabled;
140                 }
141                 return;
142             }
143         }
144     }
145 
RemoveHandler(Token p,bool reenable)146     bool RemoveHandler(Token p, bool reenable) override
147     {
148         if (p == 0) {
149             return true;
150         }
151         CORE_NS::UniqueLock lock { mutex_ };
152         for (auto it = handlers_.begin(); it != handlers_.end(); ++it) {
153             if (p == it->token) {
154                 if (--it->count == 0) {
155                     handlers_.erase(it);
156                 } else if (reenable && it->disabled > 0) {
157                     --it->disabled;
158                 }
159                 return true;
160             }
161         }
162         CORE_LOG_F("%s: Tried to remove a non-existent handler", name_.c_str());
163         return false;
164     }
165 
GetHandlers()166     BASE_NS::vector<ICallable::ConstPtr> GetHandlers() const override
167     {
168         CORE_NS::UniqueLock lock { mutex_ };
169         BASE_NS::vector<ICallable::ConstPtr> handlers;
170         handlers.reserve(handlers_.size());
171         for (auto&& p : handlers_) {
172             handlers.emplace_back(p.ptr);
173         }
174         return handlers;
175     }
176 
HasHandlers()177     bool HasHandlers() const override
178     {
179         CORE_NS::UniqueLock lock { mutex_ };
180         return !handlers_.empty();
181     }
182 
GetCallableUid()183     BASE_NS::Uid GetCallableUid() const override
184     {
185         return BaseClass::UID;
186     }
187 
GetName()188     BASE_NS::string GetName() const override
189     {
190         CORE_NS::UniqueLock lock { mutex_ };
191         return name_.empty() ? GetEventTypeName() : name_;
192     }
GetClassId()193     ObjectId GetClassId() const override
194     {
195         return {};
196     }
GetClassName()197     BASE_NS::string_view GetClassName() const override
198     {
199         return "Event";
200     }
GetInterfaces()201     BASE_NS::vector<BASE_NS::Uid> GetInterfaces() const override
202     {
203         return GetInterfacesVector();
204     }
205 
GetEventTypeName()206     BASE_NS::string GetEventTypeName() const override
207     {
208         return BaseClass::NAME;
209     }
210 
Invoke(ARG...args)211     void Invoke(ARG... args) override
212     {
213         CORE_NS::UniqueLock lock { mutex_ };
214         if (threadId_ != CORE_NS::ThreadId {} && threadId_ != CORE_NS::CurrentThreadId()) {
215             return;
216         }
217         bool resetThreadId = threadId_ == CORE_NS::ThreadId {};
218         if (resetThreadId) {
219             threadId_ = CORE_NS::CurrentThreadId();
220         }
221 
222         size_t currentCallCount = ++callCount_;
223         // we collect handlers to separate list of weak_ptr
224         if (!handlers_.empty()) {
225             // because callable can remove other handlers or callables
226             BASE_NS::vector<ICallable::WeakPtr> handlers;
227             handlers.reserve(handlers_.size());
228             for (auto&& p : handlers_) {
229                 if (p.disabled == 0) {
230                     handlers.emplace_back(p.ptr);
231                 }
232             }
233 
234             // remember the old count when starting to iterate, so that we can detect if there was recursive call
235             for (auto it = handlers.begin(); it != handlers.end() && currentCallCount == callCount_; ++it) {
236                 if (auto callable = it->lock()) {
237                     lock.Unlock();
238                     Traits::Call(callable, args...);
239                     lock.Lock();
240                 }
241             }
242         }
243 
244         if (resetThreadId) {
245             threadId_ = {};
246         }
247     }
248 
249 private:
250     struct HandlerData {
251         Token token;
252         ICallable::Ptr ptr;
253         std::uint16_t count { 1 };
254         std::uint16_t disabled {};
255     };
256     BASE_NS::vector<HandlerData> handlers_;
257     size_t callCount_ {};
258     BASE_NS::string name_;
259     mutable CORE_NS::Mutex mutex_;
260     mutable CORE_NS::ThreadId threadId_;
261 };
262 META_END_NAMESPACE()
263 #endif
264