summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudius "keldu" Holeksa <mail@keldu.de>2024-03-23 17:48:09 +0100
committerClaudius "keldu" Holeksa <mail@keldu.de>2024-03-23 17:48:09 +0100
commitc64c76e273084cfd5b8628fb268e803957fc3025 (patch)
treeebbc9bfa647617ba5c3c7c226f051a2933ccc3a5
parent7d096b9b3057617475d223330aaa6b321e0bd59a (diff)
codec, io_codec: forst and rpc work
-rw-r--r--modules/codec/c++/forst.hpp68
-rw-r--r--modules/codec/c++/forst.tmpl.hpp70
-rw-r--r--modules/codec/c++/rpc.hpp94
-rw-r--r--modules/codec/c++/schema.hpp85
-rw-r--r--modules/codec/c++/schema_factory.hpp29
-rw-r--r--modules/codec/tests/forst.cpp29
-rw-r--r--modules/codec/tests/schema.cpp69
-rw-r--r--modules/io_codec/c++/rpc.hpp4
8 files changed, 425 insertions, 23 deletions
diff --git a/modules/codec/c++/forst.hpp b/modules/codec/c++/forst.hpp
index 0e200cb..16f55c9 100644
--- a/modules/codec/c++/forst.hpp
+++ b/modules/codec/c++/forst.hpp
@@ -1,7 +1,10 @@
#pragma once
+#include <forstio/buffer.hpp>
+
#include "data.hpp"
+
namespace saw {
namespace encode {
struct KelForst {};
@@ -11,6 +14,7 @@ struct KelForst {};
#include "forst.tmpl.hpp"
namespace saw {
+template <>
class data<schema::String, encode::KelForst> {
private:
own<buffer> buff_;
@@ -20,13 +24,71 @@ public:
{}
};
+template<typename T, uint64_t N>
+class data<schema::Primitive<T,N>, encode::KelForst> {
+public:
+ using Schema = schema::Primitive<T,N>;
+private:
+ our<buffer> buff_;
+ uint64_t displacement_;
+public:
+ /**
+ * Constructor for root elements
+ */
+ data(our<buffer> buff):
+ buff_{std::move(buff)},
+ displacement_{0u}
+ {}
+
+ /**
+ * Constructor for child elements
+ */
+ data(our<buffer> buff, uint64_t dsp):
+ buff_{std::move(buff)},
+ displacement_{dsp}
+ {}
+
+ /**
+ * Get values
+ */
+ typename native_data_type<Schema>::type get(){
+ return {};
+ }
+
+ /**
+ * Set values
+ */
+ void set(typename native_data_type<Schema>::type val){
+ (void) val;
+ }
+};
+
template<typename... T, string_literal... Keys>
class data<schema::Struct<schema::Member<T,Keys>...>, encode::KelForst> {
private:
- own<buffer> buff_;
+ /**
+ * Buffer holding the whole packet
+ */
+ our<buffer> buff_;
+ /**
+ * Displacement to show the starting point
+ */
+ uint64_t displacement_;
public:
- data(own<buffer> buff):
- buff_{std::move(buff)}
+ /**
+ * Constructor for root elements
+ */
+ data(our<buffer> buff):
+ buff_{std::move(buff)},
+ displacement_{0u}
+ {}
+
+ /**
+ * Constructor for child elements
+ */
+ data(our<buffer> buff, uint64_t dsp):
+ buff_{std::move(buff)},
+ displacement_{dsp}
{}
};
}
diff --git a/modules/codec/c++/forst.tmpl.hpp b/modules/codec/c++/forst.tmpl.hpp
index 30d18ef..bfcafae 100644
--- a/modules/codec/c++/forst.tmpl.hpp
+++ b/modules/codec/c++/forst.tmpl.hpp
@@ -1,7 +1,75 @@
namespace saw {
namespace impl {
-struct forst_decode {
+/**
+ * This class provides
+ */
+template<typename Schema>
+struct forst_codec_info {
+ static_assert(always_false<Schema>, "Not supported.");
+};
+
+template<typename T, uint64_t N>
+struct forst_codec_info<schema::Primitive<T,N>> {
+private:
+public:
+ static constexpr uint64_t layers = 0u;
+};
+
+template<>
+struct forst_codec_info<schema::String> {
+public:
+ static constexpr uint64_t layers = 1u;
+};
+
+template<typename T, uint64_t N>
+struct forst_codec_info<schema::Array<T,N>> {
+public:
+ static constexpr uint64_t layers = 1u + forst_codec_info<T>::layers;
+};
+
+template<typename... Members>
+struct forst_codec_info<schema::Struct<Members...> > {
+public:
+ template<uint64_t i>
+ static uint64_t max_layers() constexpr noexcept {
+ if constexpr ( i < sizeof...(Members) ) {
+ using MT = typename parameter_pack_type<i, Members...>::type;
+
+ constexpr uint64_t layer_i = forst_codec_info<typename MT::Type>::layers;
+
+ constexpr uint64_t layer_next = max_layers<i+1u>();
+
+ constexpr uint64_t layer_val = layer_i > layer_next ? layer_i : layer_next;
+
+ return layer_val;
+ }
+ return 0u;
+ }
+public:
+ static constexpr uint64_t layers = max_layers<0>();
+};
+
+template<typename... T>
+struct forst_codec_info<schema::Tuple<T...>> {
+public:
+ template<uint64_t i>
+ static uint64_t max_layers() constexpr noexcept {
+ if constexpr ( i < sizeof...(Members) ) {
+ using MT = typename parameter_pack_type<i, T...>::type;
+
+ constexpr uint64_t layer_i = forst_codec_info<MT>::layers;
+
+ constexpr uint64_t layer_next = max_layers<i+1u>();
+
+ constexpr uint64_t layer_val = layer_i > layer_next ? layer_i : layer_next;
+
+ return layer_val;
+ }
+ return 0u;
+ }
+public:
+ static constexpr uint64_t layers = max_layers<0>();
};
}
}
diff --git a/modules/codec/c++/rpc.hpp b/modules/codec/c++/rpc.hpp
index 63ec014..9f59455 100644
--- a/modules/codec/c++/rpc.hpp
+++ b/modules/codec/c++/rpc.hpp
@@ -1,34 +1,98 @@
#pragma once
namespace saw {
+
+/**
+ *
+ */
+template<typename T, typename Remote>
+class remote_data {
+private:
+ id<T> id_;
+public:
+ remote_data(const id<T>& id):
+ id_{id}
+ {}
+
+ /**
+ * Wait until data arrives
+ */
+ error_or<data<T>> wait(wait_scope& wait);
+
+ /**
+ * Asynchronously wait for a result
+ */
+ conveyor<data<T>> on_receive();
+};
+
/**
+ * Client RPC reference structure
*/
template<typename T, typename Iface>
class rpc_client {
- template<typename... IdT>
- struct request {
- private:
- std::tuple<id<IdT>...> ids_;
- public:
- error_or<data<schema::Tuple<IdT>...>> wait();
- };
+ /**
+ * request the data from the remote
+ */
+ template<typename IdT>
+ remote_data<IdT> request_data(id<IdT> data);
- template<typename... IdT>
- request<IdT...> request_data(id<IdT>... data);
+ /**
+ * Determine type based on Name
+ */
+ template<string_literal Name>
+ error_or<
+ id<
+ typename schema_member_type<Name, Iface>::type
+ >
+ > call(data_or_id<Input> inp);
};
+/**
+ * Implementation of a remote server on the backend
+ */
template<typename T, typename Iface>
class rpc_server {
+private:
+ interface<Iface> iface_;
+public:
+ rpc_server(interface<Iface> iface):
+ iface_{std::move(iface)}
+ {}
};
+/**
+ * Representation of a remote.
+ * Partially similar to a network address
+ */
template<typename T>
-class remote {
- static_assert(always_false<T>, "Type of remote not supported");
+class remote_address {
+ static_assert(always_false<T>, "Type of remote not supported");
+
+
+};
+
+/**
+ * Reference Backend structure
+ */
+template<typename T>
+class remote_context {
+ static_assert(always_false<T>, "Type of backend not supported");
+
+ /**
+ * Resolves an address on the remote
+ */
+ conveyor<remote_address<T>> resolve_address();
- template<typename Iface>
- rpc_client<T,Iface> connect();
+ /**
+ * Connect to a remote
+ */
+ template<typename Iface>
+ conveyor<rpc_client<T,Iface>> connect(const remote_address<T>& addr);
- template<typename Iface>
- rpc_server<T,Iface> listen(network& net);
+ /**
+ * Start listening
+ */
+ template<typename Iface>
+ rpc_server<T,Iface> listen();
};
}
diff --git a/modules/codec/c++/schema.hpp b/modules/codec/c++/schema.hpp
index 37615c5..a992a84 100644
--- a/modules/codec/c++/schema.hpp
+++ b/modules/codec/c++/schema.hpp
@@ -135,6 +135,91 @@ struct Interface<Member<Function<Requests, Responses>,Names>...> {
// NOLINTEND
} // namespace schema
+
+template<typename T, typename Schema>
+struct schema_has_member{
+ static_assert(
+ always_false<T, Schema>,
+ "Not supported schema case");
+};
+
+/**
+ * Checks if identical type exists in schema structure
+ */
+template<typename T, typename... Members>
+struct schema_has_member<T, schema::Struct<Members...>> {
+private:
+ template<size_t i>
+ static constexpr bool value_element() {
+ if constexpr ( i < sizeof...(Members) ){
+ using MT = typename parameter_pack_type<i, Members...>::type;
+ if constexpr ( std::is_same_v<T,MT> ) {
+ return true;
+ } else {
+ return value_element<i+1u>();
+ }
+ }
+ return false;
+ }
+public:
+ static constexpr bool value = value_element<0>();
+};
+
+/**
+ *
+ */
+template<string_literal Key, typename Schema>
+struct schema_has_key {
+ static_assert(
+ always_false<Schema>,
+ "Not supported schema case");
+};
+
+template<string_literal Key, typename... Members>
+struct schema_has_key<Key, schema::Struct<Members...>> {
+private:
+ template<size_t i>
+ static constexpr bool value_element() {
+ if constexpr ( i < sizeof...(Members) ){
+ using MT = typename parameter_pack_type<i, Members...>::type;
+
+ if constexpr ( Key == MT::KeyLiteral ) {
+ return true;
+ }else{
+ return value_element<i+1u>();
+ }
+ }
+ return false;
+ }
+public:
+ static constexpr bool value = value_element<0>();
+};
+
+template<string_literal Name, typename Iface>
+struct schema_member_index {
+ static_assert(
+ always_false<Iface>,
+ "Not supported schema case");
+};
+
+template<string_literal Name, typename... MemberVals, string_literal... MemberKeys >
+struct schema_member_index<Name, schema::Interface<schema::Member<MemberVals, MemberKeys>...>> {
+ static constexpr uint64_t value = parameter_key_pack_index<Name, MemberKeys...>::value;
+};
+
+template<string_literal Name, typename Iface>
+struct schema_member_type {
+ static_assert(
+ always_false<Iface>,
+ "Not supported schema case");
+};
+
+template<string_literal Name, typename... MemberVals, string_literal... MemberKeys >
+struct schema_member_type<Name, schema::Interface<schema::Member<MemberVals, MemberKeys>...>> {
+
+ using type = typename parameter_pack_type<schema_member_index<Name, schema::Interface<schema::Member<MemberVals,MemberKeys>...>>::value, MemberVals...>::type;
+};
+
template <class T> struct is_struct {
constexpr static bool value = false;
};
diff --git a/modules/codec/c++/schema_factory.hpp b/modules/codec/c++/schema_factory.hpp
index 8896fdf..6b824f4 100644
--- a/modules/codec/c++/schema_factory.hpp
+++ b/modules/codec/c++/schema_factory.hpp
@@ -11,11 +11,35 @@ struct schema_factory {
template<typename... T, string_literal... Keys>
struct schema_factory<schema::Struct<schema::Member<T,Keys>...>> {
+private:
+public:
using Schema = schema::Struct<schema::Member<T,Keys>...>;
+
+ template<string_literal KA>
+ static constexpr bool has_key() noexcept {
+ return schema_has_key<KA, Schema>::value;
+ }
+
+ template<typename TA, string_literal KA>
+ static constexpr bool has_member() noexcept {
+ return schema_has_member<schema::Member<TA,KA>, Schema>::value;
+ }
+
+ template<typename TA, string_literal KA>
+ constexpr auto add_maybe() const noexcept {
+ if constexpr (!has_key<KA>()) {
+ return schema_factory<schema::Struct<schema::Member<T,Keys>..., schema::Member<TA,KA>>>{};
+ } else if constexpr (has_member<TA,KA>() ){
+ return schema_factory<schema::Struct<schema::Member<T,Keys>...> >{};
+ } else {
+ static_assert(always_false<TA>, "Struct already has the provided Key, but a mismatching Type");
+ }
+ }
template<typename TA, string_literal KA>
constexpr schema_factory<schema::Struct<schema::Member<T,Keys>...,schema::Member<TA,KA>>> add() const noexcept {
- return {};
+ static_assert(!has_key<KA>(), "Can't add member. Name is already in use.");
+ return {};
}
};
@@ -25,7 +49,8 @@ struct schema_factory<schema::Union<schema::Member<T,Keys>...>> {
template<typename TA, string_literal KA>
constexpr schema_factory<schema::Union<schema::Member<T,Keys>...,schema::Member<TA,KA>>> add() const noexcept {
- return {};
+ static_assert(!has_key<KA>(), "Can't add member. Name is already in use.");
+ return {};
}
};
diff --git a/modules/codec/tests/forst.cpp b/modules/codec/tests/forst.cpp
new file mode 100644
index 0000000..cb0442d
--- /dev/null
+++ b/modules/codec/tests/forst.cpp
@@ -0,0 +1,29 @@
+#include <forstio/test/suite.hpp>
+#include "../c++/data.hpp"
+#include "../c++/forst.hpp"
+
+#include <iostream>
+
+namespace {
+namespace schema {
+using namespace saw::schema;
+
+using TestStruct = Struct<
+ Member<String, "string">,
+ Member<UInt64, "number">,
+ Member<Int8, "signed">
+>;
+
+using TestArray = Array<
+ TestStruct
+>;
+
+SAW_TEST("Codec Forst Info"){
+ using namespace saw;
+
+ SAW_EXPECT(impl::forst_codec_info<schema::UInt64>::layers == 0, "Layer info is wrong");
+ SAW_EXPECT(impl::forst_codec_info<TestStruct>::layers == 1, "Layer info is wrong");
+ SAW_EXPECT(impl::forst_codec_info<TestArray>::layers == 2, "Layer info is wrong");
+}
+}
+}
diff --git a/modules/codec/tests/schema.cpp b/modules/codec/tests/schema.cpp
index 408a142..77d369d 100644
--- a/modules/codec/tests/schema.cpp
+++ b/modules/codec/tests/schema.cpp
@@ -3,6 +3,7 @@
#include <forstio/templates.hpp>
#include "../c++/schema.hpp"
#include "../c++/schema_hash.hpp"
+#include "../c++/schema_factory.hpp"
namespace {
template<typename T>
@@ -70,4 +71,72 @@ SAW_TEST("Schema Hashes"){
schema_test_pair<schema::HashIface, 3365712860>
>::check();
}
+
+SAW_TEST("Schema Factory Compiles"){
+ using namespace saw;
+
+ auto factory = build_schema<schema::Struct<>>();
+
+ auto str = factory
+ .add<schema::UInt32, "foo">()
+ .add<schema::Int16, "bar">()
+ .add_maybe<schema::Int16, "bar">()
+ .add_maybe<schema::String, "baz">()
+ ;
+
+ using FactorySchema = decltype(str)::Schema;
+
+ using Schema = schema::Struct<
+ schema::Member<schema::UInt32, "foo">,
+ schema::Member<schema::Int16, "bar">,
+ schema::Member<schema::String, "baz">
+ >;
+
+ SAW_EXPECT(is_struct<FactorySchema>::value, "Expected a struct");
+
+ schema_hash_test_multi<
+ schema_test_pair<FactorySchema, 86402530>,
+ schema_test_pair<Schema, 86402530>
+ >::check();
+}
+
+template<typename Schema>
+auto ensure_types_one(saw::schema_factory<Schema> builder){
+ return builder
+ .template add_maybe<schema::Array<schema::Int32>, "foo">()
+ .template add_maybe<schema::Int32, "bar">()
+ ;
+}
+
+template<typename Schema>
+auto ensure_types_two(saw::schema_factory<Schema> builder){
+ return builder
+ .template add_maybe<schema::Array<schema::Int32>, "foo">()
+ .template add_maybe<schema::UInt64, "baz">()
+ ;
+}
+
+SAW_TEST("Schema Factory Multimethod"){
+ using namespace saw;
+ auto builder = build_schema<schema::Struct<>>();
+
+ /**
+ * This would basically be multiple components
+ */
+ auto b2 = ensure_types_one(builder);
+ auto b3 = ensure_types_two(b2);
+
+ using Schema = schema::Struct<
+ schema::Member<schema::Array<schema::Int32>, "foo">,
+ schema::Member<schema::Int32, "bar">,
+ schema::Member<schema::UInt64, "baz">
+ >;
+
+ schema_hash_test_multi<
+ schema_test_pair<decltype(b3)::Schema, 2324362429>,
+ schema_test_pair<Schema, 2324362429>
+ >::check();
+
+
+}
}
diff --git a/modules/io_codec/c++/rpc.hpp b/modules/io_codec/c++/rpc.hpp
index 7a8e93b..cdade00 100644
--- a/modules/io_codec/c++/rpc.hpp
+++ b/modules/io_codec/c++/rpc.hpp
@@ -33,9 +33,9 @@ public:
template<template Interface>
class rpc_client<rmt::Network, Interface> {
private:
- own<io_stream> stream_;
+ own<async_io_stream> stream_;
public:
- rpc_client(own<io_stream> stream);
+ rpc_client(own<async_io_stream> stream);
template<typename T>
remote_result<typename response<T>::type> call(typename request<T>::type req);