248 lines
6.1 KiB
C++
248 lines
6.1 KiB
C++
//
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
|
|
//
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
//
|
|
#pragma once
|
|
|
|
#include "td/utils/Closure.h"
|
|
#include "td/utils/common.h"
|
|
#include "td/utils/StringBuilder.h"
|
|
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
namespace td {
|
|
|
|
class Actor;
|
|
|
|
// Events
|
|
//
|
|
// Small structure (up to 16 bytes) used to send events between actors.
|
|
//
|
|
// There are some predefined types of events:
|
|
// NoType -- unitialized event
|
|
// Start -- start actor
|
|
// Stop -- stop actor
|
|
// Yield -- wake up actor
|
|
// Timeout -- some timeout has expired
|
|
// Hangup -- hang up called
|
|
// Raw -- just pass 8 bytes (union Raw is used for convenience)
|
|
// Custom -- Send CustomEvent
|
|
|
|
template <class T>
|
|
std::enable_if_t<!std::is_base_of<Actor, T>::value> start_migrate(T &obj, int32 sched_id) {
|
|
}
|
|
template <class T>
|
|
std::enable_if_t<!std::is_base_of<Actor, T>::value> finish_migrate(T &obj) {
|
|
}
|
|
|
|
class CustomEvent {
|
|
public:
|
|
CustomEvent() = default;
|
|
CustomEvent(const CustomEvent &) = delete;
|
|
CustomEvent &operator=(const CustomEvent &) = delete;
|
|
CustomEvent(CustomEvent &&) = delete;
|
|
CustomEvent &operator=(CustomEvent &&) = delete;
|
|
virtual ~CustomEvent() = default;
|
|
|
|
virtual void run(Actor *actor) = 0;
|
|
virtual void start_migrate(int32 sched_id) {
|
|
}
|
|
virtual void finish_migrate() {
|
|
}
|
|
};
|
|
|
|
template <class ClosureT>
|
|
class ClosureEvent final : public CustomEvent {
|
|
public:
|
|
void run(Actor *actor) final {
|
|
closure_.run(static_cast<typename ClosureT::ActorType *>(actor));
|
|
}
|
|
template <class... ArgsT>
|
|
explicit ClosureEvent(ArgsT &&...args) : closure_(std::forward<ArgsT>(args)...) {
|
|
}
|
|
|
|
void start_migrate(int32 sched_id) final {
|
|
closure_.for_each([sched_id](auto &obj) {
|
|
using ::td::start_migrate;
|
|
start_migrate(obj, sched_id);
|
|
});
|
|
}
|
|
|
|
void finish_migrate() final {
|
|
closure_.for_each([](auto &obj) {
|
|
using ::td::finish_migrate;
|
|
finish_migrate(obj);
|
|
});
|
|
}
|
|
|
|
private:
|
|
ClosureT closure_;
|
|
};
|
|
|
|
template <class LambdaT>
|
|
class LambdaEvent final : public CustomEvent {
|
|
public:
|
|
void run(Actor *actor) final {
|
|
f_();
|
|
}
|
|
template <class FromLambdaT, std::enable_if_t<!std::is_same<std::decay_t<FromLambdaT>, LambdaEvent>::value, int> = 0>
|
|
explicit LambdaEvent(FromLambdaT &&lambda) : f_(std::forward<FromLambdaT>(lambda)) {
|
|
}
|
|
|
|
private:
|
|
LambdaT f_;
|
|
};
|
|
|
|
class Event {
|
|
public:
|
|
enum class Type { NoType, Start, Stop, Yield, Timeout, Hangup, Raw, Custom };
|
|
Type type;
|
|
uint64 link_token = 0;
|
|
union Raw {
|
|
void *ptr;
|
|
CustomEvent *custom_event;
|
|
uint32 u32;
|
|
uint64 u64;
|
|
} data{};
|
|
|
|
// factory functions
|
|
static Event start() {
|
|
return Event(Type::Start);
|
|
}
|
|
static Event stop() {
|
|
return Event(Type::Stop);
|
|
}
|
|
static Event yield() {
|
|
return Event(Type::Yield);
|
|
}
|
|
static Event timeout() {
|
|
return Event(Type::Timeout);
|
|
}
|
|
static Event hangup() {
|
|
return Event(Type::Hangup);
|
|
}
|
|
static Event raw(void *ptr) {
|
|
return Event(Type::Raw, ptr);
|
|
}
|
|
static Event raw(uint32 u32) {
|
|
return Event(Type::Raw, u32);
|
|
}
|
|
static Event raw(uint64 u64) {
|
|
return Event(Type::Raw, u64);
|
|
}
|
|
static Event custom(CustomEvent *custom_event) {
|
|
return Event(Type::Custom, custom_event);
|
|
}
|
|
|
|
template <class FromImmediateClosureT>
|
|
static Event immediate_closure(FromImmediateClosureT &&closure) {
|
|
return custom(
|
|
new ClosureEvent<typename FromImmediateClosureT::Delayed>(std::forward<FromImmediateClosureT>(closure)));
|
|
}
|
|
template <class... ArgsT>
|
|
static Event delayed_closure(ArgsT &&...args) {
|
|
using DelayedClosureT = decltype(create_delayed_closure(std::forward<ArgsT>(args)...));
|
|
return custom(new ClosureEvent<DelayedClosureT>(std::forward<ArgsT>(args)...));
|
|
}
|
|
|
|
template <class FromLambdaT>
|
|
static Event lambda(FromLambdaT &&lambda) {
|
|
return custom(new LambdaEvent<std::decay_t<FromLambdaT>>(std::forward<FromLambdaT>(lambda)));
|
|
}
|
|
|
|
Event() : Event(Type::NoType) {
|
|
}
|
|
Event(const Event &) = delete;
|
|
Event &operator=(const Event &) = delete;
|
|
Event(Event &&other) noexcept : type(other.type), link_token(other.link_token), data(other.data) {
|
|
other.type = Type::NoType;
|
|
}
|
|
Event &operator=(Event &&other) noexcept {
|
|
destroy();
|
|
type = other.type;
|
|
link_token = other.link_token;
|
|
data = other.data;
|
|
other.type = Type::NoType;
|
|
return *this;
|
|
}
|
|
~Event() {
|
|
destroy();
|
|
}
|
|
|
|
bool empty() const {
|
|
return type == Type::NoType;
|
|
}
|
|
|
|
void clear() {
|
|
destroy();
|
|
type = Type::NoType;
|
|
}
|
|
|
|
Event &set_link_token(uint64 new_link_token) {
|
|
link_token = new_link_token;
|
|
return *this;
|
|
}
|
|
|
|
friend void start_migrate(Event &obj, int32 sched_id) {
|
|
if (obj.type == Type::Custom) {
|
|
obj.data.custom_event->start_migrate(sched_id);
|
|
}
|
|
}
|
|
friend void finish_migrate(Event &obj) {
|
|
if (obj.type == Type::Custom) {
|
|
obj.data.custom_event->finish_migrate();
|
|
}
|
|
}
|
|
|
|
private:
|
|
explicit Event(Type type) : type(type) {
|
|
}
|
|
|
|
Event(Type type, void *ptr) : Event(type) {
|
|
data.ptr = ptr;
|
|
}
|
|
Event(Type type, CustomEvent *custom_event) : Event(type) {
|
|
data.custom_event = custom_event;
|
|
}
|
|
Event(Type type, uint32 u32) : Event(type) {
|
|
data.u32 = u32;
|
|
}
|
|
Event(Type type, uint64 u64) : Event(type) {
|
|
data.u64 = u64;
|
|
}
|
|
|
|
void destroy() {
|
|
if (type == Type::Custom) {
|
|
delete data.custom_event;
|
|
}
|
|
}
|
|
};
|
|
|
|
inline StringBuilder &operator<<(StringBuilder &string_builder, const Event &e) {
|
|
string_builder << "Event::";
|
|
switch (e.type) {
|
|
case Event::Type::Start:
|
|
return string_builder << "Start";
|
|
case Event::Type::Stop:
|
|
return string_builder << "Stop";
|
|
case Event::Type::Yield:
|
|
return string_builder << "Yield";
|
|
case Event::Type::Hangup:
|
|
return string_builder << "Hangup";
|
|
case Event::Type::Timeout:
|
|
return string_builder << "Timeout";
|
|
case Event::Type::Raw:
|
|
return string_builder << "Raw";
|
|
case Event::Type::Custom:
|
|
return string_builder << "Custom";
|
|
case Event::Type::NoType:
|
|
default:
|
|
return string_builder << "NoType";
|
|
}
|
|
}
|
|
|
|
} // namespace td
|