Merge branch 'dev'
commit
7824acf553
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020 Claudius "keldu" Holeksa
|
||||
Copyright (c) 2020,2021 Claudius "keldu" Holeksa
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Asynchronous framework mostly inspired by [Capn'Proto](https://github.com/capnproto/capnproto) with the key difference of not
|
||||
using Promises, but more reusable Pipelines/Conveyors. This introduces some challenges since I can't assume that only one
|
||||
element gets passed along the chain, but it is managable. The advantage is that you have zero heap overhead by recreating the chain after every use.
|
||||
element gets passed along the chain, but it is managable. The advantage is that you have zero heap overhead by not recreating the chain after every use.
|
||||
|
||||
Very early stage. I am currently rewriting my software to find a good interface solution by checking if I am comfortable with the current design.
|
||||
|
||||
|
|
|
@ -73,7 +73,11 @@ public:
|
|||
* Initialize a member by index
|
||||
*/
|
||||
template <size_t i>
|
||||
typename Container::template ElementType<i>::Builder init() {
|
||||
typename std::enable_if<
|
||||
!SchemaIsArray<
|
||||
typename MessageParameterPackType<i, V...>::Type>::Value,
|
||||
typename Container::template ElementType<i>::Builder>::type
|
||||
init() {
|
||||
return typename Container::template ElementType<i>::Builder{
|
||||
message.container.template get<i>()};
|
||||
}
|
||||
|
@ -83,14 +87,49 @@ public:
|
|||
* This is the preferred method for schema::Struct messages
|
||||
*/
|
||||
template <StringLiteral Literal>
|
||||
typename Container::template ElementType<
|
||||
MessageParameterKeyPackIndex<Literal, Keys...>::Value>::Builder
|
||||
typename std::enable_if<
|
||||
!SchemaIsArray<typename MessageParameterPackType<
|
||||
MessageParameterKeyPackIndex<Literal, Keys...>::Value,
|
||||
V...>::Type>::Value,
|
||||
typename Container::template ElementType<
|
||||
MessageParameterKeyPackIndex<Literal,
|
||||
Keys...>::Value>::Builder>::type
|
||||
init() {
|
||||
constexpr size_t i =
|
||||
MessageParameterKeyPackIndex<Literal, Keys...>::Value;
|
||||
|
||||
return init<i>();
|
||||
}
|
||||
|
||||
template <size_t i>
|
||||
typename std::enable_if<
|
||||
SchemaIsArray<
|
||||
typename MessageParameterPackType<i, V...>::Type>::Value,
|
||||
typename Container::template ElementType<i>::Builder>::type
|
||||
init(size_t size) {
|
||||
auto array_builder =
|
||||
typename Container::template ElementType<i>::Builder{
|
||||
message.container.template get<i>(), size};
|
||||
return array_builder;
|
||||
}
|
||||
|
||||
/*
|
||||
* Version for array schema type
|
||||
*/
|
||||
template <StringLiteral Literal>
|
||||
typename std::enable_if<
|
||||
SchemaIsArray<typename MessageParameterPackType<
|
||||
MessageParameterKeyPackIndex<Literal, Keys...>::Value,
|
||||
V...>::Type>::Value,
|
||||
typename Container::template ElementType<
|
||||
MessageParameterKeyPackIndex<Literal,
|
||||
Keys...>::Value>::Builder>::type
|
||||
init(size_t size) {
|
||||
constexpr size_t i =
|
||||
MessageParameterKeyPackIndex<Literal, Keys...>::Value;
|
||||
|
||||
return init<i>(size);
|
||||
}
|
||||
};
|
||||
|
||||
class Reader {
|
||||
|
@ -162,20 +201,58 @@ public:
|
|||
Reader asReader() { return Reader{message}; }
|
||||
|
||||
template <size_t i>
|
||||
typename Container::template ElementType<i>::Builder init() {
|
||||
typename std::enable_if<
|
||||
!SchemaIsArray<
|
||||
typename MessageParameterPackType<i, V...>::Type>::Value,
|
||||
typename Container::template ElementType<i>::Builder>::type
|
||||
|
||||
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
|
||||
typename std::enable_if<
|
||||
!SchemaIsArray<typename MessageParameterPackType<
|
||||
MessageParameterKeyPackIndex<Literal, Keys...>::Value,
|
||||
V...>::Type>::Value,
|
||||
typename Container::template ElementType<
|
||||
MessageParameterKeyPackIndex<Literal,
|
||||
Keys...>::Value>::Builder>::type
|
||||
init() {
|
||||
constexpr size_t i =
|
||||
MessageParameterKeyPackIndex<Literal, Keys...>::Value;
|
||||
|
||||
return init<i>();
|
||||
}
|
||||
|
||||
/*
|
||||
* If Schema is Array
|
||||
*/
|
||||
template <size_t i>
|
||||
typename std::enable_if<
|
||||
SchemaIsArray<
|
||||
typename MessageParameterPackType<i, V...>::Type>::Value,
|
||||
typename Container::template ElementType<i>::Builder>::type
|
||||
init(size_t size) {
|
||||
return typename Container::template ElementType<i>::Builder{
|
||||
message.container.template get<i>(), size};
|
||||
}
|
||||
|
||||
template <StringLiteral Literal>
|
||||
typename std::enable_if<
|
||||
SchemaIsArray<typename MessageParameterPackType<
|
||||
MessageParameterKeyPackIndex<Literal, Keys...>::Value,
|
||||
V...>::Type>::Value,
|
||||
typename Container::template ElementType<
|
||||
MessageParameterKeyPackIndex<Literal,
|
||||
Keys...>::Value>::Builder>::type
|
||||
init(size_t size) {
|
||||
constexpr size_t i =
|
||||
MessageParameterKeyPackIndex<Literal, Keys...>::Value;
|
||||
|
||||
return init<i>(size);
|
||||
}
|
||||
};
|
||||
|
||||
class Reader {
|
||||
|
@ -219,11 +296,8 @@ public:
|
|||
|
||||
/*
|
||||
* 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>
|
||||
template <class T, class Container>
|
||||
class Message<schema::Array<T>, Container> final : public MessageBase {
|
||||
private:
|
||||
using SchemaType = schema::Array<T>;
|
||||
|
@ -241,35 +315,42 @@ public:
|
|||
class Reader;
|
||||
class Builder {
|
||||
private:
|
||||
MessageType & message;
|
||||
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>()};
|
||||
Builder(MessageType &msg, size_t size) : message{msg} {
|
||||
if (size > 0) {
|
||||
message.container.resize(size);
|
||||
}
|
||||
}
|
||||
|
||||
Reader asReader() { return Reader{message}; }
|
||||
|
||||
typename Container::ElementType::Builder init(size_t i) {
|
||||
return typename Container::ElementType::Builder{
|
||||
message.container.get(i)};
|
||||
}
|
||||
|
||||
size_t size() const { return message.container.size(); }
|
||||
};
|
||||
|
||||
class Reader {
|
||||
private:
|
||||
MessageType& message;
|
||||
MessageType &message;
|
||||
|
||||
public:
|
||||
Reader(MessageType& msg):message{msg}{}
|
||||
Reader(MessageType &msg) : message{msg} {}
|
||||
|
||||
Builder asBuilder(){return Builder{message};}
|
||||
Builder asBuilder() { return Builder{message, 0}; }
|
||||
|
||||
template<size_t i>
|
||||
typename Container::MessageType::Reader get(){
|
||||
return typename
|
||||
Container::MessageType::Reader{message.container.get<i>()};
|
||||
typename Container::ElementType::Reader get(size_t i) {
|
||||
return typename Container::ElementType::Reader{
|
||||
message.container.get(i)};
|
||||
}
|
||||
|
||||
size_t size() const { return message.container.size(); }
|
||||
};
|
||||
};
|
||||
*/
|
||||
|
||||
/*
|
||||
* Tuple message class. Wrapper around a tuple schema
|
||||
|
@ -299,10 +380,24 @@ public:
|
|||
Reader asReader() { return Reader{message}; }
|
||||
|
||||
template <size_t i>
|
||||
typename Container::template ElementType<i>::Builder init() {
|
||||
typename std::enable_if<
|
||||
!SchemaIsArray<
|
||||
typename MessageParameterPackType<i, T...>::Type>::Value,
|
||||
typename Container::template ElementType<i>::Builder>::type
|
||||
init() {
|
||||
return typename Container::template ElementType<i>::Builder{
|
||||
message.container.template get<i>()};
|
||||
}
|
||||
|
||||
template <size_t i>
|
||||
typename std::enable_if<
|
||||
SchemaIsArray<
|
||||
typename MessageParameterPackType<i, T...>::Type>::Value,
|
||||
typename Container::template ElementType<i>::Builder>::type
|
||||
init(size_t size) {
|
||||
return typename Container::template ElementType<i>::Builder{
|
||||
message.container.template get<i>(), size};
|
||||
}
|
||||
};
|
||||
class Reader {
|
||||
private:
|
||||
|
@ -395,7 +490,9 @@ public:
|
|||
|
||||
Reader asReader() { return Reader{message}; }
|
||||
|
||||
void set(const std::string &str) { message.container.set(str); }
|
||||
void set(std::string &&str) { message.container.set(std::move(str)); }
|
||||
void set(const std::string_view str) { message.container.set(str); }
|
||||
void set(const char *str) { set(std::string_view{str}); }
|
||||
};
|
||||
|
||||
class Reader {
|
||||
|
@ -407,7 +504,7 @@ public:
|
|||
|
||||
Builder asBuilder() { return Builder{message}; }
|
||||
|
||||
std::string_view get() { return message.container.get(); }
|
||||
const std::string_view get() const { return message.container.get(); }
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -430,6 +527,28 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
template <class T, class Container>
|
||||
class HeapMessageRoot<schema::Array<T>, Container> {
|
||||
public:
|
||||
using Schema = schema::Array<T>;
|
||||
|
||||
private:
|
||||
Own<Message<Schema, Container>> root;
|
||||
|
||||
public:
|
||||
HeapMessageRoot(Own<Message<Schema, Container>> r) : root{std::move(r)} {}
|
||||
|
||||
typename Message<Schema, Container>::Builder build(size_t size) {
|
||||
assert(root);
|
||||
return typename Message<Schema, Container>::Builder{*root, size};
|
||||
}
|
||||
|
||||
typename Message<Schema, Container>::Reader read() {
|
||||
assert(root);
|
||||
return typename Message<Schema, Container>::Reader{*root};
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Minor helper for creating a message root
|
||||
*/
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
namespace gin {
|
||||
template <class T> class MessageContainer;
|
||||
|
||||
template <class T, class Container> class Message;
|
||||
template <class T, class Container = MessageContainer<T>> class Message;
|
||||
|
||||
template <size_t N, class... T> struct MessageParameterPackType;
|
||||
|
||||
|
@ -57,6 +57,14 @@ struct MessageParameterKeyPackIndex {
|
|||
"Provided StringLiteral doesn't exist in searched list");
|
||||
};
|
||||
|
||||
template <class T> struct SchemaIsArray {
|
||||
constexpr static bool Value = false;
|
||||
};
|
||||
|
||||
template <class T> struct SchemaIsArray<schema::Array<T>> {
|
||||
constexpr static bool Value = true;
|
||||
};
|
||||
|
||||
template <class... V, StringLiteral... Keys>
|
||||
class MessageContainer<schema::Struct<schema::NamedMember<V, Keys>...>> {
|
||||
private:
|
||||
|
@ -104,20 +112,24 @@ public:
|
|||
* Array storage
|
||||
*/
|
||||
|
||||
/*
|
||||
template<class T>
|
||||
class MessageContainer<schema::Array> {
|
||||
template <class T> class MessageContainer<schema::Array<T>> {
|
||||
private:
|
||||
using ValueType = std::vector<Message<T,MessageContainer<T>>>;
|
||||
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);
|
||||
using ElementType = Message<T, MessageContainer<T>>;
|
||||
|
||||
Message<T, MessageContainer<T>> &get(size_t index) {
|
||||
return values.at(index);
|
||||
}
|
||||
|
||||
void resize(size_t size) { values.resize(size); }
|
||||
|
||||
size_t size() const { return values.size(); }
|
||||
};
|
||||
*/
|
||||
|
||||
/*
|
||||
* Tuple storage
|
||||
|
@ -214,12 +226,15 @@ template <> class MessageContainer<schema::String> {
|
|||
public:
|
||||
using SchemaType = schema::String;
|
||||
using ValueType = std::string;
|
||||
using ValueViewType = std::string_view;
|
||||
|
||||
private:
|
||||
ValueType value;
|
||||
|
||||
public:
|
||||
void set(ValueType &&v) { value = std::move(v); }
|
||||
void set(const ValueType &v) { value = v; }
|
||||
void set(const ValueViewType v) { value = std::string{v}; }
|
||||
|
||||
const ValueType &get() const { return value; }
|
||||
};
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace gin {
|
|||
* bigger than uint32_t max. At least I hope noone would do this
|
||||
*/
|
||||
using msg_union_id_t = uint32_t;
|
||||
using msg_array_length_t = uint64_t;
|
||||
using msg_packet_length_t = uint64_t;
|
||||
|
||||
class ProtoKelCodec {
|
||||
|
@ -271,6 +272,48 @@ struct ProtoKelEncodeImpl<
|
|||
return sizeof(msg_union_id_t) + sizeMembers<0>(reader);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class Container>
|
||||
struct ProtoKelEncodeImpl<Message<schema::Array<T>, Container>> {
|
||||
static Error
|
||||
encode(typename Message<schema::Array<T>, Container>::Reader data,
|
||||
Buffer &buffer) {
|
||||
msg_array_length_t array_length = data.size();
|
||||
{
|
||||
Error error =
|
||||
StreamValue<msg_array_length_t>::encode(array_length, buffer);
|
||||
if (error.failed()) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < array_length; ++i) {
|
||||
Error error =
|
||||
ProtoKelEncodeImpl<typename Container::ElementType>::encode(
|
||||
data.get(i), buffer);
|
||||
if (error.failed()) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return noError();
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static size_t
|
||||
size(typename Message<schema::Array<T>, Container>::Reader data) {
|
||||
size_t members = sizeof(msg_array_length_t);
|
||||
for (size_t i = 0; i < data.size(); ++i) {
|
||||
members +=
|
||||
ProtoKelEncodeImpl<typename Container::ElementType>::size(
|
||||
data.get(i));
|
||||
}
|
||||
|
||||
return members;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Decode Implementations
|
||||
*/
|
||||
|
@ -436,6 +479,32 @@ struct ProtoKelDecodeImpl<
|
|||
}
|
||||
};
|
||||
|
||||
template <class T, class Container>
|
||||
struct ProtoKelDecodeImpl<Message<schema::Array<T>, Container>> {
|
||||
static Error
|
||||
decode(typename Message<schema::Array<T>, Container>::Builder data,
|
||||
Buffer &buffer) {
|
||||
msg_array_length_t array_length = 0;
|
||||
{
|
||||
Error error =
|
||||
StreamValue<msg_array_length_t>::decode(array_length, buffer);
|
||||
if (error.failed()) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < array_length; ++i) {
|
||||
Error error =
|
||||
ProtoKelDecodeImpl<typename Container::ElementType>::decode(
|
||||
data.init(i), buffer);
|
||||
if (error.failed()) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return noError();
|
||||
}
|
||||
};
|
||||
|
||||
template <class Schema, class Container>
|
||||
Error ProtoKelCodec::encode(typename Message<Schema, Container>::Reader reader,
|
||||
Buffer &buffer) {
|
||||
|
@ -487,7 +556,12 @@ Error ProtoKelCodec::decode(
|
|||
}
|
||||
|
||||
if (packet_length > limits.packet_size) {
|
||||
return criticalError("Packet size too big");
|
||||
return criticalError(
|
||||
[packet_length]() {
|
||||
return std::string{"Packet size too big: "} +
|
||||
std::to_string(packet_length);
|
||||
},
|
||||
"Packet size too big");
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace gin {
|
||||
/**
|
||||
* Helper class to encode/decode any primtive type into/from litte endian.
|
||||
|
@ -40,7 +42,7 @@ public:
|
|||
uint16_t raw = 0;
|
||||
|
||||
for (size_t i = 0; i < sizeof(T); ++i) {
|
||||
raw |= buffer.read(i) << (i * 8);
|
||||
raw |= (static_cast<uint16_t>(buffer.read(i)) << (i * 8));
|
||||
}
|
||||
memcpy(&val, &raw, sizeof(T));
|
||||
buffer.readAdvance(sizeof(T));
|
||||
|
@ -78,7 +80,7 @@ public:
|
|||
uint32_t raw = 0;
|
||||
|
||||
for (size_t i = 0; i < sizeof(T); ++i) {
|
||||
raw |= buffer.read(i) << (i * 8);
|
||||
raw |= (static_cast<uint32_t>(buffer.read(i)) << (i * 8));
|
||||
}
|
||||
memcpy(&val, &raw, sizeof(T));
|
||||
buffer.readAdvance(sizeof(T));
|
||||
|
@ -116,8 +118,9 @@ public:
|
|||
uint64_t raw = 0;
|
||||
|
||||
for (size_t i = 0; i < sizeof(T); ++i) {
|
||||
raw |= buffer.read(i) << (i * 8);
|
||||
raw |= (static_cast<uint64_t>(buffer.read(i)) << (i * 8));
|
||||
}
|
||||
|
||||
memcpy(&val, &raw, sizeof(T));
|
||||
buffer.readAdvance(sizeof(T));
|
||||
|
||||
|
@ -146,4 +149,4 @@ public:
|
|||
|
||||
template <typename T> using StreamValue = ShiftStreamValue<T>;
|
||||
|
||||
} // namespace gin
|
||||
} // namespace gin
|
||||
|
|
|
@ -182,7 +182,7 @@ GIN_TEST("Async Scheduling"){
|
|||
GIN_EXPECT(foo_30.value() == (std::string{"pre"} + std::to_string(33) + std::string{"post"}), "Values is not pre33post, but " + foo_30.value());
|
||||
}
|
||||
|
||||
GIN_TEST("Async detach"){
|
||||
GIN_TEST("Async Detach"){
|
||||
using namespace gin;
|
||||
|
||||
EventLoop event_loop;
|
||||
|
@ -227,4 +227,4 @@ GIN_TEST("Async Merge"){
|
|||
GIN_EXPECT(!wrong_value, std::string{"Expected values 10 or 11"});
|
||||
GIN_EXPECT(elements_passed == 3, std::string{"Expected 2 passed elements, got only "} + std::to_string(elements_passed));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace schema {
|
|||
|
||||
using TestTuple = schema::Tuple<schema::UInt32, schema::String>;
|
||||
|
||||
GIN_TEST("MessageList"){
|
||||
GIN_TEST("Message Tuple"){
|
||||
std::string test_string_1 = "banana";
|
||||
|
||||
auto root = gin::heapMessageRoot<TestTuple>();
|
||||
|
@ -21,7 +21,7 @@ GIN_TEST("MessageList"){
|
|||
auto uint = builder.init<0>();
|
||||
uint.set(10);
|
||||
auto string = builder.init<1>();
|
||||
string.set(test_string_1);
|
||||
string.set(std::string_view{test_string_1});
|
||||
|
||||
auto reader = root.read();
|
||||
auto uint_reader = reader.get<0>();
|
||||
|
@ -32,7 +32,7 @@ GIN_TEST("MessageList"){
|
|||
|
||||
using NestedTestTuple = schema::Tuple<schema::Tuple<schema::UInt32, schema::String>, schema::String>;
|
||||
|
||||
GIN_TEST("MessageList nested"){
|
||||
GIN_TEST("Message Tuple nested"){
|
||||
std::string test_string_1 = "banana";
|
||||
std::string test_string_2 = "bat";
|
||||
|
||||
|
@ -62,7 +62,7 @@ using TestStruct = schema::Struct<
|
|||
schema::NamedMember<schema::String, "test_name">
|
||||
>;
|
||||
|
||||
GIN_TEST("MessageStruct"){
|
||||
GIN_TEST("Message Struct"){
|
||||
std::string test_string = "foo";
|
||||
auto root = gin::heapMessageRoot<TestStruct>();
|
||||
auto builder = root.build();
|
||||
|
@ -83,6 +83,44 @@ GIN_TEST("MessageStruct"){
|
|||
*/
|
||||
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");
|
||||
GIN_EXPECT(uint_reader.get() == 23 && string_reader.get() != test_string && string_reader.get() == "foo" && name_reader.get() == "test_name", "Wrong values");
|
||||
}
|
||||
|
||||
using TestArray = schema::Array<schema::UInt32>;
|
||||
|
||||
void arrayCheck(gin::Message<TestArray>::Builder builder){
|
||||
auto one = builder.init(0);
|
||||
auto two = builder.init(1);
|
||||
auto three = builder.init(2);
|
||||
|
||||
one.set(24);
|
||||
two.set(45);
|
||||
three.set(1230);
|
||||
|
||||
auto reader = builder.asReader();
|
||||
|
||||
GIN_EXPECT(reader.get(0).get() == 24 && reader.get(1).get() == 45 && reader.get(2).get(), "Wrong values");
|
||||
}
|
||||
|
||||
GIN_TEST("Message Array"){
|
||||
auto root = gin::heapMessageRoot<TestArray>();
|
||||
|
||||
auto builder = root.build(3);
|
||||
|
||||
arrayCheck(builder);
|
||||
}
|
||||
|
||||
using TestArrayStruct = schema::Struct<
|
||||
schema::NamedMember<TestArray, "array">
|
||||
>;
|
||||
|
||||
GIN_TEST("Message Array in Struct"){
|
||||
auto root = gin::heapMessageRoot<TestArrayStruct>();
|
||||
|
||||
auto builder = root.build();
|
||||
|
||||
auto array = builder.init<"array">(3);
|
||||
|
||||
arrayCheck(array);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -195,4 +195,33 @@ GIN_TEST("Union Decoding"){
|
|||
auto str_rd = reader.get<"test_string">();
|
||||
GIN_EXPECT(str_rd.get() == "foo", "Wrong value: " + std::string{str_rd.get()});
|
||||
}
|
||||
|
||||
using TestArrayStruct = schema::Array<
|
||||
TestStruct
|
||||
>;
|
||||
|
||||
GIN_TEST("Array Encoding"){
|
||||
using namespace gin;
|
||||
|
||||
ProtoKelCodec codec;
|
||||
auto root = heapMessageRoot<TestArrayStruct>();
|
||||
auto builder = root.build(2);
|
||||
|
||||
auto one = builder.init(0);
|
||||
auto two = builder.init(1);
|
||||
|
||||
one.init<"test_uint">().set(4);
|
||||
one.init<"test_string">().set("foo");
|
||||
one.init<"test_name">().set("Fedor");
|
||||
|
||||
two.init<"test_uint">().set(9);
|
||||
two.init<"test_string">().set("bar");
|
||||
two.init<"test_name">().set("Bravo");
|
||||
|
||||
RingBuffer buffer;
|
||||
|
||||
Error error = codec.encode<TestArrayStruct>(root.read(), buffer);
|
||||
|
||||
GIN_EXPECT(!error.failed(), "Error occured");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue