#pragma once #include "schema.hpp" #include "data.hpp" #include #include namespace saw { namespace encode { struct Args {}; } namespace schema { template using Args = Struct< Member, Member, Member >; } template class data { static_assert(always_false,"Not supported. Use the schema::Args alias or check how it's defined."); }; template class data...>, schema::Tuple>, encode::Args> { private: int argc_; char** argv_; public: data(int argc, char** argv): argc_{argc}, argv_{argv} {} uint64_t size() const { if(argc_ < 0){ return 0u; } static_assert(sizeof(int) <= sizeof(uint64_t), "size_t is smaller than int"); return static_cast(argc_); } std::string_view arg_view(uint64_t i){ if(i < size()){ return std::string_view{argv_[i]}; } return ""; } }; namespace impl { template struct args_decode { static_assert(always_false, "Not supported"); }; template struct args_decode, ToDec> { using Schema = schema::Primitive; static error_or decode(data& to, std::string_view view){ if(view.empty()){ return make_error("Can't decode empty data."); } typename native_data_type::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("Parsing failed. "); } to.set(val); return make_void(); } }; template struct args_decode { using Schema = schema::String; static error_or decode(data& to, std::string_view view){ try{ to.set(std::string{view}); }catch(const std::exception&){ return make_error(); } return make_void(); } }; template struct args_decode...>,schema::Tuple>,ToDec> { using Schema = schema::Args< schema::Struct...>, schema::Tuple >; using SchemaStruct = schema::Struct...>; using SchemaTuple = schema::Tuple; template static error_or decode_struct_member(data& to, std::string_view name, std::string_view value){ if constexpr ( i < sizeof...(Str) ) { static constexpr string_literal Literal = parameter_key_pack_type::literal; using StrT = typename parameter_pack_type::type; if(Literal.view() == name){ auto& target = to.template get(); auto eov = args_decode::decode(target, value); return eov; } return decode_struct_member(to, name, value); } return make_error("Couldn't decode argument"); } template static error_or decode_tuple_member(data& to, uint64_t ptr_i, std::string_view value){ if constexpr ( i < sizeof...(Tup) ){ if ( i == ptr_i ){ using TupT = typename parameter_pack_type::type; auto& target = to.template get(); return args_decode::decode(target, value); } return decode_tuple_member(to, ptr_i, value); } return make_error("Too many positional arguments."); } static error_or decode(data& from, data& to){ if(from.size() == 0){ return make_error(); } to.template get<"program">().set(std::string{from.arg_view(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("--")){ auto min_val = view.size() > 2u ? 2u : view.size(); view.remove_prefix(min_val); ++i; if( i >= from.size() ){ return make_error(); } auto value_view = from.arg_view(i); auto eov = decode_struct_member<0>(to.template get<"args">(), view, value_view); if(eov.is_error()){ return eov; } } else { auto eov = decode_tuple_member<0>(to.template get<"positionals">(), tuple_pos, view); if(eov.is_error()){ return eov; } ++tuple_pos; } } if(tuple_pos != sizeof...(Tup)){ return make_error("Didn't parse the whole set of positionals."); } return void_t{}; } }; } template class codec { public: template error_or decode(data& from, data& to){ /* struct name_and_value { std::string name; std::string value; }; std::string program; std::vector navs; std::vector positionals; */ auto eov = impl::args_decode::decode(from,to); return eov; } }; }