7 #include "arg_router/parsing/unknown_argument_handling.hpp"
8 #include "arg_router/policy/exception_translator.hpp"
9 #include "arg_router/policy/flatten_help.hpp"
10 #include "arg_router/policy/no_result_value.hpp"
11 #include "arg_router/tree_node.hpp"
18 namespace policy::validation
20 template <
typename... Rules>
26 template <
typename... Params>
27 class add_missing_exception_translator
29 using params_tuple = std::tuple<std::decay_t<Params>...>;
30 using policies_tuple = boost::mp11::mp_copy_if<params_tuple, policy::is_policy>;
34 policy::exception_translator<default_error_code_translations, void>;
36 constexpr
static auto has_exception_translator =
37 boost::mp11::mp_find_if<policies_tuple, traits::has_translate_exception_method>::value !=
38 std::tuple_size_v<policies_tuple>;
40 using type = std::conditional_t<
41 has_exception_translator,
42 boost::mp11::mp_rename<params_tuple, tree_node>,
43 boost::mp11::mp_rename<
44 boost::mp11::mp_push_back<params_tuple, std::decay_t<decltype(exception_translator)>>,
53 template <
typename... Params>
54 class root_t :
public detail::add_missing_exception_translator<Params...>::type
56 using parent_type =
typename detail::add_missing_exception_translator<Params...>::type;
59 using typename parent_type::policies_type;
60 using typename parent_type::children_type;
64 !parent_type::template any_phases_v<
bool,
70 "Root does not support policies with any parsing phases");
72 static_assert(!traits::has_long_name_method_v<parent_type> &&
73 !traits::has_short_name_method_v<parent_type> &&
74 !traits::has_display_name_method_v<parent_type> &&
75 !traits::has_none_name_method_v<parent_type> &&
76 !traits::has_error_name_method_v<parent_type> &&
77 !traits::has_description_method_v<parent_type>,
78 "Root cannot have name or description policies");
80 constexpr
static auto validator_index =
81 algorithm::find_specialisation_v<policy::validation::validator, policies_type>;
82 static_assert(validator_index != std::tuple_size_v<policies_type>,
83 "Root must have a validator policy, use "
84 "policy::validation::default_validator unless you have "
85 "created a custom one");
87 static_assert(std::tuple_size_v<children_type> >= 1,
"Root must have at least one child");
89 template <
typename Child>
90 struct router_checker {
91 constexpr
static bool has_router = !std::is_void_v<
92 typename Child::template phase_finder_t<policy::has_routing_phase_method>>;
94 constexpr
static bool value = policy::has_no_result_value_v<Child> || has_router;
96 static_assert(boost::mp11::mp_all_of<children_type, router_checker>::value,
97 "All root children must have routers, unless they have no value");
106 template <
bool Flatten>
110 using label = AR_STRING(
"");
111 using description = AR_STRING(
"");
113 typename parent_type::template default_leaf_help_data_type<Flatten>::all_children_help;
120 template <
auto has_exception_translator =
121 detail::add_missing_exception_translator<Params...>::has_exception_translator>
122 constexpr
explicit root_t(Params... params,
124 std::enable_if_t<has_exception_translator>* =
nullptr) noexcept :
125 parent_type{std::move(params)...}
127 validator_type::template validate<std::decay_t<decltype(*
this)>>();
130 template <
auto has_exception_translator =
131 detail::add_missing_exception_translator<Params...>::has_exception_translator>
132 constexpr
explicit root_t(Params... params,
134 std::enable_if_t<!has_exception_translator>* =
nullptr) noexcept :
135 parent_type{std::move(params)...,
136 detail::add_missing_exception_translator<Params...>::exception_translator}
138 validator_type::template validate<std::decay_t<decltype(*
this)>>();
151 const auto front_token = args.empty() ?
156 auto match = std::optional<parsing::parse_target>{};
158 [&](
auto ,
const auto& child) {
162 throw multi_lang_exception{error_code::unhandled_arguments, args};
169 if (front_token.name.empty()) {
178 this->translate_exception(e);
190 template <
typename Iter,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Iter>,
int>>>
191 void parse(Iter begin, Iter end)
const
194 for (; begin != end; ++begin) {
197 args.shrink_to_fit();
199 parse(std::move(args));
210 template <
typename Container,
211 typename = std::enable_if_t<
213 void parse(
const Container& c)
const
218 parse(std::begin(c), std::end(c));
228 void parse(
int argc,
char** argv)
const
231 parse(&argv[1], &argv[argc]);
239 void help([[maybe_unused]] std::ostream& stream)
const
243 [&](
auto* type_ptr) {
244 using root_type = std::decay_t<std::remove_pointer_t<decltype(type_ptr)>>;
245 using root_children =
typename root_type::children_type;
247 constexpr
static auto help_index =
248 boost::mp11::mp_find_if<root_children, traits::has_generate_help_method>::value;
250 if constexpr (help_index < std::tuple_size_v<root_children>) {
251 using help_type = std::tuple_element_t<help_index, root_children>;
252 constexpr
auto flatten =
254 typename help_type::policies_type>;
256 const auto& help_node = std::get<help_index>(this->children());
258 if constexpr (traits::has_generate_runtime_help_data_method_v<help_type> &&
259 traits::has_runtime_generate_help_method_v<help_type>) {
261 help_node.template generate_runtime_help_data<flatten>(*
this);
262 help_node.template generate_help<root_type, help_type, flatten>(stream,
265 help_node.template generate_help<root_type, help_type, flatten>(stream);
268 this->translate_exception(e);
278 [[nodiscard]]
string help()
const
294 template <
typename... Params>
295 [[nodiscard]] constexpr
auto root(Params... params) noexcept
void help([[maybe_unused]] std::ostream &stream) const
void parse(const Container &c) const
void parse(Iter begin, Iter end) const
void parse(vector< parsing::token_type > args) const
void parse(int argc, char **argv) const
std::tuple_element_t< validator_index, policies_type > validator_type
constexpr root_t(Params... params, std::enable_if_t< has_exception_translator > *=nullptr) noexcept
constexpr auto has_specialisation_v
void unknown_argument_exception(const Node &node, token_type unknown_token)
constexpr auto exception_translator
constexpr std::enable_if_t< traits::is_tuple_like_v< std::decay_t< Tuple > > > tuple_iterator(F &&f, Tuple &&tuple)
constexpr auto help(Policies... policies) noexcept
std::vector< T, config::allocator< T > > vector
std::basic_ostringstream< char, std::char_traits< char >, config::allocator< char > > ostringstream