Merge branch 'fb-schema' into dev
This commit is contained in:
commit
7192a8a5b6
|
@ -112,9 +112,6 @@ SpacesInCStyleCastParentheses: false
|
|||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 4
|
||||
UseTab: ForContinuationAndIndentation
|
||||
...
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
1094
source/kelgin/json.h
1094
source/kelgin/json.h
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})";
|
||||
}
|
289
test/json.cpp
289
test/json.cpp
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue