diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index bb850a91712..9619c3df995 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -388,6 +388,7 @@ struct Sections { const auto indent = std::string(current_indent, ' '); const auto indent_next = std::string(current_indent + 2, ' '); const bool push_name{outer_type == OuterType::OBJ}; // Dictionary keys must have a name + const bool is_top_level_arg{outer_type == OuterType::NONE}; // True on the first recursion switch (arg.m_type) { case RPCArg::Type::STR_HEX: @@ -396,7 +397,7 @@ struct Sections { case RPCArg::Type::AMOUNT: case RPCArg::Type::RANGE: case RPCArg::Type::BOOL: { - if (outer_type == OuterType::NONE) return; // Nothing more to do for non-recursive types on first recursion + if (is_top_level_arg) return; // Nothing more to do for non-recursive types on first recursion auto left = indent; if (arg.m_opts.type_str.size() != 0 && push_name) { left += "\"" + arg.GetName() + "\": " + arg.m_opts.type_str.at(0); @@ -404,12 +405,12 @@ struct Sections { left += push_name ? arg.ToStringObj(/*oneline=*/false) : arg.ToString(/*oneline=*/false); } left += ","; - PushSection({left, arg.ToDescriptionString()}); + PushSection({left, arg.ToDescriptionString(/*is_named_arg=*/push_name)}); break; } case RPCArg::Type::OBJ: case RPCArg::Type::OBJ_USER_KEYS: { - const auto right = outer_type == OuterType::NONE ? "" : arg.ToDescriptionString(); + const auto right = is_top_level_arg ? "" : arg.ToDescriptionString(/*is_named_arg=*/push_name); PushSection({indent + (push_name ? "\"" + arg.GetName() + "\": " : "") + "{", right}); for (const auto& arg_inner : arg.m_inner) { Push(arg_inner, current_indent + 2, OuterType::OBJ); @@ -417,20 +418,20 @@ struct Sections { if (arg.m_type != RPCArg::Type::OBJ) { PushSection({indent_next + "...", ""}); } - PushSection({indent + "}" + (outer_type != OuterType::NONE ? "," : ""), ""}); + PushSection({indent + "}" + (is_top_level_arg ? "" : ","), ""}); break; } case RPCArg::Type::ARR: { auto left = indent; left += push_name ? "\"" + arg.GetName() + "\": " : ""; left += "["; - const auto right = outer_type == OuterType::NONE ? "" : arg.ToDescriptionString(); + const auto right = is_top_level_arg ? "" : arg.ToDescriptionString(/*is_named_arg=*/push_name); PushSection({left, right}); for (const auto& arg_inner : arg.m_inner) { Push(arg_inner, current_indent + 2, OuterType::ARR); } PushSection({indent_next + "...", ""}); - PushSection({indent + "]" + (outer_type != OuterType::NONE ? "," : ""), ""}); + PushSection({indent + "]" + (is_top_level_arg ? "" : ","), ""}); break; } } // no default case, so the compiler can warn about missing cases @@ -627,7 +628,7 @@ std::string RPCHelpMan::ToString() const if (i == 0) ret += "\nArguments:\n"; // Push named argument name and description - sections.m_sections.emplace_back(::ToString(i + 1) + ". " + arg.GetFirstName(), arg.ToDescriptionString()); + sections.m_sections.emplace_back(::ToString(i + 1) + ". " + arg.GetFirstName(), arg.ToDescriptionString(/*is_named_arg=*/true)); sections.m_max_pad = std::max(sections.m_max_pad, sections.m_sections.back().m_left.size()); // Recursively push nested args @@ -721,7 +722,7 @@ bool RPCArg::IsOptional() const } } -std::string RPCArg::ToDescriptionString() const +std::string RPCArg::ToDescriptionString(bool is_named_arg) const { std::string ret; ret += "("; @@ -767,14 +768,12 @@ std::string RPCArg::ToDescriptionString() const ret += ", optional, default=" + std::get(m_fallback).write(); } else { switch (std::get(m_fallback)) { + case RPCArg::Optional::OMITTED_NAMED_ARG: // Deprecated alias for OMITTED, can be removed case RPCArg::Optional::OMITTED: { + if (is_named_arg) ret += ", optional"; // Default value is "null" in dicts. Otherwise, // nothing to do. Element is treated as if not present and has no default value break; } - case RPCArg::Optional::OMITTED_NAMED_ARG: { - ret += ", optional"; // Default value is "null" - break; - } case RPCArg::Optional::NO: { ret += ", required"; break; diff --git a/src/rpc/util.h b/src/rpc/util.h index a86300d8b40..30c46bfdcda 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -154,21 +154,24 @@ struct RPCArg { /** Required arg */ NO, /** + * The arg is optional for one of two reasons: + * * Optional arg that is a named argument and has a default value of - * `null`. When possible, the default value should be specified. - */ - OMITTED_NAMED_ARG, - /** + * `null`. + * * Optional argument with default value omitted because they are - * implicitly clear. That is, elements in an array or object may not + * implicitly clear. That is, elements in an array may not * exist by default. * When possible, the default value should be specified. */ OMITTED, + OMITTED_NAMED_ARG, // Deprecated alias for OMITTED, can be removed }; + /** Hint for default value */ using DefaultHint = std::string; + /** Default constant value */ using Default = UniValue; - using Fallback = std::variant; + using Fallback = std::variant; const std::string m_names; //!< The name of the arg (can be empty for inner args, can contain multiple aliases separated by | for named request arguments) const Type m_type; @@ -178,10 +181,10 @@ struct RPCArg { const RPCArgOptions m_opts; RPCArg( - const std::string name, - const Type type, - const Fallback fallback, - const std::string description, + std::string name, + Type type, + Fallback fallback, + std::string description, RPCArgOptions opts = {}) : m_names{std::move(name)}, m_type{std::move(type)}, @@ -193,11 +196,11 @@ struct RPCArg { } RPCArg( - const std::string name, - const Type type, - const Fallback fallback, - const std::string description, - const std::vector inner, + std::string name, + Type type, + Fallback fallback, + std::string description, + std::vector inner, RPCArgOptions opts = {}) : m_names{std::move(name)}, m_type{std::move(type)}, @@ -234,7 +237,7 @@ struct RPCArg { * Return the description string, including the argument type and whether * the argument is required. */ - std::string ToDescriptionString() const; + std::string ToDescriptionString(bool is_named_arg) const; }; struct RPCResult { @@ -263,12 +266,12 @@ struct RPCResult { const std::string m_cond; RPCResult( - const std::string cond, - const Type type, - const std::string m_key_name, - const bool optional, - const std::string description, - const std::vector inner = {}) + std::string cond, + Type type, + std::string m_key_name, + bool optional, + std::string description, + std::vector inner = {}) : m_type{std::move(type)}, m_key_name{std::move(m_key_name)}, m_inner{std::move(inner)}, @@ -282,19 +285,19 @@ struct RPCResult { } RPCResult( - const std::string cond, - const Type type, - const std::string m_key_name, - const std::string description, - const std::vector inner = {}) - : RPCResult{cond, type, m_key_name, false, description, inner} {} + std::string cond, + Type type, + std::string m_key_name, + std::string description, + std::vector inner = {}) + : RPCResult{std::move(cond), type, std::move(m_key_name), /*optional=*/false, std::move(description), std::move(inner)} {} RPCResult( - const Type type, - const std::string m_key_name, - const bool optional, - const std::string description, - const std::vector inner = {}, + Type type, + std::string m_key_name, + bool optional, + std::string description, + std::vector inner = {}, bool skip_type_check = false) : m_type{std::move(type)}, m_key_name{std::move(m_key_name)}, @@ -308,12 +311,12 @@ struct RPCResult { } RPCResult( - const Type type, - const std::string m_key_name, - const std::string description, - const std::vector inner = {}, + Type type, + std::string m_key_name, + std::string description, + std::vector inner = {}, bool skip_type_check = false) - : RPCResult{type, m_key_name, false, description, inner, skip_type_check} {} + : RPCResult{type, std::move(m_key_name), /*optional=*/false, std::move(description), std::move(inner), skip_type_check} {} /** Append the sections of the result. */ void ToSections(Sections& sections, OuterType outer_type = OuterType::NONE, const int current_indent = 0) const;