diff options
author | Claudius 'keldu' Holeksa <mail@keldu.de> | 2024-07-31 15:53:21 +0200 |
---|---|---|
committer | Claudius 'keldu' Holeksa <mail@keldu.de> | 2024-07-31 15:53:21 +0200 |
commit | b0554a3dd0ea14d2d84f3d0e9fa7f22ff1c04175 (patch) | |
tree | 9ef43e924960a359747fd8e9a73f18f506444b17 | |
parent | 32004c2a672f99ee5c242c2c84d30e00bb31cf25 (diff) |
Basic Arg parsing support
-rw-r--r-- | modules/codec/c++/args.hpp | 65 | ||||
-rw-r--r-- | modules/codec/tests/args.cpp | 2 | ||||
-rw-r--r-- | modules/core/c++/error.cpp | 6 | ||||
-rw-r--r-- | modules/core/c++/error.hpp | 27 |
4 files changed, 91 insertions, 9 deletions
diff --git a/modules/codec/c++/args.hpp b/modules/codec/c++/args.hpp index a2b338b..e3e651d 100644 --- a/modules/codec/c++/args.hpp +++ b/modules/codec/c++/args.hpp @@ -4,6 +4,7 @@ #include "data.hpp" #include <algorithm> +#include <charconv> namespace saw { namespace encode { @@ -59,6 +60,42 @@ struct args_decode { static_assert(always_false<T,ToDec>, "Not supported"); }; +template<typename T, uint64_t N, typename ToDec> +struct args_decode<schema::Primitive<T,N>, ToDec> { + using Schema = schema::Primitive<T,N>; + + static error_or<void> decode(data<Schema, ToDec>& to, std::string_view view){ + if(view.empty()){ + return make_error<err::invalid_state>("Can't decode empty data."); + } + typename native_data_type<Schema>::type val{}; + auto fc_res = std::from_chars(view.data(), view.data()+view.size(), val); + if(fc_res.ec != std::errc{}){ + auto err_bld = error_builder{[&](){ + return std::string{"Parsing of failed: "} + std::string{view}; + }}; + return err_bld.template make_error<err::invalid_state>("Parsing failed. "); + } + to.set(val); + + return make_void(); + } +}; + +template<typename ToDec> +struct args_decode<schema::String, ToDec> { + using Schema = schema::String; + + static error_or<void> decode(data<Schema, ToDec>& to, std::string_view view){ + try{ + to.set(std::string{view}); + }catch(const std::exception&){ + return make_error<err::out_of_memory>(); + } + return make_void(); + } +}; + template<typename... Str, string_literal... Lits, typename... Tup, typename ToDec> struct args_decode<schema::Args<schema::Struct<schema::Member<Str,Lits>...>,schema::Tuple<Tup...>>,ToDec> { using Schema = schema::Args< @@ -73,11 +110,12 @@ struct args_decode<schema::Args<schema::Struct<schema::Member<Str,Lits>...>,sche static error_or<void> decode_struct_member(data<SchemaStruct, ToDec>& to, std::string_view name, std::string_view value){ if constexpr ( i < sizeof...(Str) ) { static constexpr string_literal Literal = parameter_key_pack_type<i,Lits...>::literal; + using StrT = typename parameter_pack_type<i,Str...>::type; if(Literal.view() == name){ auto& target = to.template get<Literal>(); - /// @TODO - return void_t{}; + auto eov = args_decode<StrT, ToDec>::decode(target, value); + return eov; } return decode_struct_member<i+1u>(to, name, value); @@ -86,9 +124,17 @@ struct args_decode<schema::Args<schema::Struct<schema::Member<Str,Lits>...>,sche } template<uint64_t i> - static error_or<void> decode_tuple_member(data<SchemaTuple, ToDec>& to, std::string_view value){ - - return make_error<err::not_implemented>(); + static error_or<void> decode_tuple_member(data<SchemaTuple, ToDec>& to, uint64_t ptr_i, std::string_view value){ + if constexpr ( i < sizeof...(Tup) ){ + if ( i == ptr_i ){ + using TupT = typename parameter_pack_type<i,Tup...>::type; + auto& target = to.template get<i>(); + + return args_decode<TupT, ToDec>::decode(target, value); + } + return decode_tuple_member<i+1u>(to, ptr_i, value); + } + return make_error<err::invalid_state>("Too many positional arguments."); } static error_or<void> decode(data<Schema, encode::Args>& from, data<Schema,ToDec>& to){ @@ -97,7 +143,8 @@ struct args_decode<schema::Args<schema::Struct<schema::Member<Str,Lits>...>,sche } to.template get<"program">().set(std::string{from.arg_view(0)}); - std::size_t tuple_pos = 0; + uint64_t tuple_pos = 0; + for(size_t i = 1; i < from.size(); ++i){ auto view = from.arg_view(i); if(view.starts_with("--")){ @@ -116,7 +163,7 @@ struct args_decode<schema::Args<schema::Struct<schema::Member<Str,Lits>...>,sche return eov; } } else { - auto eov = decode_tuple_member<0>(to.template get<"positionals">(), view); + auto eov = decode_tuple_member<0>(to.template get<"positionals">(), tuple_pos, view); if(eov.is_error()){ return eov; } @@ -125,7 +172,7 @@ struct args_decode<schema::Args<schema::Struct<schema::Member<Str,Lits>...>,sche } if(tuple_pos != sizeof...(Tup)){ - return make_error<err::invalid_state>(); + return make_error<err::invalid_state>("Didn't parse the whole set of positionals."); } return void_t{}; @@ -138,6 +185,7 @@ class codec<Schema, encode::Args> { public: template<typename ToDec> error_or<void> decode(data<Schema, encode::Args>& from, data<Schema, ToDec>& to){ + /* struct name_and_value { std::string name; std::string value; @@ -145,6 +193,7 @@ public: std::string program; std::vector<name_and_value> navs; std::vector<std::string> positionals; + */ auto eov = impl::args_decode<Schema,ToDec>::decode(from,to); return eov; diff --git a/modules/codec/tests/args.cpp b/modules/codec/tests/args.cpp index ed6d918..f53b80e 100644 --- a/modules/codec/tests/args.cpp +++ b/modules/codec/tests/args.cpp @@ -40,7 +40,7 @@ SAW_TEST("Codec Args Decode"){ codec<sch::Args<sch::ArgsStruct, sch::ArgsTuple>, encode::Args> args_codec; auto eov = args_codec.decode(dat_args, dat_nat); - SAW_EXPECT(eov.is_value(), "Couldn't decode data"); + SAW_EXPECT(eov.is_value(), std::string{"Couldn't decode data. "} + std::string{eov.get_error().get_category()} + std::string{" - "} + std::string{eov.get_error().get_message()}); auto& prog = dat_nat.template get<"program">(); auto& str = dat_nat.template get<"args">(); diff --git a/modules/core/c++/error.cpp b/modules/core/c++/error.cpp index 192cab6..d5132ac 100644 --- a/modules/core/c++/error.cpp +++ b/modules/core/c++/error.cpp @@ -9,6 +9,12 @@ error::error(error::code code_, bool is_critical__, const std::string_view &msg) error_code_{static_cast<error::code>(code_)} , is_critical_{is_critical__}, error_message_{msg}{} + error::error(error::code code_, bool is_critical__, std::string&& msg): + error_code_{static_cast<error::code>(code_)}, + is_critical_{is_critical__}, + error_message_{std::move(msg)} + {} + error::error(error &&error) : error_code_{std::move(error.error_code_)} diff --git a/modules/core/c++/error.hpp b/modules/core/c++/error.hpp index 8439f85..7a5dd8a 100644 --- a/modules/core/c++/error.hpp +++ b/modules/core/c++/error.hpp @@ -2,6 +2,7 @@ #include <algorithm> #include <limits> +#include <functional> #include <string> #include <string_view> #include <variant> @@ -40,6 +41,7 @@ private: public: error(error::code id, bool is_critical); error(error::code id, bool is_critical, const std::string_view &msg); + error(error::code id, bool is_critical, std::string&& msg); error(error &&error); SAW_FORBID_COPY(error); @@ -158,6 +160,31 @@ template<typename T> error make_error(){ error make_error(error::code code, const std::string_view &generic); +struct error_builder { +private: + std::function<std::string()> func_; +public: + template<typename Func> + error_builder(Func&& func__): + func_{std::move(func__)} + {} + + template<typename T> + error make_error(const std::string& generic){ + try{ + std::string err_str = func_(); + error::code id = impl::get_template_id<T>(); + func_ = [](){return "";}; + return error{id, T::is_critical, std::move(err_str)}; + }catch(const std::exception&){} + return make_error<T>(generic); + } +}; + +template<typename Func> +error_builder build_error(Func&& func){ + return error_builder{std::move(func)}; +} namespace err { struct no_error { |