Program Listing for File data.hpp
↰ Return to documentation for file (eshet/data.hpp)
#pragma once
#include "actorpp/actor.hpp"
#include "eshet/msgpack_to_string.hpp"
#include "msgpack.hpp"
#include <functional>
#include <variant>
namespace eshet {
using namespace actorpp;
using Time = std::chrono::duration<uint32_t, std::milli>;
template <typename T> msgpack::object_handle oh_with_zone(const T &value) {
std::unique_ptr<msgpack::zone> z = std::make_unique<msgpack::zone>();
return msgpack::object_handle(msgpack::object(value, *z), std::move(z));
}
template <typename Base> struct HasMsgpackObject {
msgpack::object_handle value;
explicit HasMsgpackObject(msgpack::object_handle value)
: value(std::move(value)) {}
explicit HasMsgpackObject() {}
template <typename T> explicit HasMsgpackObject(T t) {
value.set(msgpack::object(std::move(t)));
}
template <typename T> T as() const {
T v;
value.get().convert(v);
return v;
}
template <typename T> void convert(T &v) const { value.get().convert(v); }
template <typename... Ts> void convert(std::tuple<Ts &...> v) const {
value.get().convert(v);
}
bool operator==(const HasMsgpackObject<Base> &other) const {
return value.get() == other.value.get();
}
bool operator!=(const HasMsgpackObject<Base> &other) const {
return !(*this == other);
}
};
struct Success : public HasMsgpackObject<Success> {
using HasMsgpackObject<Success>::HasMsgpackObject;
static constexpr const char *name = "Success";
};
// Error is usable as an exception, so needs to be copyable
struct Error : public HasMsgpackObject<Error>, public std::exception {
using HasMsgpackObject<Error>::HasMsgpackObject;
static constexpr const char *name = "Error";
Error(const Error &other)
: HasMsgpackObject<Error>(msgpack::clone(other.value.get())) {}
Error(Error &&) = default;
Error &operator=(Error &&) = default;
const char *what() const throw() {
if (!error_str.size()) {
error_str += "Error(";
append_msgpack(error_str, value.get());
error_str += ")";
}
return error_str.c_str();
}
private:
mutable std::string error_str;
};
using Result = std::variant<Success, Error>;
struct Known : public HasMsgpackObject<Known> {
explicit Known() : HasMsgpackObject<Known>(), t_since_change(0) {}
template <typename T>
explicit Known(T &&v, Time t = Time{0})
: HasMsgpackObject<Known>(std::forward<T>(v)), t_since_change(t) {}
static constexpr const char *name = "Known";
Time t_since_change;
};
struct Unknown {
explicit Unknown(Time t = Time{0}) : t_since_change(t) {}
bool operator==(const Unknown &other) const { return true; }
bool operator!=(const Unknown &other) const { return !(*this == other); }
Time t_since_change;
};
using StateResult = std::variant<Known, Unknown, Error>;
using StateUpdate = std::variant<Known, Unknown>;
using AnyResult = std::variant<Success, Known, Unknown, Error>;
struct Call : public HasMsgpackObject<Call> {
static constexpr const char *name = "Call";
uint16_t connection_id;
uint16_t id;
explicit Call(uint16_t connection_id, uint16_t id,
msgpack::object_handle args,
Channel<std::tuple<uint16_t, uint16_t, Result>> reply_chan)
: HasMsgpackObject<Call>(std::move(args)), connection_id(connection_id),
id(id), reply_chan(reply_chan) {}
void reply(Result r) { reply_chan.emplace(connection_id, id, std::move(r)); }
Channel<std::tuple<uint16_t, uint16_t, Result>> reply_chan;
};
// make these printable
template <typename Base>
std::ostream &operator<<(std::ostream &stream,
const HasMsgpackObject<Base> &value) {
return stream << Base::name << "(" << value.value.get() << ")";
}
std::ostream &operator<<(std::ostream &stream, const Unknown &unknown) {
return stream << "unknown";
}
template <typename T,
typename = std::enable_if_t<std::is_same<T, Result>::value ||
std::is_same<T, StateResult>::value ||
std::is_same<T, StateUpdate>::value ||
std::is_same<T, AnyResult>::value>>
std::ostream &operator<<(std::ostream &stream, const T &result) {
std::visit([&](const auto &v) { stream << v; }, result);
return stream;
}
struct Disconnected : public std::exception {
const char *what() const throw() { return "Disconnected"; }
};
struct ProtocolError : public std::exception {
const char *what() const throw() { return "ProtocolError"; }
};
} // namespace eshet