Merge branch 'fb-schema' into dev

This commit is contained in:
Claudius Holeksa 2021-12-25 13:57:45 +01:00
commit 7192a8a5b6
14 changed files with 962 additions and 2345 deletions

View File

@ -112,9 +112,6 @@ SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 4
UseTab: ForContinuationAndIndentation
...

View File

@ -29,10 +29,10 @@ def add_kel_source_files(self, sources, filetype, lib_env=None, shared=False, ta
sources.append( self.StaticObject( target=target_name, source=path ) )
pass
env=Environment(CPPPATH=['#source/kelgin','#source','#','#driver'],
env=Environment(ENV=os.environ, CPPPATH=['#source/kelgin','#source','#','#driver'],
CXX='clang++',
CPPDEFINES=['GIN_UNIX'],
CXXFLAGS=['-std=c++17','-g','-Wall','-Wextra'],
CXXFLAGS=['-std=c++20','-g','-Wall','-Wextra'],
LIBS=['gnutls'])
env.__class__.add_source_files = add_kel_source_files

File diff suppressed because it is too large Load Diff

View File

@ -2,457 +2,440 @@
#include <cstdint>
#include <tuple>
#include <type_traits>
#include <variant>
#include <vector>
#include <cassert>
#include "common.h"
#include "message_container.h"
#include "schema.h"
#include "string_literal.h"
namespace gin {
class Message {
class MessageBase {
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 <class T> T &as() {
static_assert(std::is_base_of<MessageBase, T>());
return dynamic_cast<T &>(*this);
}
template <typename T> const T &as() const {
static_assert(std::is_base_of<Message, T>());
return reinterpret_cast<const T &>(*this);
template <class T> const T &as() const {
static_assert(std::is_base_of<MessageBase, T>());
return dynamic_cast<const T &>(*this);
}
};
/*
* Representing all primitive types
* Representing all message types
* Description which type to use happens through the use of the schema classes
* in schema.h The message classes are wrapper classes which store the data
* according to the specified container class.
*
* The reader and builder classe exist to create some clarity while implementing
* parsers. Also minor guarantess are provided if the message is used as a
* template parameter.
*/
template <typename T> class MessagePrimitive : public Message {
/*
* Struct Message
*/
template <class... V, StringLiteral... Keys, class Container>
class Message<schema::Struct<schema::NamedMember<V, Keys>...>, Container> final
: public MessageBase {
private:
T value;
using SchemaType = schema::Struct<schema::NamedMember<V, Keys>...>;
using MessageType = Message<SchemaType, Container>;
Container container;
static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>,
"Container should have same the schema as Message");
friend class Builder;
friend class Reader;
public:
MessagePrimitive() = default;
class Reader;
class Builder {
private:
MessagePrimitive<T> &message;
MessageType &message;
public:
Builder(MessagePrimitive<T> &message) : message{message} {}
constexpr void set(const T &value) {
message.value = value;
message.set_explicitly = true;
}
Builder(MessageType &msg) : message{msg} {}
Reader asReader() { return Reader{message}; }
};
class Reader {
private:
MessagePrimitive<T> &message;
public:
Reader(MessagePrimitive<T> &message) : message{message} {}
const T &get() const { return message.value; }
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} {}
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);
message.set_explicitly = true;
}
*/
Reader asReader() { return Reader{message}; }
};
class Reader {
private:
MessagePrimitive<std::string> &message;
public:
Reader(MessagePrimitive<std::string> &message) : message{message} {}
std::string_view get() const { return std::string_view{message.value}; }
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;
}
* Initialize a member by index
*/
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};
typename Container::template ElementType<i>::Builder init() {
return typename Container::template ElementType<i>::Builder{
message.container.template get<i>()};
}
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 Builder{message}; }
};
};
/// @todo how to do initialization?
template <typename T> class MessageArray : public Message {
private:
using array_type = std::vector<T>;
array_type elements;
friend class Builder;
friend class Reader;
public:
class Reader;
class Builder {
private:
MessageArray<T> &message;
public:
Builder(MessageArray<T> &message) : message{message} {
message.set_explicitly = true;
}
constexpr typename T::Builder init(size_t i) {
T &msg_ref = message.elements.at(i);
return typename T::Builder{msg_ref};
}
Reader asReader() { return Reader{message}; }
};
class Reader {
private:
MessageArray<T> &message;
public:
Reader(MessageArray<T> &message) : message{message} {}
constexpr typename T::Reader get(size_t i) {
return message.elements.at(i);
}
size_t size() const { return message.elements.size(); }
bool isSetExplicitly() const { return message.set_explicitly; }
Builder asBuilder() { return Builder{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;
template <typename T, typename... TL> struct ParameterPackIndex<T, T, TL...> {
static constexpr size_t value = 0u;
};
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; }
bool isSetExplicitly() const { return message.set_explicitly; }
Builder asBuilder() { return Builder{message}; }
};
};
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>
class MessageUnion<MessageUnionMember<V, K>...> : public Message {
private:
using value_type = std::variant<MessageUnionMember<V, K>...>;
value_type values;
friend class Builder;
friend class Reader;
public:
class Reader;
class Builder {
private:
MessageUnion<MessageUnionMember<V, K>...> &message;
public:
Builder(MessageUnion<MessageUnionMember<V, K>...> &message)
: message{message} {
message.set_explicitly = true;
}
template <size_t i>
constexpr typename ParameterPackType<i, V...>::type::Builder init() {
message.values =
typename std::variant_alternative_t<i, value_type>{};
typename ParameterPackType<i, V...>::type &msg_ref =
std::get<i>(message.values).value;
return typename ParameterPackType<i, V...>::type::Builder{msg_ref};
}
template <typename T>
constexpr typename ParameterPackType<ParameterPackIndex<T, K...>::value,
V...>::type::Builder
/*
* Initialize a member by their name
* This is the preferred method for schema::Struct messages
*/
template <StringLiteral Literal>
typename Container::template ElementType<
MessageParameterKeyPackIndex<Literal, Keys...>::Value>::Builder
init() {
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};
constexpr size_t i =
MessageParameterKeyPackIndex<Literal, Keys...>::Value;
return init<i>();
}
};
class Reader {
private:
MessageType &message;
public:
Reader(MessageType &msg) : message{msg} {}
Builder asBuilder() { return Builder{message}; }
/*
* Get member by index
*/
template <size_t i>
typename Container::template ElementType<i>::Reader get() {
return typename Container::template ElementType<i>::Reader{
message.container.template get<i>()};
}
/*
* Get member by name
* This is the preferred method for schema::Struct messages
*/
template <StringLiteral Literal>
typename Container::template ElementType<
MessageParameterKeyPackIndex<Literal, Keys...>::Value>::Reader
get() {
// The index of the first match
constexpr size_t i =
MessageParameterKeyPackIndex<Literal, Keys...>::Value;
return get<i>();
}
};
Builder build() { return Builder{*this}; }
Reader read() { return Reader{*this}; }
};
/*
* Union message class. Wrapper object
*/
template <class... V, StringLiteral... Keys, class Container>
class Message<schema::Union<schema::NamedMember<V, Keys>...>, Container> final
: public MessageBase {
private:
using SchemaType = schema::Union<schema::NamedMember<V, Keys>...>;
using MessageType = Message<SchemaType, Container>;
Container container;
static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>,
"Container should have same the schema as Message");
friend class Builder;
friend class Reader;
public:
class Reader;
class Builder {
private:
MessageType &message;
public:
Builder(MessageType &msg) : message{msg} {}
Reader asReader() { return Reader{message}; }
template <size_t i>
typename Container::template ElementType<i>::Builder init() {
return typename Container::template ElementType<i>::Builder{
message.container.template get<i>()};
}
template <StringLiteral Literal>
typename Container::template ElementType<
MessageParameterKeyPackIndex<Literal, Keys...>::Value>::Builder
init() {
constexpr size_t i =
MessageParameterKeyPackIndex<Literal, Keys...>::Value;
return init<i>();
}
};
class Reader {
private:
MessageType &message;
public:
Reader(MessageType &msg) : message{msg} {}
Builder asBuilder() { return Builder{message}; }
template <size_t i>
typename Container::template ElementType<i>::Reader get() {
return typename Container::template ElementType<i>::Reader{
message.container.template get<i>()};
}
template <StringLiteral Literal>
typename Container::template ElementType<
MessageParameterKeyPackIndex<Literal, Keys...>::Value>::Reader
get() {
// The index of the first match
constexpr size_t i =
MessageParameterKeyPackIndex<Literal, Keys...>::Value;
return get<i>();
}
template <StringLiteral Literal>
constexpr size_t toIndex() const noexcept {
return MessageParameterKeyPackIndex<Literal, Keys...>::Value;
}
size_t index() const noexcept { return message.container.index(); }
template <StringLiteral Literal> bool hasAlternative() const {
return index() == toIndex<Literal>();
}
};
};
/*
* Array message class. Wrapper around an array schema element
* @todo Array class needs either a resize function or each message class has an
* individual call for Array children
*/
/*
template<class T, class Container>
class Message<schema::Array<T>, Container> final : public MessageBase {
private:
using SchemaType = schema::Array<T>;
using MessageType = Message<SchemaType, Container>;
Container container;
static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>,
"Container should have same Schema as Message");
friend class Builder;
friend class Reader;
public:
class Reader;
class Builder {
private:
MessageType & message;
public:
Builder(MessageType& msg):message{msg}{}
Reader asReader(){return Reader{message};}
template<size_t i>
typename Container::MessageType::Builder init(){
return typename
Container::MessageType::Builder{message.container.get<i>()};
}
};
class Reader {
private:
MessageType& message;
public:
Reader(MessageType& msg):message{msg}{}
Builder asBuilder(){return Builder{message};}
template<size_t i>
typename Container::MessageType::Reader get(){
return typename
Container::MessageType::Reader{message.container.get<i>()};
}
};
};
*/
/*
* Tuple message class. Wrapper around a tuple schema
*/
template <class... T, class Container>
class Message<schema::Tuple<T...>, Container> final : public MessageBase {
private:
using SchemaType = schema::Tuple<T...>;
using MessageType = Message<SchemaType, Container>;
Container container;
static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>,
"Container should have same the schema as Message");
friend class Builder;
friend class Reader;
public:
class Reader;
class Builder {
MessageType &message;
public:
Builder(MessageType &msg) : message{msg} {}
Reader asReader() { return Reader{message}; }
template <size_t i>
typename Container::template ElementType<i>::Builder init() {
return typename Container::template ElementType<i>::Builder{
message.container.template get<i>()};
}
};
class Reader {
private:
MessageUnion<MessageUnionMember<V, K>...> &message;
MessageType &message;
public:
Reader(MessageUnion<MessageUnionMember<V, K>...> &message)
: message{message} {}
template <size_t i>
constexpr typename ParameterPackType<i, V...>::type::Reader get() {
typename ParameterPackType<i, V...>::type &msg_ref =
std::get<i>(message.values).value;
return typename ParameterPackType<i, V...>::type::Reader{msg_ref};
}
template <typename T>
constexpr typename ParameterPackType<ParameterPackIndex<T, K...>::value,
V...>::type::Reader
get() {
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};
}
template <typename T> constexpr bool holdsAlternative() {
return std::holds_alternative<std::variant_alternative_t<
ParameterPackIndex<T, K...>::value, value_type>>(
message.values);
}
size_t index() const { return message.values.index(); }
bool isSetExplicitly() const { return message.set_explicitly; }
constexpr size_t size() { return std::variant_size<value_type>::value; }
Reader(MessageType &msg) : message{msg} {}
Builder asBuilder() { return Builder{message}; }
template <size_t i>
typename Container::template ElementType<i>::Reader get() {
return typename Container::template ElementType<i>::Reader{
message.container.template get<i>()};
}
};
};
class MessageReader {
/*
* Primitive type (float, double, uint8_t, uint16_t, uint32_t, uint64_t, int8_t,
* int16_t, int32_t, int64_t) message class
*/
template <class T, size_t N, class Container>
class Message<schema::Primitive<T, N>, Container> final : public MessageBase {
private:
using SchemaType = schema::Primitive<T, N>;
using MessageType = Message<SchemaType, Container>;
Container container;
static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>,
"Container should have same the schema as Message");
friend class Builder;
friend class Reader;
public:
virtual ~MessageReader() = default;
class Reader;
class Builder {
private:
MessageType &message;
public:
Builder(MessageType &msg) : message{msg} {}
Reader asReader() { return Reader{message}; }
void set(const typename Container::ValueType &value) {
message.container.set(value);
}
};
class Reader {
private:
MessageType &message;
public:
Reader(Message &msg) : message{msg} {}
Builder asBuilder() { return Builder{message}; }
const typename Container::ValueType &get() const {
return message.container.get();
}
};
};
class MessageBuilder {
template <class Container>
class Message<schema::String, Container> final : public MessageBase {
private:
Own<Message> root_message = nullptr;
using SchemaType = schema::String;
using MessageType = Message<SchemaType, Container>;
Container container;
static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>,
"Container should have same the schema as Message");
friend class Builder;
friend class Reader;
public:
virtual ~MessageBuilder() = default;
class Reader;
class Builder {
private:
MessageType &message;
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};
public:
Builder(MessageType &msg) : message{msg} {}
Reader asReader() { return Reader{message}; }
void set(const std::string &str) { message.container.set(str); }
};
class Reader {
private:
MessageType &message;
public:
Reader(MessageType &msg) : message{msg} {}
Builder asBuilder() { return Builder{message}; }
std::string_view get() { return message.container.get(); }
};
};
template <class Schema, class Container = MessageContainer<Schema>>
class HeapMessageRoot {
private:
Own<Message<Schema, Container>> root;
public:
HeapMessageRoot(Own<Message<Schema, Container>> r) : root{std::move(r)} {}
typename Message<Schema, Container>::Builder build() {
assert(root);
return typename Message<Schema, Container>::Builder{*root};
}
typename Message<Schema, Container>::Reader read() {
assert(root);
return typename Message<Schema, Container>::Reader{*root};
}
};
inline MessageBuilder heapMessageBuilder() { return MessageBuilder{}; }
/*
* Minor helper for creating a message root
*/
template <class Schema, class Container = MessageContainer<Schema>>
inline HeapMessageRoot<Schema, Container> heapMessageRoot() {
Own<Message<Schema, Container>> root = heap<Message<Schema, Container>>();
return HeapMessageRoot<Schema, Container>{std::move(root)};
}
} // namespace gin

View File

@ -0,0 +1,226 @@
#pragma once
#include "schema.h"
namespace gin {
template <class T> class MessageContainer;
template <class T, class Container> class Message;
template <size_t N, class... T> struct MessageParameterPackType;
template <class TN, class... T> struct MessageParameterPackType<0, TN, T...> {
using Type = TN;
};
template <size_t N, class TN, class... T>
struct MessageParameterPackType<N, TN, T...> {
static_assert(sizeof...(T) > 0, "Exhausted parameters");
using Type = typename MessageParameterPackType<N - 1, T...>::Type;
};
template <class T, class... TL> struct MessageParameterPackIndex;
template <class T, class... TL> struct MessageParameterPackIndex<T, T, TL...> {
static constexpr size_t Value = 0u;
};
template <class T, class TL0, class... TL>
struct MessageParameterPackIndex<T, TL0, TL...> {
static constexpr size_t Value =
1u + MessageParameterPackIndex<T, TL...>::Value;
};
/*
* Nightmare inducing compiler problems found here. Somehow non-type
* StringLiterals cannot be resolved as non-type primitive template values can.
* This is the workaround
*/
template <StringLiteral V, StringLiteral Key0, StringLiteral... Keys>
struct MessageParameterKeyPackIndexHelper {
static constexpr size_t Value =
(V == Key0)
? (0u)
: (1u + MessageParameterKeyPackIndexHelper<V, Keys...>::Value);
};
template <StringLiteral V, StringLiteral Key0>
struct MessageParameterKeyPackIndexHelper<V, Key0> {
static constexpr size_t Value = (V == Key0) ? (0u) : (1u);
};
template <StringLiteral V, StringLiteral... Keys>
struct MessageParameterKeyPackIndex {
static constexpr size_t Value =
MessageParameterKeyPackIndexHelper<V, Keys...>::Value;
static_assert(Value < sizeof...(Keys),
"Provided StringLiteral doesn't exist in searched list");
};
template <class... V, StringLiteral... Keys>
class MessageContainer<schema::Struct<schema::NamedMember<V, Keys>...>> {
private:
using ValueType = std::tuple<Message<V, MessageContainer<V>>...>;
ValueType values;
public:
using SchemaType = schema::Struct<schema::NamedMember<V, Keys>...>;
template <size_t i>
using ElementType = typename MessageParameterPackType<
i, Message<V, MessageContainer<V>>...>::Type;
template <size_t i> ElementType<i> &get() { return std::get<i>(values); }
};
/*
* Union storage
*/
template <class... V, StringLiteral... Keys>
class MessageContainer<schema::Union<schema::NamedMember<V, Keys>...>> {
private:
using ValueType = std::variant<Message<V, MessageContainer<V>>...>;
ValueType value;
public:
using SchemaType = schema::Union<schema::NamedMember<V, Keys>...>;
template <size_t i>
using ElementType = typename MessageParameterPackType<
i, Message<V, MessageContainer<V>>...>::Type;
template <size_t i> ElementType<i> &get() {
if (i != value.index()) {
using MessageIV = typename MessageParameterPackType<i, V...>::Type;
value = Message<MessageIV, MessageContainer<MessageIV>>{};
}
return std::get<i>(value);
}
size_t index() const noexcept { return value.index(); }
};
/*
* Array storage
*/
/*
template<class T>
class MessageContainer<schema::Array> {
private:
using ValueType = std::vector<Message<T,MessageContainer<T>>>;
ValueType values;
public:
using SchemaType = schema::Array<T>;
template<size_t i> Message<T,MessageContainer<T>>& get(){
return values.at(i);
}
};
*/
/*
* Tuple storage
*/
template <class... T> class MessageContainer<schema::Tuple<T...>> {
private:
using ValueType = std::tuple<Message<T, MessageContainer<T>>...>;
ValueType values;
public:
using SchemaType = schema::Tuple<T...>;
template <size_t i>
using ElementType = typename MessageParameterPackType<
i, Message<T, MessageContainer<T>>...>::Type;
template <size_t i> ElementType<i> &get() { return std::get<i>(values); }
};
/*
* Helper for the basic message container, so the class doesn't have to be
* specialized 10 times.
*/
template <class T> struct PrimitiveTypeHelper;
template <>
struct PrimitiveTypeHelper<schema::Primitive<schema::SignedInteger, 1>> {
using Type = int8_t;
};
template <>
struct PrimitiveTypeHelper<schema::Primitive<schema::SignedInteger, 2>> {
using Type = int16_t;
};
template <>
struct PrimitiveTypeHelper<schema::Primitive<schema::SignedInteger, 4>> {
using Type = int32_t;
};
template <>
struct PrimitiveTypeHelper<schema::Primitive<schema::SignedInteger, 8>> {
using Type = int64_t;
};
template <>
struct PrimitiveTypeHelper<schema::Primitive<schema::UnsignedInteger, 1>> {
using Type = uint8_t;
};
template <>
struct PrimitiveTypeHelper<schema::Primitive<schema::UnsignedInteger, 2>> {
using Type = uint16_t;
};
template <>
struct PrimitiveTypeHelper<schema::Primitive<schema::UnsignedInteger, 4>> {
using Type = uint32_t;
};
template <>
struct PrimitiveTypeHelper<schema::Primitive<schema::UnsignedInteger, 8>> {
using Type = uint64_t;
};
template <>
struct PrimitiveTypeHelper<schema::Primitive<schema::FloatingPoint, 4>> {
using Type = float;
};
template <>
struct PrimitiveTypeHelper<schema::Primitive<schema::FloatingPoint, 8>> {
using Type = double;
};
template <class T, size_t N> class MessageContainer<schema::Primitive<T, N>> {
public:
using SchemaType = schema::Primitive<T, N>;
using ValueType =
typename PrimitiveTypeHelper<schema::Primitive<T, N>>::Type;
private:
ValueType value;
public:
MessageContainer() : value{0} {}
void set(const ValueType &v) { value = v; }
const ValueType &get() const { return value; }
};
template <> class MessageContainer<schema::String> {
public:
using SchemaType = schema::String;
using ValueType = std::string;
private:
ValueType value;
public:
void set(const ValueType &v) { value = v; }
const ValueType &get() const { return value; }
};
} // namespace gin

View File

@ -1,22 +0,0 @@
#include "message_dynamic.h"
namespace gin {
template <>
DynamicMessage::Type DynamicMessagePrimitive<uint64_t>::type() const {
return DynamicMessage::Type::Unsigned;
};
template <>
DynamicMessage::Type DynamicMessagePrimitive<int64_t>::type() const {
return DynamicMessage::Type::Signed;
};
template <>
DynamicMessage::Type DynamicMessagePrimitive<std::string>::type() const {
return DynamicMessage::Type::String;
};
template <> DynamicMessage::Type DynamicMessagePrimitive<bool>::type() const {
return DynamicMessage::Type::Bool;
};
template <> DynamicMessage::Type DynamicMessagePrimitive<double>::type() const {
return DynamicMessage::Type::Double;
};
} // namespace gin

View File

@ -1,274 +0,0 @@
#pragma once
#include <cstdint>
#include <deque>
#include <map>
#include <string>
#include "common.h"
/// @todo Move implementation to cpp file
namespace gin {
/*
* Base class for each message data structure
*/
class DynamicMessage {
protected:
/*
* The encoder and decoders use this as a hint if this was set by a default
* value or not
*/
bool set_explicitly = false;
public:
/*
* Later use for dynamic access
*/
enum class Type : uint16_t {
Null,
Struct,
List,
Array,
Union,
String,
Signed,
Unsigned,
Bool,
Double
};
virtual ~DynamicMessage() = default;
virtual Type type() const = 0;
template <typename T> T &as() {
static_assert(std::is_base_of<DynamicMessage, T>());
return reinterpret_cast<T &>(*this);
}
template <typename T> const T &as() const {
static_assert(std::is_base_of<DynamicMessage, T>());
return reinterpret_cast<const T &>(*this);
}
class DynamicReader;
class DynamicBuilder {
private:
DynamicMessage &message;
public:
DynamicBuilder(DynamicMessage &message) : message{message} {}
DynamicReader asReader() const { return DynamicReader{message}; }
DynamicMessage::Type type() const { return message.type(); }
template <typename T> typename T::Builder as() {
static_assert(std::is_base_of<DynamicMessage, T>());
return typename T::Builder{reinterpret_cast<T &>(message)};
}
};
class DynamicReader {
private:
DynamicMessage &message;
public:
DynamicReader(DynamicMessage &message) : message{message} {}
DynamicBuilder asBuilder() const { return DynamicBuilder{message}; }
DynamicMessage::Type type() const { return message.type(); }
template <typename T> typename T::Reader as() {
static_assert(std::is_base_of<DynamicMessage, T>());
return typename T::Reader{reinterpret_cast<T &>(message)};
}
};
};
class DynamicMessageNull : public DynamicMessage {
public:
DynamicMessage::Type type() const override {
return DynamicMessage::Type::Null;
}
};
static DynamicMessageNull dynamicNullMessage;
template <typename T> class DynamicMessagePrimitive : public DynamicMessage {
private:
T value;
friend class Builder;
friend class Reader;
public:
DynamicMessagePrimitive() = default;
DynamicMessage::Type type() const override;
class Reader;
class Builder {
private:
DynamicMessagePrimitive<T> &message;
public:
Builder(DynamicMessagePrimitive<T> &message) : message{message} {}
constexpr void set(const T &value) {
message.value = value;
message.set_explicitly = true;
}
constexpr void set(T &&value) {
message.value = std::move(value);
message.set_explicitly = true;
}
Reader asReader() const { return Reader{message}; }
};
class Reader {
private:
DynamicMessagePrimitive<T> &message;
public:
Reader(DynamicMessagePrimitive<T> &message) : message{message} {}
constexpr const T &get() { return message.value; }
bool isSetExplicitly() const { return message.set_explicitly; }
Builder asBuilder() const { return Builder{message}; }
};
};
using DynamicMessageString = DynamicMessagePrimitive<std::string>;
using DynamicMessageSigned = DynamicMessagePrimitive<int64_t>;
using DynamicMessageUnsigned = DynamicMessagePrimitive<uint64_t>;
using DynamicMessageBool = DynamicMessagePrimitive<bool>;
using DynamicMessageDouble = DynamicMessagePrimitive<double>;
class DynamicMessageStruct : public DynamicMessage {
private:
std::map<std::string, Own<DynamicMessage>, std::less<>> messages;
friend class Builder;
friend class Reader;
public:
DynamicMessage::Type type() const override {
return DynamicMessage::Type::Struct;
}
class Reader;
class Builder {
private:
DynamicMessageStruct &message;
public:
Builder(DynamicMessageStruct &message) : message{message} {
message.set_explicitly = true;
}
template <typename T> typename T::Builder init(const std::string &key) {
Own<T> msg = std::make_unique<T>();
typename T::Builder builder{*msg};
/*auto insert = */ message.messages.insert(
std::make_pair(key, std::move(msg)));
return builder;
}
DynamicMessage::DynamicBuilder init(const std::string &key,
Own<DynamicMessage> &&msg) {
DynamicMessage::DynamicBuilder builder{*msg};
message.messages.insert(std::make_pair(key, std::move(msg)));
return builder;
}
Reader asReader() const { return Reader{message}; }
};
class Reader {
private:
DynamicMessageStruct &message;
public:
Reader(DynamicMessageStruct &message) : message{message} {}
DynamicMessage::DynamicReader get(std::string_view key) {
auto find = message.messages.find(key);
if (find != message.messages.end()) {
return DynamicMessage::DynamicReader{*(find->second)};
} else {
return DynamicMessage::DynamicReader{dynamicNullMessage};
}
}
size_t size() const { return message.messages.size(); }
bool isSetExplicitly() const { return message.set_explicitly; }
Builder asBuilder() const { return Builder{message}; }
};
};
class DynamicMessageList : public DynamicMessage {
private:
std::deque<Own<DynamicMessage>> messages;
friend class Builder;
friend class Reader;
public:
DynamicMessage::Type type() const override {
return DynamicMessage::Type::List;
}
class Reader;
class Builder {
private:
DynamicMessageList &message;
public:
Builder(DynamicMessageList &message) : message{message} {
message.set_explicitly = true;
}
template <typename T> typename T::Builder push() {
static_assert(std::is_base_of<DynamicMessage, T>());
Own<T> msg = std::make_unique<T>();
typename T::Builder builder{*msg};
message.messages.push_back(std::move(msg));
return builder;
}
DynamicMessage::DynamicBuilder push(Own<DynamicMessage> &&msg) {
DynamicMessage::DynamicBuilder builder{*msg};
message.messages.push_back(std::move(msg));
return builder;
}
Reader asReader() const { return Reader{message}; }
};
class Reader {
private:
DynamicMessageList &message;
public:
Reader(DynamicMessageList &message) : message{message} {}
DynamicMessage::DynamicReader get(size_t element) {
if (element < message.messages.size()) {
return DynamicMessage::DynamicReader{
*(message.messages[element])};
} else {
return DynamicMessage::DynamicReader{dynamicNullMessage};
}
}
size_t size() const { return message.messages.size(); }
bool isSetExplicitly() const { return message.set_explicitly; }
Builder asBuilder() const { return Builder{message}; }
};
};
} // namespace gin

View File

@ -42,31 +42,39 @@ public:
const Version version() const { return Version{0, 0, 0}; }
template <typename T>
Error encode(typename T::Reader reader, Buffer &buffer);
template <class Schema, class Container = MessageContainer<Schema>>
Error encode(typename Message<Schema, Container>::Reader reader,
Buffer &buffer);
template <typename T>
Error decode(typename T::Builder builder, Buffer &buffer,
const Limits &limits = Limits{});
template <class Schema, class Container = MessageContainer<Schema>>
Error decode(typename Message<Schema, Container>::Builder builder,
Buffer &buffer, const Limits &limits = Limits{});
};
template <typename T> struct ProtoKelEncodeImpl;
template <class T> struct ProtoKelEncodeImpl;
template <typename T> struct ProtoKelEncodeImpl<MessagePrimitive<T>> {
static Error encode(typename MessagePrimitive<T>::Reader data,
Buffer &buffer) {
Error error = StreamValue<T>::encode(data.get(), buffer);
template <class T, size_t N, class Container>
struct ProtoKelEncodeImpl<Message<schema::Primitive<T, N>, Container>> {
static Error
encode(typename Message<schema::Primitive<T, N>, Container>::Reader data,
Buffer &buffer) {
Error error = StreamValue<typename PrimitiveTypeHelper<
schema::Primitive<T, N>>::Type>::encode(data.get(), buffer);
return error;
}
static size_t size(typename MessagePrimitive<T>::Reader) {
return StreamValue<T>::size();
static size_t
size(typename Message<schema::Primitive<T, N>, Container>::Reader) {
return StreamValue<typename PrimitiveTypeHelper<
schema::Primitive<T, N>>::Type>::size();
}
};
template <> struct ProtoKelEncodeImpl<MessagePrimitive<std::string>> {
static Error encode(typename MessagePrimitive<std::string>::Reader data,
Buffer &buffer) {
template <class Container>
struct ProtoKelEncodeImpl<Message<schema::String, Container>> {
static Error
encode(typename Message<schema::String, Container>::Reader data,
Buffer &buffer) {
std::string_view view = data.get();
size_t size = view.size();
@ -86,24 +94,27 @@ template <> struct ProtoKelEncodeImpl<MessagePrimitive<std::string>> {
return noError();
}
static size_t size(typename MessagePrimitive<std::string>::Reader reader) {
static size_t
size(typename Message<schema::String, Container>::Reader reader) {
return sizeof(size_t) + reader.get().size();
}
};
template <typename... T> struct ProtoKelEncodeImpl<MessageList<T...>> {
template <class... T, class Container>
struct ProtoKelEncodeImpl<Message<schema::Tuple<T...>, Container>> {
template <size_t i = 0>
static typename std::enable_if<i == sizeof...(T), Error>::type
encodeMembers(typename MessageList<T...>::Reader, Buffer &) {
encodeMembers(typename Message<schema::Tuple<T...>, Container>::Reader,
Buffer &) {
return noError();
}
template <size_t i = 0>
static typename std::enable_if <
i<sizeof...(T), Error>::type
encodeMembers(typename MessageList<T...>::Reader data, Buffer &buffer) {
static typename std::enable_if<(i < sizeof...(T)), Error>::type
encodeMembers(typename Message<schema::Tuple<T...>, Container>::Reader data,
Buffer &buffer) {
Error error =
ProtoKelEncodeImpl<typename ParameterPackType<i, T...>::type>::
ProtoKelEncodeImpl<typename Container::template ElementType<i>>::
encode(data.template get<i>(), buffer);
if (error.failed()) {
return error;
@ -112,47 +123,52 @@ template <typename... T> struct ProtoKelEncodeImpl<MessageList<T...>> {
return encodeMembers<i + 1>(data, buffer);
}
static Error encode(typename MessageList<T...>::Reader data,
Buffer &buffer) {
static Error
encode(typename Message<schema::Tuple<T...>, Container>::Reader data,
Buffer &buffer) {
return encodeMembers<0>(data, buffer);
}
template <size_t i = 0>
static typename std::enable_if<i == sizeof...(T), size_t>::type
sizeMembers(typename MessageList<T...>::Reader) {
sizeMembers(typename Message<schema::Tuple<T...>, Container>::Reader) {
return 0;
}
template <size_t i = 0>
static typename std::enable_if <
i<sizeof...(T), size_t>::type
sizeMembers(typename MessageList<T...>::Reader reader) {
return ProtoKelEncodeImpl<typename ParameterPackType<i, T...>::type>::
i<sizeof...(T), size_t>::type sizeMembers(
typename Message<schema::Tuple<T...>, Container>::Reader reader) {
return ProtoKelEncodeImpl<typename Container::template ElementType<i>>::
size(reader.template get<i>()) +
sizeMembers<i + 1>(reader);
}
static size_t size(typename MessageList<T...>::Reader reader) {
static size_t
size(typename Message<schema::Tuple<T...>, Container>::Reader reader) {
return sizeMembers<0>(reader);
}
};
template <typename... V, typename... K>
struct ProtoKelEncodeImpl<MessageStruct<MessageStructMember<V, K>...>> {
template <typename... V, StringLiteral... K, class Container>
struct ProtoKelEncodeImpl<
Message<schema::Struct<schema::NamedMember<V, K>...>, Container>> {
template <size_t i = 0>
static typename std::enable_if<i == sizeof...(V), Error>::type
encodeMembers(typename MessageStruct<MessageStructMember<V, K>...>::Reader,
encodeMembers(typename Message<schema::Struct<schema::NamedMember<V, K>...>,
Container>::Reader,
Buffer &) {
return noError();
}
template <size_t i = 0>
static typename std::enable_if <
i<sizeof...(V), Error>::type encodeMembers(
typename MessageStruct<MessageStructMember<V, K>...>::Reader data,
typename Message<schema::Struct<schema::NamedMember<V, K>...>,
Container>::Reader data,
Buffer &buffer) {
Error error =
ProtoKelEncodeImpl<typename ParameterPackType<i, V...>::type>::
ProtoKelEncodeImpl<typename Container::template ElementType<i>>::
encode(data.template get<i>(), buffer);
if (error.failed()) {
return error;
@ -161,79 +177,87 @@ struct ProtoKelEncodeImpl<MessageStruct<MessageStructMember<V, K>...>> {
}
static Error
encode(typename MessageStruct<MessageStructMember<V, K>...>::Reader data,
encode(typename Message<schema::Struct<schema::NamedMember<V, K>...>,
Container>::Reader data,
Buffer &buffer) {
return encodeMembers<0>(data, buffer);
}
template <size_t i = 0>
static typename std::enable_if<i == sizeof...(V), size_t>::type
sizeMembers(typename MessageStruct<MessageStructMember<V, K>...>::Reader) {
return 0;
}
template <size_t i = 0>
static typename std::enable_if <
i<sizeof...(V), size_t>::type
sizeMembers(typename MessageStruct<MessageStructMember<V, K>...>::Reader
reader) {
return ProtoKelEncodeImpl<typename ParameterPackType<i, V...>::type>::
size(reader.template get<i>()) +
sizeMembers<i + 1>(reader);
}
static size_t
size(typename MessageStruct<MessageStructMember<V, K>...>::Reader reader) {
return sizeMembers<0>(reader);
}
};
template <typename... V, typename... K>
struct ProtoKelEncodeImpl<MessageUnion<MessageUnionMember<V, K>...>> {
template <size_t i = 0>
static typename std::enable_if<i == sizeof...(V), Error>::type
encodeMembers(typename MessageUnion<MessageUnionMember<V, K>...>::Reader,
Buffer &) {
return noError();
}
template <size_t i = 0>
static typename std::enable_if <
i<sizeof...(V), Error>::type encodeMembers(
typename MessageUnion<MessageUnionMember<V, K>...>::Reader reader,
Buffer &buffer) {
if (reader.template holdsAlternative<
typename ParameterPackType<i, K...>::type>()) {
Error error = StreamValue<msg_union_id_t>::encode(i, buffer);
if (error.failed()) {
return error;
}
return ProtoKelEncodeImpl<typename ParameterPackType<
i, V...>::type>::encode(reader.template get<i>(), buffer);
}
return encodeMembers<i + 1>(reader, buffer);
}
static Error
encode(typename MessageUnion<MessageUnionMember<V, K>...>::Reader reader,
Buffer &buffer) {
return encodeMembers<0>(reader, buffer);
}
template <size_t i = 0>
static typename std::enable_if<i == sizeof...(V), size_t>::type
sizeMembers(typename MessageUnion<MessageUnionMember<V, K>...>::Reader) {
sizeMembers(typename Message<schema::Struct<schema::NamedMember<V, K>...>,
Container>::Reader) {
return 0;
}
template <size_t i = 0>
static typename std::enable_if <
i<sizeof...(V), size_t>::type sizeMembers(
typename MessageUnion<MessageUnionMember<V, K>...>::Reader reader) {
if (reader.template holdsAlternative<
typename ParameterPackType<i, K...>::type>()) {
return ProtoKelEncodeImpl<typename ParameterPackType<
i, V...>::type>::size(reader.template get<i>());
typename Message<schema::Struct<schema::NamedMember<V, K>...>,
Container>::Reader reader) {
return ProtoKelEncodeImpl<typename Container::template ElementType<i>>::
size(reader.template get<i>()) +
sizeMembers<i + 1>(reader);
}
static size_t
size(typename Message<schema::Struct<schema::NamedMember<V, K>...>,
Container>::Reader reader) {
return sizeMembers<0>(reader);
}
};
template <typename... V, StringLiteral... K, class Container>
struct ProtoKelEncodeImpl<
Message<schema::Union<schema::NamedMember<V, K>...>, Container>> {
template <size_t i = 0>
static typename std::enable_if<i == sizeof...(V), Error>::type
encodeMembers(typename Message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Reader,
Buffer &) {
return noError();
}
template <size_t i = 0>
static typename std::enable_if <
i<sizeof...(V), Error>::type encodeMembers(
typename Message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Reader reader,
Buffer &buffer) {
if (reader.index() == i) {
Error error = StreamValue<msg_union_id_t>::encode(i, buffer);
if (error.failed()) {
return error;
}
return ProtoKelEncodeImpl<typename Container::template ElementType<
i>>::encode(reader.template get<i>(), buffer);
}
return encodeMembers<i + 1>(reader, buffer);
}
static Error
encode(typename Message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Reader reader,
Buffer &buffer) {
return encodeMembers<0>(reader, buffer);
}
template <size_t i = 0>
static typename std::enable_if<i == sizeof...(V), size_t>::type
sizeMembers(typename Message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Reader) {
return 0;
}
template <size_t i = 0>
static typename std::enable_if <
i<sizeof...(V), size_t>::type sizeMembers(
typename Message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Reader reader) {
if (reader.index() == i) {
return ProtoKelEncodeImpl<typename Container::template ElementType<
i>>::size(reader.template get<i>());
}
return sizeMembers<i + 1>(reader);
}
@ -242,8 +266,9 @@ struct ProtoKelEncodeImpl<MessageUnion<MessageUnionMember<V, K>...>> {
* Size of union id + member size
*/
static size_t
size(typename MessageUnion<MessageUnionMember<V, K>...>::Reader reader) {
return sizeof(uint32_t) + sizeMembers<0>(reader);
size(typename Message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Reader reader) {
return sizeof(msg_union_id_t) + sizeMembers<0>(reader);
}
};
/*
@ -251,19 +276,24 @@ struct ProtoKelEncodeImpl<MessageUnion<MessageUnionMember<V, K>...>> {
*/
template <typename T> struct ProtoKelDecodeImpl;
template <typename T> struct ProtoKelDecodeImpl<MessagePrimitive<T>> {
static Error decode(typename MessagePrimitive<T>::Builder data,
Buffer &buffer) {
T val = 0;
Error error = StreamValue<T>::decode(val, buffer);
template <class T, size_t N, class Container>
struct ProtoKelDecodeImpl<Message<schema::Primitive<T, N>, Container>> {
static Error
decode(typename Message<schema::Primitive<T, N>, Container>::Builder data,
Buffer &buffer) {
typename PrimitiveTypeHelper<schema::Primitive<T, N>>::Type val = 0;
Error error = StreamValue<typename PrimitiveTypeHelper<
schema::Primitive<T, N>>::Type>::decode(val, buffer);
data.set(val);
return error;
}
};
template <> struct ProtoKelDecodeImpl<MessagePrimitive<std::string>> {
static Error decode(typename MessagePrimitive<std::string>::Builder data,
Buffer &buffer) {
template <class Container>
struct ProtoKelDecodeImpl<Message<schema::String, Container>> {
static Error
decode(typename Message<schema::String, Container>::Builder data,
Buffer &buffer) {
size_t size = 0;
if (sizeof(size) > buffer.readCompositeLength()) {
return recoverableError("Buffer too small");
@ -293,21 +323,23 @@ template <> struct ProtoKelDecodeImpl<MessagePrimitive<std::string>> {
}
};
template <typename... T> struct ProtoKelDecodeImpl<MessageList<T...>> {
template <class... T, class Container>
struct ProtoKelDecodeImpl<Message<schema::Tuple<T...>, Container>> {
template <size_t i = 0>
static typename std::enable_if<i == sizeof...(T), Error>::type
decodeMembers(typename MessageList<T...>::Builder, Buffer &) {
decodeMembers(typename Message<schema::Tuple<T...>, Container>::Builder,
Buffer &) {
return noError();
}
template <size_t i = 0>
static typename std::enable_if <
i<sizeof...(T), Error>::type
decodeMembers(typename MessageList<T...>::Builder builder,
Buffer &buffer) {
i<sizeof...(T), Error>::type decodeMembers(
typename Message<schema::Tuple<T...>, Container>::Builder builder,
Buffer &buffer) {
Error error =
ProtoKelDecodeImpl<typename ParameterPackType<i, T...>::type>::
ProtoKelDecodeImpl<typename Container::template ElementType<i>>::
decode(builder.template init<i>(), buffer);
if (error.failed()) {
return error;
@ -315,17 +347,21 @@ template <typename... T> struct ProtoKelDecodeImpl<MessageList<T...>> {
return decodeMembers<i + 1>(builder, buffer);
}
static Error decode(typename MessageList<T...>::Builder builder,
Buffer &buffer) {
static Error
decode(typename Message<schema::Tuple<T...>, Container>::Builder builder,
Buffer &buffer) {
return decodeMembers<0>(builder, buffer);
}
};
template <typename... V, typename... K>
struct ProtoKelDecodeImpl<MessageStruct<MessageStructMember<V, K>...>> {
template <class... V, StringLiteral... K, class Container>
struct ProtoKelDecodeImpl<
Message<schema::Struct<schema::NamedMember<V, K>...>, Container>> {
template <size_t i = 0>
static typename std::enable_if<i == sizeof...(V), Error>::type
decodeMembers(typename MessageStruct<MessageStructMember<V, K>...>::Builder,
decodeMembers(typename Message<schema::Struct<schema::NamedMember<V, K>...>,
Container>::Builder,
Buffer &) {
return noError();
}
@ -333,12 +369,12 @@ struct ProtoKelDecodeImpl<MessageStruct<MessageStructMember<V, K>...>> {
template <size_t i = 0>
static typename std::enable_if <
i<sizeof...(V), Error>::type decodeMembers(
typename MessageStruct<MessageStructMember<V, K>...>::Builder
builder,
typename Message<schema::Struct<schema::NamedMember<V, K>...>,
Container>::Builder builder,
Buffer &buffer) {
Error error =
ProtoKelDecodeImpl<typename ParameterPackType<i, V...>::type>::
ProtoKelDecodeImpl<typename Container::template ElementType<i>>::
decode(builder.template init<i>(), buffer);
if (error.failed()) {
return error;
@ -346,18 +382,21 @@ struct ProtoKelDecodeImpl<MessageStruct<MessageStructMember<V, K>...>> {
return decodeMembers<i + 1>(builder, buffer);
}
static Error decode(
typename MessageStruct<MessageStructMember<V, K>...>::Builder builder,
Buffer &buffer) {
static Error
decode(typename Message<schema::Struct<schema::NamedMember<V, K>...>,
Container>::Builder builder,
Buffer &buffer) {
return decodeMembers<0>(builder, buffer);
}
};
template <typename... V, typename... K>
struct ProtoKelDecodeImpl<MessageUnion<MessageUnionMember<V, K>...>> {
template <class... V, StringLiteral... K, class Container>
struct ProtoKelDecodeImpl<
Message<schema::Union<schema::NamedMember<V, K>...>, Container>> {
template <size_t i = 0>
static typename std::enable_if<i == sizeof...(V), Error>::type
decodeMembers(typename MessageUnion<MessageUnionMember<V, K>...>::Builder,
decodeMembers(typename Message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Builder,
Buffer &, msg_union_id_t) {
return noError();
}
@ -365,13 +404,14 @@ struct ProtoKelDecodeImpl<MessageUnion<MessageUnionMember<V, K>...>> {
template <size_t i = 0>
static typename std::enable_if <
i<sizeof...(V), Error>::type decodeMembers(
typename MessageUnion<MessageUnionMember<V, K>...>::Builder builder,
typename Message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Builder builder,
Buffer &buffer, msg_union_id_t id) {
if (id == i) {
Error error =
ProtoKelDecodeImpl<typename ParameterPackType<i, V...>::type>::
decode(builder.template init<i>(), buffer);
ProtoKelDecodeImpl<typename Container::template ElementType<
i>>::decode(builder.template init<i>(), buffer);
if (error.failed()) {
return error;
}
@ -380,7 +420,8 @@ struct ProtoKelDecodeImpl<MessageUnion<MessageUnionMember<V, K>...>> {
}
static Error
decode(typename MessageUnion<MessageUnionMember<V, K>...>::Builder builder,
decode(typename Message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Builder builder,
Buffer &buffer) {
msg_union_id_t id = 0;
Error error = StreamValue<msg_union_id_t>::decode(id, buffer);
@ -395,11 +436,13 @@ struct ProtoKelDecodeImpl<MessageUnion<MessageUnionMember<V, K>...>> {
}
};
template <typename T>
Error ProtoKelCodec::encode(typename T::Reader reader, Buffer &buffer) {
template <class Schema, class Container>
Error ProtoKelCodec::encode(typename Message<Schema, Container>::Reader reader,
Buffer &buffer) {
BufferView view{buffer};
msg_packet_length_t packet_length = ProtoKelEncodeImpl<T>::size(reader);
msg_packet_length_t packet_length =
ProtoKelEncodeImpl<Message<Schema, Container>>::size(reader);
// Check the size of the packet for the first
// message length description
@ -417,7 +460,8 @@ Error ProtoKelCodec::encode(typename T::Reader reader, Buffer &buffer) {
}
}
{
Error error = ProtoKelEncodeImpl<T>::encode(reader, view);
Error error = ProtoKelEncodeImpl<Message<Schema, Container>>::encode(
reader, view);
if (error.failed()) {
return error;
}
@ -427,9 +471,10 @@ Error ProtoKelCodec::encode(typename T::Reader reader, Buffer &buffer) {
return noError();
}
template <typename T>
Error ProtoKelCodec::decode(typename T::Builder builder, Buffer &buffer,
const Limits &limits) {
template <class Schema, class Container>
Error ProtoKelCodec::decode(
typename Message<Schema, Container>::Builder builder, Buffer &buffer,
const Limits &limits) {
BufferView view{buffer};
msg_packet_length_t packet_length = 0;
@ -446,13 +491,15 @@ Error ProtoKelCodec::decode(typename T::Builder builder, Buffer &buffer,
}
{
Error error = ProtoKelDecodeImpl<T>::decode(builder, view);
Error error = ProtoKelDecodeImpl<Message<Schema, Container>>::decode(
builder, view);
if (error.failed()) {
return error;
}
}
{
if (ProtoKelEncodeImpl<T>::size(builder.asReader()) != packet_length) {
if (ProtoKelEncodeImpl<Message<Schema, Container>>::size(
builder.asReader()) != packet_length) {
return criticalError("Bad packet format");
}
}
@ -461,4 +508,4 @@ Error ProtoKelCodec::decode(typename T::Builder builder, Buffer &buffer,
return noError();
}
} // namespace gin
} // namespace gin

51
source/kelgin/schema.h Normal file
View File

@ -0,0 +1,51 @@
#pragma once
#include "string_literal.h"
namespace gin {
namespace schema {
template <class T, StringLiteral Literal> struct NamedMember {};
template <class... T> struct Struct;
template <class... V, StringLiteral... K>
struct Struct<NamedMember<V, K>...> {};
template <class... T> struct Union;
template <class... V, StringLiteral... K> struct Union<NamedMember<V, K>...> {};
template <class T> struct Array {};
template <class... T> struct Tuple {};
struct String {};
struct SignedInteger {};
struct UnsignedInteger {};
struct FloatingPoint {};
template <class T, size_t N> struct Primitive {
static_assert(((std::is_same_v<T, SignedInteger> ||
std::is_same_v<T, UnsignedInteger>)&&(N == 1 || N == 2 ||
N == 4 || N == 8)) ||
(std::is_same_v<T, FloatingPoint> && (N == 4 || N == 8)),
"Primitive Type is not supported");
};
using Int8 = Primitive<SignedInteger, 1>;
using Int16 = Primitive<SignedInteger, 2>;
using Int32 = Primitive<SignedInteger, 4>;
using Int64 = Primitive<SignedInteger, 8>;
using UInt8 = Primitive<UnsignedInteger, 1>;
using UInt16 = Primitive<UnsignedInteger, 2>;
using UInt32 = Primitive<UnsignedInteger, 4>;
using UInt64 = Primitive<UnsignedInteger, 8>;
using Float32 = Primitive<FloatingPoint, 4>;
using Float64 = Primitive<FloatingPoint, 8>;
} // namespace schema
} // namespace gin

View File

@ -9,17 +9,32 @@ namespace gin {
* literal. It guarantees compile time uniqueness and thus allows using strings
* in template parameters.
*/
template <typename T, T... Chars> class StringLiteral {
template <class CharT, size_t N> class StringLiteral {
public:
static constexpr std::array<T, sizeof...(Chars) + 1u> data = {Chars...,
'\0'};
static constexpr std::string_view view() {
constexpr StringLiteral(const CharT (&input)[N]) noexcept {
for (size_t i = 0; i < N; ++i) {
data[i] = input[i];
}
}
std::array<CharT, N> data{};
constexpr std::string_view view() const noexcept {
return std::string_view{data.data()};
}
constexpr bool
operator==(const StringLiteral<CharT, N> &) const noexcept = default;
template <class CharTR, size_t NR>
constexpr bool
operator==(const StringLiteral<CharTR, NR> &) const noexcept {
return false;
}
};
} // namespace gin
template <typename T, T... Chars>
constexpr gin::StringLiteral<T, Chars...> operator""_t() {
return {};
}
constexpr gin::StringLiteral<T, sizeof...(Chars)> operator""_key() {
return gin::StringLiteral<T, sizeof...(Chars) + 1u>{Chars..., '\0'};
}
} // namespace gin

View File

@ -1,31 +0,0 @@
#pragma once
#include <string_view>
#include "message.h"
namespace gin {
const std::string_view json_org_example =
R"({
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
})";
}

View File

@ -1,289 +0,0 @@
#include "suite/suite.h"
#include <cstdint>
#include <string>
#include "buffer.h"
#include "source/kelgin/message.h"
#include "source/kelgin/json.h"
#include "./data/json.h"
using gin::MessageList;
using gin::MessageStruct;
using gin::MessageStructMember;
using gin::MessagePrimitive;
using gin::heapMessageBuilder;
using gin::JsonCodec;
using gin::Error;
using gin::RingBuffer;
namespace {
typedef MessageList<MessagePrimitive<uint32_t>, MessagePrimitive<std::string> > TestList;
GIN_TEST("JSON List Encoding"){
auto builder = heapMessageBuilder();
auto root = builder.initRoot<TestList>();
auto uint = root.init<0>();
uint.set(12);
auto string = root.init<1>();
string.set("free");
RingBuffer temp_buffer;
JsonCodec codec;
codec.encode<TestList>(root.asReader(), temp_buffer);
std::string tmp_string = temp_buffer.toString();
GIN_EXPECT(tmp_string == "[12,\"free\"]", std::string{"Bad encoding:\n"} + tmp_string);
}
typedef MessageStruct<
MessageStructMember<MessagePrimitive<uint32_t>, decltype("test_uint"_t)>,
MessageStructMember<MessagePrimitive<std::string>, decltype("test_string"_t)>,
MessageStructMember<MessagePrimitive<std::string>, decltype("test_name"_t)>,
MessageStructMember<MessagePrimitive<bool>, decltype("test_bool"_t)>
> TestStruct;
GIN_TEST("JSON Struct Encoding"){
auto builder = heapMessageBuilder();
auto root = builder.initRoot<TestStruct>();
auto uint = root.init<decltype("test_uint"_t)>();
uint.set(23);
std::string test_string = "foo";
auto string = root.init<decltype("test_string"_t)>();
string.set(test_string);
auto string_name = root.init<decltype("test_name"_t)>();
string_name.set("test_name"_t.view());
root.init<decltype("test_bool"_t)>().set(false);
JsonCodec codec;
RingBuffer temp_buffer;
codec.encode<TestStruct>(root.asReader(), temp_buffer);
std::string expected_result{"{\"test_uint\":23,\"test_string\":\"foo\",\"test_name\":\"test_name\",\"test_bool\":false}"};
std::string tmp_string = temp_buffer.toString();
GIN_EXPECT(tmp_string == expected_result, std::string{"Bad encoding:\n"} + tmp_string);
}
typedef gin::MessageUnion<
gin::MessageUnionMember<gin::MessagePrimitive<uint32_t>, decltype("test_uint"_t)>,
gin::MessageUnionMember<gin::MessagePrimitive<std::string>, decltype("test_string"_t)>
> TestUnion;
GIN_TEST("JSON Union Encoding"){
using namespace gin;
{
auto builder = heapMessageBuilder();
auto root = builder.initRoot<TestUnion>();
auto test_uint = root.init<decltype("test_uint"_t)>();
test_uint.set(23);
RingBuffer buffer;
JsonCodec codec;
Error error = codec.encode<TestUnion>(root.asReader(), buffer);
GIN_EXPECT(!error.failed(), error.message());
std::string expected_result{"{\"test_uint\":23}"};
std::string tmp_string = buffer.toString();
GIN_EXPECT(tmp_string == expected_result, std::string{"Bad encoding:\n"} + tmp_string);
}
{
auto builder = heapMessageBuilder();
auto root = builder.initRoot<TestUnion>();
auto test_string = root.init<decltype("test_string"_t)>();
test_string.set("foo");
RingBuffer buffer;
JsonCodec codec;
Error error = codec.encode<TestUnion>(root.asReader(), buffer);
GIN_EXPECT(!error.failed(), error.message());
std::string expected_result{"{\"test_string\":\"foo\"}"};
std::string tmp_string = buffer.toString();
GIN_EXPECT(tmp_string == expected_result, std::string{"Bad encoding:\n"} + tmp_string);
}
}
GIN_TEST("JSON Struct Decoding"){
std::string json_string = R"(
{
"test_string" :"banana" ,
"test_uint" : 5,
"test_name" : "keldu",
"test_bool" : true
})";
auto builder = heapMessageBuilder();
TestStruct::Builder root = builder.initRoot<TestStruct>();
JsonCodec codec;
RingBuffer temp_buffer;
temp_buffer.push(*reinterpret_cast<const uint8_t*>(json_string.data()), json_string.size());
Error error = codec.decode<TestStruct>(root, temp_buffer);
GIN_EXPECT( !error.failed(), error.message() );
auto reader = root.asReader();
GIN_EXPECT( reader.get<decltype("test_string"_t)>().get() == "banana", "Test String has wrong value" );
GIN_EXPECT( reader.get<decltype("test_uint"_t)>().get() == 5, "Test Unsigned has wrong value" );
GIN_EXPECT( reader.get<decltype("test_name"_t)>().get() == "keldu", "Test Name has wrong value" );
GIN_EXPECT( reader.get<decltype("test_bool"_t)>().get() == true, "Test Bool has wrong value" );
}
GIN_TEST("JSON List Decoding"){
std::string json_string = R"(
[
12,
"free"
])";
auto builder = heapMessageBuilder();
TestList::Builder root = builder.initRoot<TestList>();
JsonCodec codec;
RingBuffer temp_buffer;
temp_buffer.push(*reinterpret_cast<const uint8_t*>(json_string.data()), json_string.size());
Error error = codec.decode<TestList>(root, temp_buffer);
GIN_EXPECT( !error.failed(), error.message() );
auto reader = root.asReader();
GIN_EXPECT( reader.get<0>().get() == 12, "Test Unsigned has wrong value" );
GIN_EXPECT( reader.get<1>().get() == "free", "Test String has wrong value" );
}
typedef MessageStruct<
MessageStructMember<MessagePrimitive<uint32_t>, decltype("test_uint"_t)>,
MessageStructMember<TestStruct, decltype("test_struct"_t)>,
MessageStructMember<MessagePrimitive<std::string>, decltype("test_name"_t)>
> TestStructDepth;
GIN_TEST("JSON Struct Decoding Two layer"){
std::string json_string = R"(
{
"test_struct" :{
"test_string" : "banana",
"test_uint": 40,
"test_name":"HaDiKo",
"test_bool" :false
},
"test_uint": 5,
"test_name" : "keldu"
})";
auto builder = heapMessageBuilder();
TestStructDepth::Builder root = builder.initRoot<TestStructDepth>();
JsonCodec codec;
RingBuffer temp_buffer;
temp_buffer.push(*reinterpret_cast<const uint8_t*>(json_string.data()), json_string.size());
Error error = codec.decode<TestStructDepth>(root, temp_buffer);
GIN_EXPECT( !error.failed(), error.message() );
auto reader = root.asReader();
auto inner_reader = reader.get<decltype("test_struct"_t)>();
GIN_EXPECT( inner_reader.get<decltype("test_string"_t)>().get() == "banana", "Test String has wrong value" );
GIN_EXPECT( inner_reader.get<decltype("test_uint"_t)>().get() == 40, "Test Unsigned has wrong value" );
GIN_EXPECT( inner_reader.get<decltype("test_name"_t)>().get() == "HaDiKo", "Test Name has wrong value" );
GIN_EXPECT( inner_reader.get<decltype("test_bool"_t)>().get() == false, "Test Bool has wrong value" );
GIN_EXPECT( reader.get<decltype("test_uint"_t)>().get() == 5, "Test Unsigned has wrong value" );
GIN_EXPECT( reader.get<decltype("test_name"_t)>().get() == "keldu", "Test Name has wrong value" );
}
typedef MessageStruct<
MessageStructMember<
MessageStruct<
MessageStructMember< MessagePrimitive<std::string>, decltype("title"_t)>,
MessageStructMember<
MessageStruct<
MessageStructMember<MessagePrimitive<std::string>,decltype("title"_t)>,
MessageStructMember<
MessageStruct<
MessageStructMember<
MessageStruct<
MessageStructMember<MessagePrimitive<std::string>,decltype("ID"_t)>,
MessageStructMember<MessagePrimitive<std::string>,decltype("SortAs"_t)>,
MessageStructMember<MessagePrimitive<std::string>,decltype("GlossTerm"_t)>,
MessageStructMember<MessagePrimitive<std::string>,decltype("Acronym"_t)>,
MessageStructMember<MessagePrimitive<std::string>,decltype("Abbrev"_t)>,
MessageStructMember<
MessageStruct<
MessageStructMember<MessagePrimitive<std::string>, decltype("para"_t)>,
MessageStructMember<
MessageList<
MessagePrimitive<std::string>,
MessagePrimitive<std::string>
>
, decltype("GlossSeeAlso"_t)>
>
, decltype("GlossDef"_t)>,
MessageStructMember<MessagePrimitive<std::string>, decltype("GlossSee"_t)>
>
, decltype("GlossEntry"_t)>
>
, decltype("GlossList"_t)>
>
, decltype("GlossDiv"_t)>
>
, decltype("glossary"_t)>
> TestJsonOrgExample;
GIN_TEST ("JSON.org Decoding Example"){
auto builder = heapMessageBuilder();
TestJsonOrgExample::Builder root = builder.initRoot<TestJsonOrgExample>();
JsonCodec codec;
RingBuffer temp_buffer;
temp_buffer.push(*reinterpret_cast<const uint8_t*>(gin::json_org_example.data()), gin::json_org_example.size());
Error error = codec.decode<TestJsonOrgExample>(root, temp_buffer);
GIN_EXPECT(!error.failed(), error.message());
auto reader = root.asReader();
auto glossary_reader = reader.get<decltype("glossary"_t)>();
GIN_EXPECT(glossary_reader.get<decltype("title"_t)>().get() == "example glossary", "Bad glossary title");
auto gloss_div_reader = glossary_reader.get<decltype("GlossDiv"_t)>();
GIN_EXPECT(gloss_div_reader.get<decltype("title"_t)>().get() == "S", "bad gloss div value" );
auto gloss_list_reader = gloss_div_reader.get<decltype("GlossList"_t)>();
auto gloss_entry_reader = gloss_list_reader.get<decltype("GlossEntry"_t)>();
GIN_EXPECT(gloss_entry_reader.get<decltype("ID"_t)>().get() == "SGML", "bad ID value" );
GIN_EXPECT(gloss_entry_reader.get<decltype("SortAs"_t)>().get() == "SGML", "bad SortAs value" );
GIN_EXPECT(gloss_entry_reader.get<decltype("GlossTerm"_t)>().get() == "Standard Generalized Markup Language", "bad GlossTerm value" );
GIN_EXPECT(gloss_entry_reader.get<decltype("Acronym"_t)>().get() == "SGML", "bad Acronym value" );
GIN_EXPECT(gloss_entry_reader.get<decltype("Abbrev"_t)>().get() == "ISO 8879:1986", "bad Abbrev value" );
GIN_EXPECT(gloss_entry_reader.get<decltype("GlossSee"_t)>().get() == "markup", "bad GlossSee value" );
auto gloss_def_reader = gloss_entry_reader.get<decltype("GlossDef"_t)>();
GIN_EXPECT(gloss_def_reader.get<decltype("para"_t)>().get() == "A meta-markup language, used to create markup languages such as DocBook.", "para value wrong");
auto gloss_see_also_reader = gloss_def_reader.get<decltype("GlossSeeAlso"_t)>();
GIN_EXPECT(gloss_see_also_reader.get<0>().get() == "GML", "List 0 value wrong");
GIN_EXPECT(gloss_see_also_reader.get<1>().get() == "XML", "List 1 value wrong");
// (void) gloss_div_reader;
}
}

View File

@ -4,50 +4,50 @@
#include <string>
#include "source/kelgin/message.h"
using gin::MessageList;
using gin::MessageStruct;
using gin::MessageStructMember;
using gin::MessagePrimitive;
using gin::heapMessageBuilder;
#include "source/kelgin/schema.h"
namespace {
typedef MessageList<MessagePrimitive<uint32_t>, MessagePrimitive<std::string> > TestList;
namespace schema {
using namespace gin::schema;
}
using TestTuple = schema::Tuple<schema::UInt32, schema::String>;
GIN_TEST("MessageList"){
std::string test_string_1 = "banana";
auto builder = heapMessageBuilder();
auto root = builder.initRoot<TestList>();
auto uint = root.init<0>();
auto root = gin::heapMessageRoot<TestTuple>();
auto builder = root.build();
auto uint = builder.init<0>();
uint.set(10);
auto string = root.init<1>();
auto string = builder.init<1>();
string.set(test_string_1);
auto root_reader = root.asReader();
auto uint_reader = root_reader.get<0>();
auto string_reader = root_reader.get<1>();
auto reader = root.read();
auto uint_reader = reader.get<0>();
auto string_reader = reader.get<1>();
GIN_EXPECT( uint_reader.get() == 10 && string_reader.get() == test_string_1, "wrong values");
}
typedef MessageList<MessageList<MessagePrimitive<uint32_t>, MessagePrimitive<std::string>>, MessagePrimitive<std::string> > NestedTestList;
using NestedTestTuple = schema::Tuple<schema::Tuple<schema::UInt32, schema::String>, schema::String>;
GIN_TEST("MessageList nested"){
std::string test_string_1 = "banana";
std::string test_string_2 = "bat";
auto builder = heapMessageBuilder();
auto root = builder.initRoot<NestedTestList>();
auto inner_list = root.init<0>();
auto root = gin::heapMessageRoot<NestedTestTuple>();
auto builder = root.build();
auto inner_list = builder.init<0>();
auto uint = inner_list.init<0>();
uint.set(20);
auto inner_string = inner_list.init<1>();
inner_string.set(test_string_2);
auto string = root.init<1>();
auto string = builder.init<1>();
string.set(test_string_1);
auto root_reader = root.asReader();
auto root_reader = root.read();
auto inner_reader = root_reader.get<0>();
auto uint_reader = inner_reader.get<0>();
auto inner_string_reader = inner_reader.get<1>();
@ -56,30 +56,33 @@ GIN_TEST("MessageList nested"){
GIN_EXPECT(uint_reader.get() == 20 && inner_string_reader.get() == test_string_2 && string_reader.get() == test_string_1, "wrong values");
}
typedef MessageStruct<
MessageStructMember<MessagePrimitive<uint32_t>, decltype("test_uint"_t)>,
MessageStructMember<MessagePrimitive<std::string>, decltype("test_string"_t)>,
MessageStructMember<MessagePrimitive<std::string>, decltype("test_name"_t)>
> TestStruct;
using TestStruct = schema::Struct<
schema::NamedMember<schema::UInt32, "test_uint">,
schema::NamedMember<schema::String, "test_string">,
schema::NamedMember<schema::String, "test_name">
>;
GIN_TEST("MessageStruct"){
std::string test_string = "foo";
auto builder = heapMessageBuilder();
auto root = builder.initRoot<TestStruct>();
auto uint = root.init<decltype("test_uint"_t)>();
auto root = gin::heapMessageRoot<TestStruct>();
auto builder = root.build();
auto uint = builder.init<"test_uint">();
uint.set(23);
auto string = root.init<decltype("test_string"_t)>();
auto string = builder.init<"test_string">();
string.set(test_string);
auto string_name = root.init<decltype("test_name"_t)>();
string_name.set(&"test_name"_t.data[0]);
auto string_name = builder.init<"test_name">();
string_name.set("test_name");
auto reader = root.asReader();
auto uint_reader = reader.get<decltype("test_uint"_t)>();
auto string_reader = reader.get<decltype("test_string"_t)>();
auto name_reader = reader.get<decltype("test_name"_t)>();
auto reader = root.read();
auto uint_reader = reader.get<"test_uint">();
auto string_reader = reader.get<"test_string">();
auto name_reader = reader.get<"test_name">();
/*
* Set string to another value to guarantee no changes
*/
test_string = "foo2";
GIN_EXPECT(uint_reader.get() == 23 && string_reader.get() != test_string && string_reader.get() == "foo" && name_reader.get() == "test_name", "wrong values");
}
}
}

View File

@ -5,54 +5,59 @@
#include <iostream>
namespace {
typedef gin::MessagePrimitive<uint32_t> TestSize;
namespace schema {
using namespace gin::schema;
}
using TestSize = schema::UInt32;
typedef gin::MessageList<gin::MessagePrimitive<uint32_t>, gin::MessagePrimitive<uint16_t>> TestList;
using TestTuple = schema::Tuple<schema::UInt32, schema::UInt16>;
typedef gin::MessageStruct<
gin::MessageStructMember<gin::MessagePrimitive<uint32_t>, decltype("test_uint"_t)>,
gin::MessageStructMember<gin::MessagePrimitive<std::string>, decltype("test_string"_t)>,
gin::MessageStructMember<gin::MessagePrimitive<std::string>, decltype("test_name"_t)>
> TestStruct;
using TestStruct = schema::Struct<
schema::NamedMember<schema::UInt32, "test_uint">,
schema::NamedMember<schema::String, "test_string">,
schema::NamedMember<schema::String, "test_name">
>;
typedef gin::MessageUnion<
gin::MessageUnionMember<gin::MessagePrimitive<uint32_t>, decltype("test_uint"_t)>,
gin::MessageUnionMember<gin::MessagePrimitive<std::string>, decltype("test_string"_t)>
> TestUnion;
using TestUnion = schema::Union<
schema::NamedMember<schema::UInt32, "test_uint">,
schema::NamedMember<schema::String, "test_string">
>;
GIN_TEST("Primitive Encoding"){
using namespace gin;
uint32_t value = 5;
auto builder = heapMessageBuilder();
auto root = builder.initRoot<TestSize>();
auto root = heapMessageRoot<TestSize>();
auto builder = root.build();
root.set(value);
builder.set(value);
RingBuffer temp_buffer;
ProtoKelCodec codec;
Error error = ProtoKelEncodeImpl<TestSize>::encode(root.asReader(), temp_buffer);
Error error = codec.encode<TestSize>(root.read(), temp_buffer);
GIN_EXPECT(!error.failed(), error.message());
GIN_EXPECT(temp_buffer.readCompositeLength() == sizeof(value), "Bad Size: " + std::to_string(temp_buffer.readCompositeLength()));
GIN_EXPECT(temp_buffer[0] == 5 && temp_buffer[1] == 0 && temp_buffer[2] == 0 && temp_buffer[3] == 0, "Wrong encoded values");
GIN_EXPECT(temp_buffer.readCompositeLength() == (sizeof(value)+sizeof(msg_packet_length_t)), "Bad Size: " + std::to_string(temp_buffer.readCompositeLength()));
constexpr size_t pkt_shift = sizeof(msg_packet_length_t);
GIN_EXPECT(temp_buffer[pkt_shift] == 5 && temp_buffer[pkt_shift+1] == 0 && temp_buffer[pkt_shift+2] == 0 && temp_buffer[pkt_shift+3] == 0, "Wrong encoded values");
}
GIN_TEST("List Encoding"){
using namespace gin;
auto builder = heapMessageBuilder();
auto root = builder.initRoot<TestList>();
auto root = heapMessageRoot<TestTuple>();
auto builder = root.build();
auto first = root.init<0>();
auto first = builder.init<0>();
first.set(2135231);
auto second = root.init<1>();
auto second = builder.init<1>();
second.set(43871);
RingBuffer buffer;
ProtoKelCodec codec;
Error error = codec.encode<TestList>(root.asReader(), buffer);
Error error = codec.encode<TestTuple>(root.read(), buffer);
GIN_EXPECT(!error.failed(), error.message());
GIN_EXPECT(buffer.readCompositeLength() == 14, "Bad Size: " + std::to_string(buffer.readCompositeLength()));
@ -62,23 +67,23 @@ GIN_TEST("List Encoding"){
GIN_TEST("Struct Encoding"){
using namespace gin;
auto builder = heapMessageBuilder();
auto root = builder.initRoot<TestStruct>();
auto root = heapMessageRoot<TestStruct>();
auto builder = root.build();
auto test_uint = root.init<decltype("test_uint"_t)>();
auto test_uint = builder.init<"test_uint">();
test_uint.set(23);
std::string test_string = "foo";
auto string = root.init<decltype("test_string"_t)>();
auto string = builder.init<"test_string">();
string.set(test_string);
auto string_name = root.init<decltype("test_name"_t)>();
string_name.set("test_name"_t.view());
auto string_name = builder.init<"test_name">();
string_name.set("test_name");
RingBuffer buffer;
ProtoKelCodec codec;
Error error = codec.encode<TestStruct>(root.asReader(), buffer);
Error error = codec.encode<TestStruct>(builder.asReader(), buffer);
GIN_EXPECT(!error.failed(), error.message());
GIN_EXPECT(buffer.readCompositeLength() == 40, "Bad Size: " + std::to_string(buffer.readCompositeLength()));
@ -89,16 +94,16 @@ GIN_TEST("Struct Encoding"){
GIN_TEST("Union Encoding"){
using namespace gin;
{
auto builder = heapMessageBuilder();
auto root = builder.initRoot<TestUnion>();
auto root = heapMessageRoot<TestUnion>();
auto builder = root.build();
auto test_uint = root.init<decltype("test_uint"_t)>();
auto test_uint = builder.init<"test_uint">();
test_uint.set(23);
RingBuffer buffer;
ProtoKelCodec codec;
Error error = codec.encode<TestUnion>(root.asReader(), buffer);
Error error = codec.encode<TestUnion>(builder.asReader(), buffer);
GIN_EXPECT(!error.failed(), error.message());
GIN_EXPECT(buffer.readCompositeLength() == 16, "Bad Size: " + std::to_string(buffer.readCompositeLength()));
@ -106,16 +111,16 @@ GIN_TEST("Union Encoding"){
== buffer.toHex(), "Not equal encoding:\n"+buffer.toHex());
}
{
auto builder = heapMessageBuilder();
auto root = builder.initRoot<TestUnion>();
auto root = heapMessageRoot<TestUnion>();
auto builder = root.build();
auto test_string = root.init<decltype("test_string"_t)>();
auto test_string = builder.init<"test_string">();
test_string.set("foo");
RingBuffer buffer;
ProtoKelCodec codec;
Error error = codec.encode<TestUnion>(root.asReader(), buffer);
Error error = codec.encode<TestUnion>(builder.asReader(), buffer);
GIN_EXPECT(!error.failed(), error.message());
GIN_EXPECT(buffer.readCompositeLength() == 23, "Bad Size: " + std::to_string(buffer.readCompositeLength()));
@ -124,7 +129,7 @@ GIN_TEST("Union Encoding"){
}
}
GIN_TEST("List Decoding"){
GIN_TEST("Tuple Decoding"){
using namespace gin;
const uint8_t buffer_raw[] = {0x06, 0, 0, 0, 0, 0, 0, 0, 0xbf, 0x94, 0x20, 0x00, 0x5f, 0xab};
@ -133,13 +138,13 @@ GIN_TEST("List Decoding"){
ProtoKelCodec codec;
auto builder = heapMessageBuilder();
auto root = builder.initRoot<TestList>();
auto root = heapMessageRoot<TestTuple>();
auto builder = root.build();
Error error = codec.decode<TestList>(root, buffer);
Error error = codec.decode<TestTuple>(builder, buffer);
GIN_EXPECT(!error.failed(), error.message());
auto reader = root.asReader();
auto reader = builder.asReader();
auto first = reader.get<0>();
auto second = reader.get<1>();
@ -156,15 +161,15 @@ GIN_TEST("Struct Decoding"){
ProtoKelCodec codec;
auto builder = heapMessageBuilder();
auto root = builder.initRoot<TestStruct>();
auto root = heapMessageRoot<TestStruct>();
auto builder = root.build();
Error error = codec.decode<TestStruct>(root, buffer);
auto reader = root.asReader();
Error error = codec.decode<TestStruct>(builder, buffer);
auto reader = builder.asReader();
auto foo_string = reader.get<decltype("test_string"_t)>();
auto test_uint = reader.get<decltype("test_uint"_t)>();
auto test_name = reader.get<decltype("test_name"_t)>();
auto foo_string = reader.get<"test_string">();
auto test_uint = reader.get<"test_uint">();
auto test_name = reader.get<"test_name">();
GIN_EXPECT(!error.failed(), error.message());
GIN_EXPECT(foo_string.get() == "foo" && test_uint.get() == 23 && test_name.get() == "test_name", "Values not correctly decoded");
@ -179,15 +184,15 @@ GIN_TEST("Union Decoding"){
ProtoKelCodec codec;
auto builder = heapMessageBuilder();
auto root = builder.initRoot<TestUnion>();
auto reader = root.asReader();
auto root = heapMessageRoot<TestUnion>();
auto builder = root.build();
auto reader = builder.asReader();
Error error = codec.decode<TestUnion>(root, buffer);
Error error = codec.decode<TestUnion>(builder, buffer);
GIN_EXPECT(!error.failed(), error.message());
GIN_EXPECT(reader.holdsAlternative<decltype("test_string"_t)>(), "Wrong union value");
auto str_rd = reader.get<decltype("test_string"_t)>();
GIN_EXPECT(reader.hasAlternative<"test_string">(), "Wrong union value");
auto str_rd = reader.get<"test_string">();
GIN_EXPECT(str_rd.get() == "foo", "Wrong value: " + std::string{str_rd.get()});
}
}