/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef META_API_EVENT_HANDLER_H
#define META_API_EVENT_HANDLER_H
#include
#include
#include
#include
#include
#include
META_BEGIN_NAMESPACE()
/**
* @brief The EventHandler class is a helper class for adding event handlers to events.
*
* EventHandler takes care of removing the event handler automatically
* when the target event changes or when the EventHandler object is destroyed.
*
* Calling Subscribe when already subscribed will remove the old subscription.
*/
class EventHandler {
public:
META_NO_COPY(EventHandler)
EventHandler() noexcept = default;
virtual ~EventHandler()
{
Unsubscribe();
}
EventHandler(EventHandler&& other) noexcept
: event_ { BASE_NS::move(other.event_) }, token_ { BASE_NS::exchange(other.token_, {}) }
{}
EventHandler& operator=(EventHandler&& other) noexcept
{
if (&other != this) {
Unsubscribe();
event_ = BASE_NS::move(other.event_);
token_ = BASE_NS::exchange(other.token_, {});
}
return *this;
}
template
EventHandler(const Event& event, const typename EventType::InterfaceTypePtr& func,
const ITaskQueue::Ptr& queue = nullptr)
{
Subscribe(event, func, queue);
}
template
EventHandler(
const Event& event, const typename EventType::InterfaceTypePtr& func, const BASE_NS::Uid& queueId)
{
Subscribe(event, func, queueId);
}
EventHandler(const BASE_NS::shared_ptr& event, const ICallable::Ptr& func)
{
TypelessSubscribe(event, func);
}
template>
EventHandler(const Event& event, Func func, const ITaskQueue::Ptr& queue = nullptr)
{
Subscribe(event, BASE_NS::move(func), queue);
}
template>
EventHandler(
const Event& event, const typename EventType::InterfaceTypePtr& func, const BASE_NS::Uid& queueId)
{
Subscribe(event, BASE_NS::move(func), queueId);
}
/**
* @brief Check if this handler has subscribed to an event
*/
bool IsValid() const
{
return !event_.expired();
}
/**
* @brief Subscribe to an event.
* @param event Event to subscribe to.
* @param func Callable to invoke when event is triggered.
* @return True if the successfully subscribed.
*/
bool TypelessSubscribe(const IEvent::Ptr& event, const ICallable::Ptr& func)
{
if (!event) {
CORE_LOG_E("Cannot subscribe to null event");
return false;
}
Unsubscribe();
token_ = event->AddHandler(func);
if (token_) {
event_ = event;
}
return token_;
}
/**
* @brief Subscribe to an event.
* @param event Event to subscribe to.
* @param func Callable to invoke when event is triggered.
* @oaram queue Optional queue where 'func' is invoked, if null, invoked directly.
* @return True if the successfully subscribed.
*/
template
bool Subscribe(const Event& event, const typename EventType::InterfaceTypePtr& func,
const ITaskQueue::Ptr& queue = nullptr)
{
return queue ? TypelessSubscribe(event,
MakeDeferred(
[func](auto&&... args) { func->Invoke(BASE_NS::forward(args)...); },
queue))
: TypelessSubscribe(event, func);
}
/**
* @brief Subscribe to an event.
* @param event Event to subscribe to.
* @param func Callable to invoke when event is triggered.
* @param queueId Queue id where 'func' is invoked. Fails if no such queue exists.
* @return True if the successfully subscribed.
*/
template
bool Subscribe(
const Event& event, const typename EventType::InterfaceTypePtr& func, const BASE_NS::Uid& queueId)
{
auto queue = GetTaskQueueRegistry().GetTaskQueue(queueId);
if (!queue) {
CORE_LOG_E("Cannot initialize event handler for queue %s: Queue not registered.",
BASE_NS::to_string(queueId).c_str());
}
return queue && Subscribe(event, func, queue);
}
/**
* @brief Subscribe to an event. See above Subscribe function for parameters
*/
template>
bool Subscribe(const Event& event, Func func, const ITaskQueue::Ptr& queue = nullptr)
{
return Subscribe(event, MakeCallback(BASE_NS::move(func)), queue);
}
/**
* @brief Subscribe to an event. See above Subscribe function for parameters
*/
template>
bool Subscribe(const Event& event, Func func, const BASE_NS::Uid& queueId)
{
return Subscribe(event, MakeCallback(BASE_NS::move(func)), queueId);
}
/**
* @brief Subscribe to an event. See above Subscribe function for parameters
*/
template>
bool Subscribe(const BASE_NS::shared_ptr& event, Func func, const ITaskQueue::Ptr& queue = nullptr)
{
auto ev = interface_pointer_cast(event);
return ev && Subscribe(event, MakeCallback(BASE_NS::move(func)), queue);
}
/**
* @brief Subscribe to an event. See above Subscribe function for parameters
*/
template>
bool Subscribe(const BASE_NS::shared_ptr& event, Func func, const BASE_NS::Uid& queueId)
{
auto ev = interface_pointer_cast(event);
return ev && Subscribe(event, MakeCallback(BASE_NS::move(func)), queueId);
}
/**
* @brief Unsubscribe from the event.
*/
void Unsubscribe()
{
if (auto e = event_.lock()) {
e->RemoveHandler(token_);
event_ = nullptr;
token_ = {};
}
}
protected:
IEvent::WeakPtr event_;
IEvent::Token token_ {};
};
META_END_NAMESPACE()
#endif