2020-10-01 14:20:55 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <cstdint>
|
|
|
|
#include <tuple>
|
2020-10-04 16:30:13 +02:00
|
|
|
#include <variant>
|
2020-10-01 14:20:55 +02:00
|
|
|
|
|
|
|
#include "common.h"
|
|
|
|
|
|
|
|
#include "string_literal.h"
|
|
|
|
|
|
|
|
namespace gin {
|
|
|
|
class Message {
|
|
|
|
protected:
|
|
|
|
bool set_explicitly = false;
|
|
|
|
|
|
|
|
public:
|
|
|
|
template <typename T> T &as() {
|
|
|
|
static_assert(std::is_base_of<Message, T>());
|
|
|
|
return reinterpret_cast<T &>(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T> const T &as() const {
|
|
|
|
static_assert(std::is_base_of<Message, T>());
|
|
|
|
return reinterpret_cast<const T &>(*this);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
/*
|
|
|
|
* Representing all primitive types
|
|
|
|
*/
|
|
|
|
template <typename T> class MessagePrimitive : public Message {
|
|
|
|
private:
|
|
|
|
T value;
|
|
|
|
|
|
|
|
friend class Builder;
|
|
|
|
friend class Reader;
|
|
|
|
|
|
|
|
public:
|
|
|
|
MessagePrimitive() = default;
|
|
|
|
|
|
|
|
class Reader;
|
|
|
|
class Builder {
|
|
|
|
private:
|
|
|
|
MessagePrimitive<T> &message;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Builder(MessagePrimitive<T> &message) : message{message} {}
|
|
|
|
|
|
|
|
constexpr void set(const T &value) {
|
|
|
|
message.value = value;
|
|
|
|
message.set_explicitly = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Reader asReader() { return Reader{message}; }
|
|
|
|
};
|
|
|
|
|
|
|
|
class Reader {
|
|
|
|
private:
|
|
|
|
MessagePrimitive<T> &message;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Reader(MessagePrimitive<T> &message) : message{message} {}
|
|
|
|
|
2020-10-04 16:30:13 +02:00
|
|
|
const T &get() const { return message.value; }
|
2020-10-01 14:20:55 +02:00
|
|
|
|
|
|
|
bool isSetExplicitly() const { return message.set_explicitly; }
|
|
|
|
|
|
|
|
Builder asBuilder() { return Builder{message}; }
|
|
|
|
};
|
|
|
|
};
|
|
|
|
template <> class MessagePrimitive<std::string> : public Message {
|
|
|
|
private:
|
|
|
|
std::string value;
|
|
|
|
|
|
|
|
friend class Builder;
|
|
|
|
friend class Reader;
|
|
|
|
|
|
|
|
public:
|
|
|
|
MessagePrimitive() = default;
|
|
|
|
|
|
|
|
class Reader;
|
|
|
|
class Builder {
|
|
|
|
private:
|
|
|
|
MessagePrimitive<std::string> &message;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Builder(MessagePrimitive<std::string> &message) : message{message} {}
|
|
|
|
|
2020-10-04 16:30:13 +02:00
|
|
|
void set(std::string_view value) {
|
|
|
|
message.value = std::string{value};
|
|
|
|
message.set_explicitly = true;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
void set(std::string &&value) {
|
|
|
|
message.value = std::move(value);
|
2020-10-01 14:20:55 +02:00
|
|
|
message.set_explicitly = true;
|
|
|
|
}
|
2020-10-04 16:30:13 +02:00
|
|
|
*/
|
2020-10-01 14:20:55 +02:00
|
|
|
|
|
|
|
Reader asReader() { return Reader{message}; }
|
|
|
|
};
|
|
|
|
|
|
|
|
class Reader {
|
|
|
|
private:
|
|
|
|
MessagePrimitive<std::string> &message;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Reader(MessagePrimitive<std::string> &message) : message{message} {}
|
|
|
|
|
2020-10-04 16:30:13 +02:00
|
|
|
std::string_view get() const { return std::string_view{message.value}; }
|
2020-10-01 14:20:55 +02:00
|
|
|
|
|
|
|
bool isSetExplicitly() const { return message.set_explicitly; }
|
|
|
|
|
|
|
|
Builder asBuilder() { return Builder{message}; }
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename... Args> class MessageList : public Message {
|
|
|
|
private:
|
|
|
|
using tuple_type = std::tuple<Args...>;
|
|
|
|
tuple_type elements;
|
|
|
|
friend class Builder;
|
|
|
|
friend class Reader;
|
|
|
|
|
|
|
|
public:
|
|
|
|
class Reader;
|
|
|
|
class Builder {
|
|
|
|
private:
|
|
|
|
MessageList<Args...> &message;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Builder(MessageList<Args...> &message) : message{message} {
|
|
|
|
message.set_explicitly = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <size_t i>
|
|
|
|
constexpr typename std::tuple_element_t<i, tuple_type>::Builder init() {
|
|
|
|
std::tuple_element_t<i, tuple_type> &msg_ref =
|
|
|
|
std::get<i>(message.elements);
|
|
|
|
return
|
|
|
|
typename std::tuple_element_t<i, tuple_type>::Builder{msg_ref};
|
|
|
|
}
|
|
|
|
|
|
|
|
Reader asReader() { return Reader{message}; }
|
|
|
|
};
|
|
|
|
|
|
|
|
class Reader {
|
|
|
|
private:
|
|
|
|
MessageList<Args...> &message;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Reader(MessageList<Args...> &message) : message{message} {}
|
|
|
|
|
|
|
|
template <size_t i>
|
|
|
|
constexpr typename std::tuple_element_t<i, tuple_type>::Reader get() {
|
|
|
|
return std::get<i>(message.elements);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t size() const { return std::tuple_size<tuple_type>::value; }
|
|
|
|
|
|
|
|
bool isSetExplicitly() const { return message.set_explicitly; }
|
|
|
|
|
|
|
|
Builder asBuilder() { return Reader{message}; }
|
|
|
|
};
|
|
|
|
};
|
|
|
|
template <typename T, typename K> struct MessageStructMember;
|
|
|
|
|
|
|
|
template <typename T, typename C, C... Chars>
|
|
|
|
struct MessageStructMember<T, StringLiteral<C, Chars...>> {
|
|
|
|
T value;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Helper structs which retrieve
|
|
|
|
* the index of a parameter pack based on the index
|
|
|
|
* or
|
|
|
|
* a type based on the index
|
|
|
|
* Pass N as the index for the desired type
|
|
|
|
* or
|
|
|
|
* a type to get the first occurence of a type index
|
|
|
|
*/
|
|
|
|
template <size_t N, typename... T> struct ParameterPackType;
|
|
|
|
|
|
|
|
template <typename T, typename... TL> struct ParameterPackType<0, T, TL...> {
|
|
|
|
using type = T;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <size_t N, typename T, typename... TL>
|
|
|
|
struct ParameterPackType<N, T, TL...> {
|
|
|
|
using type = typename ParameterPackType<N - 1, TL...>::type;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T, typename... TL> struct ParameterPackIndex;
|
|
|
|
|
2020-10-06 04:12:24 +02:00
|
|
|
template <typename T, typename... TL> struct ParameterPackIndex<T, T, TL...> {
|
|
|
|
static constexpr size_t value = 0u;
|
|
|
|
};
|
|
|
|
|
2020-10-01 14:20:55 +02:00
|
|
|
template <typename T, typename TL0, typename... TL>
|
|
|
|
struct ParameterPackIndex<T, TL0, TL...> {
|
|
|
|
static constexpr size_t value = 1u + ParameterPackIndex<T, TL...>::value;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename... T> class MessageStruct;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Since no value is retrieved from the keys, I only need a value tuple
|
|
|
|
*/
|
|
|
|
template <typename... V, typename... K>
|
|
|
|
class MessageStruct<MessageStructMember<V, K>...> : public Message {
|
|
|
|
private:
|
|
|
|
using value_type = std::tuple<V...>;
|
|
|
|
value_type values;
|
|
|
|
friend class Builder;
|
|
|
|
friend class Reader;
|
|
|
|
|
|
|
|
public:
|
|
|
|
class Reader;
|
|
|
|
class Builder {
|
|
|
|
private:
|
|
|
|
MessageStruct<MessageStructMember<V, K>...> &message;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Builder(MessageStruct<MessageStructMember<V, K>...> &message)
|
|
|
|
: message{message} {
|
|
|
|
message.set_explicitly = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <size_t i>
|
|
|
|
constexpr typename std::tuple_element_t<i, value_type>::Builder init() {
|
|
|
|
std::tuple_element_t<i, value_type> &msg_ref =
|
|
|
|
std::get<i>(message.values);
|
|
|
|
return
|
|
|
|
typename std::tuple_element_t<i, value_type>::Builder{msg_ref};
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
constexpr
|
|
|
|
typename std::tuple_element_t<ParameterPackIndex<T, K...>::value,
|
|
|
|
value_type>::Builder
|
|
|
|
init() {
|
|
|
|
std::tuple_element_t<ParameterPackIndex<T, K...>::value, value_type>
|
|
|
|
&msg_ref = std::get<ParameterPackIndex<T, K...>::value>(
|
|
|
|
message.values);
|
|
|
|
return typename std::tuple_element_t<
|
|
|
|
ParameterPackIndex<T, K...>::value, value_type>::Builder{
|
|
|
|
msg_ref};
|
|
|
|
}
|
|
|
|
|
|
|
|
Reader asReader() { return Reader{message}; }
|
|
|
|
};
|
|
|
|
class Reader {
|
|
|
|
private:
|
|
|
|
MessageStruct<MessageStructMember<V, K>...> &message;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Reader(MessageStruct<MessageStructMember<V, K>...> &message)
|
|
|
|
: message{message} {}
|
|
|
|
|
|
|
|
template <size_t i>
|
|
|
|
constexpr typename std::tuple_element_t<i, value_type>::Reader get() {
|
|
|
|
std::tuple_element_t<i, value_type> &msg_ref =
|
|
|
|
std::get<i>(message.values);
|
|
|
|
return
|
|
|
|
typename std::tuple_element_t<i, value_type>::Reader{msg_ref};
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
constexpr
|
|
|
|
typename std::tuple_element_t<ParameterPackIndex<T, K...>::value,
|
|
|
|
value_type>::Reader
|
|
|
|
get() {
|
|
|
|
std::tuple_element_t<ParameterPackIndex<T, K...>::value, value_type>
|
|
|
|
&msg_ref = std::get<ParameterPackIndex<T, K...>::value>(
|
|
|
|
message.values);
|
|
|
|
return typename std::tuple_element_t<
|
|
|
|
ParameterPackIndex<T, K...>::value, value_type>::Reader{
|
|
|
|
msg_ref};
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr size_t size() { return std::tuple_size<value_type>::value; }
|
|
|
|
|
|
|
|
Builder asBuilder() { return Builder{message}; }
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2020-10-04 16:30:13 +02:00
|
|
|
template <typename T, typename K> struct MessageUnionMember;
|
|
|
|
|
|
|
|
template <typename T, typename C, C... Chars>
|
|
|
|
struct MessageUnionMember<T, StringLiteral<C, Chars...>> {
|
|
|
|
T value;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename... T> class MessageUnion;
|
|
|
|
|
|
|
|
/// @todo copied from MessageStruct, but the acces is different, since
|
|
|
|
/// only one value can be set at the same time.
|
|
|
|
template <typename... V, typename... K>
|
2020-10-06 01:47:57 +02:00
|
|
|
class MessageUnion<MessageUnionMember<V, K>...> : public Message {
|
2020-10-04 16:30:13 +02:00
|
|
|
private:
|
2020-10-06 20:43:56 +02:00
|
|
|
using value_type = std::variant<MessageUnionMember<V, K>...>;
|
2020-10-04 16:30:13 +02:00
|
|
|
value_type values;
|
|
|
|
friend class Builder;
|
|
|
|
friend class Reader;
|
|
|
|
|
|
|
|
public:
|
|
|
|
class Reader;
|
|
|
|
class Builder {
|
|
|
|
private:
|
2020-10-06 01:47:57 +02:00
|
|
|
MessageUnion<MessageUnionMember<V, K>...> &message;
|
2020-10-04 16:30:13 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
Builder(MessageUnion<MessageUnionMember<V, K>...> &message)
|
|
|
|
: message{message} {
|
|
|
|
message.set_explicitly = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <size_t i>
|
2020-10-06 20:43:56 +02:00
|
|
|
constexpr typename ParameterPackType<i, V...>::type::Builder init() {
|
|
|
|
message.values =
|
|
|
|
typename std::variant_alternative_t<i, value_type>{};
|
2020-10-06 04:12:24 +02:00
|
|
|
typename ParameterPackType<i, V...>::type &msg_ref =
|
|
|
|
std::get<i>(message.values).value;
|
2020-10-06 20:43:56 +02:00
|
|
|
return typename ParameterPackType<i, V...>::type::Builder{msg_ref};
|
2020-10-04 16:30:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2020-10-06 20:43:56 +02:00
|
|
|
constexpr typename ParameterPackType<ParameterPackIndex<T, K...>::value,
|
|
|
|
V...>::type::Builder
|
2020-10-04 16:30:13 +02:00
|
|
|
init() {
|
2020-10-06 20:43:56 +02:00
|
|
|
message.values = typename std::variant_alternative_t<
|
|
|
|
ParameterPackIndex<T, K...>::value, value_type>{};
|
|
|
|
typename ParameterPackType<ParameterPackIndex<T, K...>::value,
|
|
|
|
V...>::type &msg_ref =
|
|
|
|
std::get<ParameterPackIndex<T, K...>::value>(message.values)
|
|
|
|
.value;
|
|
|
|
return
|
|
|
|
typename ParameterPackType<ParameterPackIndex<T, K...>::value,
|
|
|
|
V...>::type::Builder{msg_ref};
|
2020-10-04 16:30:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Reader asReader() { return Reader{message}; }
|
|
|
|
};
|
|
|
|
class Reader {
|
|
|
|
private:
|
2020-10-06 01:47:57 +02:00
|
|
|
MessageUnion<MessageUnionMember<V, K>...> &message;
|
2020-10-04 16:30:13 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
Reader(MessageUnion<MessageUnionMember<V, K>...> &message)
|
|
|
|
: message{message} {}
|
|
|
|
|
|
|
|
template <size_t i>
|
2020-10-06 20:43:56 +02:00
|
|
|
constexpr typename ParameterPackType<i, V...>::type::Reader get() {
|
2020-10-06 04:12:24 +02:00
|
|
|
typename ParameterPackType<i, V...>::type &msg_ref =
|
|
|
|
std::get<i>(message.values).value;
|
2020-10-06 20:43:56 +02:00
|
|
|
return typename ParameterPackType<i, V...>::type::Reader{msg_ref};
|
2020-10-04 16:30:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2020-10-06 20:43:56 +02:00
|
|
|
constexpr typename ParameterPackType<ParameterPackIndex<T, K...>::value,
|
|
|
|
V...>::type::Reader
|
2020-10-04 16:30:13 +02:00
|
|
|
get() {
|
2020-10-06 20:43:56 +02:00
|
|
|
typename ParameterPackType<ParameterPackIndex<T, K...>::value,
|
|
|
|
V...>::type &msg_ref =
|
|
|
|
std::get<ParameterPackIndex<T, K...>::value>(message.values)
|
|
|
|
.value;
|
|
|
|
return
|
|
|
|
typename ParameterPackType<ParameterPackIndex<T, K...>::value,
|
|
|
|
V...>::type::Reader{msg_ref};
|
2020-10-04 16:30:13 +02:00
|
|
|
}
|
|
|
|
|
2020-10-06 01:47:57 +02:00
|
|
|
template <typename T> constexpr bool holdsAlternative() {
|
2020-10-06 20:43:56 +02:00
|
|
|
return std::holds_alternative<std::variant_alternative_t<
|
|
|
|
ParameterPackIndex<T, K...>::value, value_type>>(
|
|
|
|
message.values);
|
2020-10-06 01:47:57 +02:00
|
|
|
}
|
|
|
|
|
2020-10-22 18:38:56 +02:00
|
|
|
size_t index() const { return message.values.index(); }
|
2020-10-13 16:53:57 +02:00
|
|
|
|
2020-10-04 16:30:13 +02:00
|
|
|
constexpr size_t size() { return std::variant_size<value_type>::value; }
|
|
|
|
|
|
|
|
Builder asBuilder() { return Builder{message}; }
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2020-10-01 14:20:55 +02:00
|
|
|
class MessageReader {
|
|
|
|
public:
|
|
|
|
virtual ~MessageReader() = default;
|
|
|
|
};
|
|
|
|
|
|
|
|
class MessageBuilder {
|
|
|
|
private:
|
|
|
|
Own<Message> root_message = nullptr;
|
|
|
|
|
|
|
|
public:
|
|
|
|
virtual ~MessageBuilder() = default;
|
|
|
|
|
|
|
|
template <typename MessageRoot> typename MessageRoot::Builder initRoot() {
|
|
|
|
root_message = std::make_unique<MessageRoot>();
|
|
|
|
MessageRoot &msg_ref = root_message->as<MessageRoot>();
|
|
|
|
return typename MessageRoot::Builder{msg_ref};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
inline MessageBuilder heapMessageBuilder() { return MessageBuilder{}; }
|
|
|
|
} // namespace gin
|