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