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, 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:
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 
RemoveHandler(Token p)128     bool RemoveHandler(Token p) override
129     {
130         if (p == 0) {
131             return true;
132         }
133         CORE_NS::UniqueLock lock { mutex_ };
134         for (auto it = handlers_.begin(); it != handlers_.end(); it++) {
135             if (p == it->token) {
136                 if (--it->count == 0) {
137                     handlers_.erase(it);
138                 }
139                 return true;
140             }
141         }
142         CORE_LOG_F("%s: Tried to remove a non-existent handler", name_.c_str());
143         return false;
144     }
145 
GetHandlers()146     BASE_NS::vector<ICallable::ConstPtr> GetHandlers() const override
147     {
148         CORE_NS::UniqueLock lock { mutex_ };
149         BASE_NS::vector<ICallable::ConstPtr> handlers;
150         handlers.reserve(handlers_.size());
151         for (auto&& p : handlers_) {
152             handlers.emplace_back(p.ptr);
153         }
154         return handlers;
155     }
156 
HasHandlers()157     bool HasHandlers() const override
158     {
159         CORE_NS::UniqueLock lock { mutex_ };
160         return !handlers_.empty();
161     }
162 
GetCallableUid()163     BASE_NS::Uid GetCallableUid() const override
164     {
165         return BaseClass::UID;
166     }
167 
GetName()168     BASE_NS::string_view GetName() const override
169     {
170         CORE_NS::UniqueLock lock { mutex_ };
171         return name_.empty() ? GetEventTypeName() : name_;
172     }
173 
GetEventTypeName()174     BASE_NS::string_view GetEventTypeName() const override
175     {
176         return BaseClass::NAME;
177     }
178 
Invoke(ARG...args)179     void Invoke(ARG... args) override
180     {
181         CORE_NS::UniqueLock lock { mutex_ };
182         if (threadId_ != CORE_NS::ThreadId {} && threadId_ != CORE_NS::CurrentThreadId()) {
183             return;
184         }
185         bool resetThreadId = threadId_ == CORE_NS::ThreadId {};
186         if (resetThreadId) {
187             threadId_ = CORE_NS::CurrentThreadId();
188         }
189 
190         size_t currentCallCount = ++callCount_;
191         // we collect handlers to separate list of weak_ptr
192         if (!handlers_.empty()) {
193             // because callable can remove other handlers or callables
194             BASE_NS::vector<ICallable::WeakPtr> handlers;
195             handlers.reserve(handlers_.size());
196             for (auto&& p : handlers_) {
197                 handlers.emplace_back(p.ptr);
198             }
199 
200             // remember the old count when starting to iterate, so that we can detect if there was recursive call
201             for (auto it = handlers.begin(); it != handlers.end() && currentCallCount == callCount_; ++it) {
202                 if (auto callable = it->lock()) {
203                     lock.Unlock();
204                     Traits::Call(callable, args...);
205                     lock.Lock();
206                 }
207             }
208         }
209 
210         if (resetThreadId) {
211             threadId_ = {};
212         }
213     }
214 
215 private:
216     struct HandlerData {
217         Token token;
218         ICallable::Ptr ptr;
219         std::size_t count { 1 };
220     };
221     BASE_NS::vector<HandlerData> handlers_;
222     size_t callCount_ {};
223     BASE_NS::string name_;
224     mutable CORE_NS::Mutex mutex_;
225     mutable CORE_NS::ThreadId threadId_;
226 };
227 META_END_NAMESPACE()
228 #endif
229