diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -271,6 +271,10 @@ } } +/** + * A pair of strings that can be aligned (through padding) with other Sections + * later on + */ struct Section { Section(const std::string &left, const std::string &right) : m_left{left}, m_right{right} {} @@ -278,6 +282,10 @@ const std::string m_right; }; +/** + * Keeps track of RPCArgs by transforming them into sections for the purpose + * of serializing everything to a single string + */ struct Sections { std::vector
m_sections; size_t m_max_pad{0}; @@ -287,6 +295,11 @@ m_sections.push_back(s); } + /** + * Serializing RPCArgs depends on the outer type. Only arrays and + * dictionaries can be nested in json. The top-level outer type is "named + * arguments", a mix between a dictionary and arrays. + */ enum class OuterType { ARR, OBJ, @@ -294,10 +307,16 @@ NAMED_ARG, }; + /** + * Recursive helper to translate an RPCArg into sections + */ void Push(const RPCArg &arg, const size_t current_indent = 5, const OuterType outer_type = OuterType::NAMED_ARG) { const auto indent = std::string(current_indent, ' '); const auto indent_next = std::string(current_indent + 2, ' '); + // Dictionary keys must have a name + const bool push_name{outer_type == OuterType::OBJ}; + switch (arg.m_type) { case RPCArg::Type::STR_HEX: case RPCArg::Type::STR: @@ -309,13 +328,11 @@ return; } auto left = indent; - if (arg.m_type_str.size() != 0 && - outer_type == OuterType::OBJ) { + if (arg.m_type_str.size() != 0 && push_name) { left += "\"" + arg.m_name + "\": " + arg.m_type_str.at(0); } else { - left += outer_type == OuterType::OBJ - ? arg.ToStringObj(/* oneline */ false) - : arg.ToString(/* oneline */ false); + left += push_name ? arg.ToStringObj(/* oneline */ false) + : arg.ToString(/* oneline */ false); } left += ","; PushSection({left, arg.ToDescriptionString()}); @@ -326,7 +343,10 @@ const auto right = outer_type == OuterType::NAMED_ARG ? "" : arg.ToDescriptionString(); - PushSection({indent + "{", right}); + PushSection({indent + + (push_name ? "\"" + arg.m_name + "\": " : "") + + "{", + right}); for (const auto &arg_inner : arg.m_inner) { Push(arg_inner, current_indent + 2, OuterType::OBJ); } @@ -341,9 +361,7 @@ } case RPCArg::Type::ARR: { auto left = indent; - left += outer_type == OuterType::OBJ - ? "\"" + arg.m_name + "\": " - : ""; + left += push_name ? "\"" + arg.m_name + "\": " : ""; left += "["; const auto right = outer_type == OuterType::NAMED_ARG ? "" @@ -364,6 +382,9 @@ } } + /** + * Concatenate all sections with proper padding + */ std::string ToString() const { std::string ret; const size_t pad = m_max_pad + 4;