diff options
author | Claudius "keldu" Holeksa <mail@keldu.de> | 2024-03-23 17:48:09 +0100 |
---|---|---|
committer | Claudius "keldu" Holeksa <mail@keldu.de> | 2024-03-23 17:48:09 +0100 |
commit | c64c76e273084cfd5b8628fb268e803957fc3025 (patch) | |
tree | ebbc9bfa647617ba5c3c7c226f051a2933ccc3a5 | |
parent | 7d096b9b3057617475d223330aaa6b321e0bd59a (diff) |
codec, io_codec: forst and rpc work
-rw-r--r-- | modules/codec/c++/forst.hpp | 68 | ||||
-rw-r--r-- | modules/codec/c++/forst.tmpl.hpp | 70 | ||||
-rw-r--r-- | modules/codec/c++/rpc.hpp | 94 | ||||
-rw-r--r-- | modules/codec/c++/schema.hpp | 85 | ||||
-rw-r--r-- | modules/codec/c++/schema_factory.hpp | 29 | ||||
-rw-r--r-- | modules/codec/tests/forst.cpp | 29 | ||||
-rw-r--r-- | modules/codec/tests/schema.cpp | 69 | ||||
-rw-r--r-- | modules/io_codec/c++/rpc.hpp | 4 |
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); |