#pragma once #include #include #include #include #include #include #include namespace saw { namespace impl { struct cli_mode { struct read {}; struct write {}; struct list {}; }; template struct cli_traverser { template static error_or traverse(std::deque& sch_path, data& enc_data, std::string& json_data){ return make_error("Exhausted path or structure is not supported as of this moment"); } }; template struct cli_modifier { codec json; static_assert( std::is_same_v>, "Not supported" ); error_or read( std::deque& sch_path, data& enc_data, std::string& json_data_str ) { { data json_data; auto eov = json.template encode(enc_data, json_data); if(eov.is_error()){ return eov; } json_data_str = convert_to_string(json_data.get_buffer()); } return void_t{}; } error_or write( std::deque& sch_path, data& enc_data, std::string& json_data_str ){ { /// @todo string to data data json_data{ std::string_view{json_data_str} }; auto eov = json.template decode(json_data, enc_data); if(eov.is_error()){ return eov; } } return void_t{}; } }; template struct cli_traverser { using Schema = schema::String; template static error_or traverse(std::deque& sch_path, data& enc_data, std::string& json_data){ if(not sch_path.empty()){ return make_error("Schema path too long"); } cli_modifier mod; if constexpr (std::is_same_v){ return mod.read(sch_path, enc_data, json_data); } else if constexpr (std::is_same_v) { return mod.write(sch_path, enc_data, json_data); } else { return make_error("We only support cli_mode::read and cli_mode::write"); } } }; 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::template 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::template 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, enc_data, json_data); } else if constexpr (std::is_same_v) { return mod.write(sch_path, enc_data, 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, enc_data, 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 error_or modify_data_on_cli(const std::string_view& mode, const std::string_view& file_path, std::deque sch_path, std::string& json_data){ /** * Read data from file */ std::string file_data = [&]() -> std::string { std::fstream fstr{std::string{file_path}, fstr.binary | fstr.in}; if(!fstr.is_open()){ return {}; } std::stringstream sstr; sstr << fstr.rdbuf(); return sstr.str(); }(); if(file_data.empty()){ return make_error("File exists, but is empty."); } data enc_data{std::string_view{file_data}}; codec enc_codec; data native_data; { auto eov = enc_codec.decode(enc_data, native_data); if(eov.is_error()){ return eov; } } if (mode == "r") { { auto eov = impl::cli_traverser>::template traverse(sch_path, native_data, json_data); if(eov.is_error()){ return eov; } } } else if (mode == "w") { { auto eov = impl::cli_traverser>::template traverse(sch_path, native_data, json_data); if(eov.is_error()){ return eov; } } { auto eov = enc_codec.template encode>(native_data, enc_data); if(eov.is_error()){ return eov; } } { std::fstream fstr{std::string{file_path}, fstr.binary | fstr.out | fstr.trunc }; if(!fstr.is_open()){ return make_error("Couldn't open file"); } std::stringstream sstr; std::string enc_str = convert_to_string(enc_data.get_buffer()); fstr << enc_str; fstr.close(); } } else if (mode == "l"){ { } }else{ return make_error("Invalid mode"); } return void_t{}; } }