#pragma once #include #include namespace saw { namespace impl { struct cli_mode { struct read {}; struct write {}; }; template struct cli_traverser { static_assert(always_false, "Not supported"); }; template struct cli_modifier { codec json; codec encoded; error_or read( std::deque& sch_path, data& enc_data, std::string& json_data_str ){ data native; if constexpr ( std::is_same_v ){ auto eov = encoded.decode(enc_data, native); if(eov.is_error()){ return eov; } }else{ native = enc_data; } { data json_data; auto eov = json.encode(native, json_data); if(eov.is_error()){ return eov; } json_data_str = convert_to_string(json_data.get_buffer()); std::cout< write( std::deque& sch_path, data& enc_data, std::string& json_data_str ){ data native; { /// @todo string to data data json_data{ std::string_view{json_data_str} }; auto eov = json.decode(json_data, native); if(eov.is_error()){ return eov; } } if constexpr (std::is_same_v ){ auto eov = encoded.encode(native, enc_data); if(eov.is_error()){ return eov; } }else{ enc_data = native; } return void_t{}; } }; template struct cli_traverser, Encoding> { using Schema = schema::Tuple; template static error_or traverse_member(std::deque& sch_path, data& enc_data, std::string& json_data){ using Type = typename parameter_pack_type::type; std::string num_str = std::to_string(i); if( num_str == sch_path.front() ){ sch_path.pop_front(); return cli_traverser::traverse(sch_path, enc_data.template get(), json_data); } if ( (i+1) < sizeof...(T)){ return traverse_member(sch_path, enc_data, json_data); } return make_error("Didn't find tuple path element"); } }; /** * Traverse the path until we hit the end of the provided path */ template struct cli_traverser...>, Encoding> { using Schema = schema::Struct...>; template static error_or traverse_member(std::deque& sch_path, data& enc_data, std::string& json_data){ using Type = typename parameter_pack_type::type; constexpr string_literal Literal = parameter_key_pack_type::literal; if ( Literal.view() == sch_path.front() ){ sch_path.pop_front(); return cli_traverser::traverse(sch_path, enc_data.template get(), json_data); } if constexpr ( (i+1) < sizeof...(T) ) { return traverse_member(sch_path, enc_data, json_data); } return make_error("Didn't find struct path element"); } template static error_or traverse(std::deque& sch_path, data& enc_data, std::string& json_data){ /** * If our path is empty, then we have reached the desired destination. */ if(sch_path.empty()){ /** * Decide during this step if we are reading or not */ cli_modifier mod; if constexpr (std::is_same_v){ return mod.read(sch_path, json_data); } else if constexpr (std::is_same_v) { return mod.write(sch_path, json_data); } else { return make_error("We only support cli_mode::read and cli_mode::write"); } } else { if constexpr ( sizeof...(T) > 0 ){ return traverse_member(sch_path, json_data); } return make_error("No elements in struct while path isn't empty"); } return void_t{}; } }; } struct parsed_args { bool read_mode = true; std::string file_path; std::deque sch_path; }; template int modify_data_on_cli(bool read_mode, const std::string& file_path, std::deque sch_path, std::string& json_data){ /** * Read data from file */ data data; data native_data; if (read_mode) { auto eov = impl::cli_modifier::traverse(sch_path, native_data, json_data); if(eov.is_error()){ return -1; } } else { auto eov = impl::cli_modifier::traverse(sch_path, native_data, json_data); if(eov.is_error()){ return -1; } } return 0; } }