arg_router  1.4.0
C++ command line argument parsing and routing
one_of.hpp
1 // Copyright (C) 2022-2023 by Camden Mannett.
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
4 
5 #pragma once
6 
7 #include "arg_router/dependency/detail.hpp"
8 #include "arg_router/policy/multi_stage_value.hpp"
9 
10 namespace arg_router::dependency
11 {
19 template <typename... Params>
20 class one_of_t : public detail::basic_one_of_t<AR_STRING("One of: "), Params...>
21 {
22  using parent_type = detail::basic_one_of_t<AR_STRING("One of: "), Params...>;
23 
24  static_assert(boost::mp11::mp_none_of<typename parent_type::children_type,
26  "one_of children must not use a multi_stage_value policy");
27 
28  using variant_type =
29  boost::mp11::mp_rename<typename parent_type::basic_value_type, std::variant>;
30 
31  static_assert(
32  !parent_type::template any_phases_v<variant_type, policy::has_validation_phase_method>,
33  "one_of does not support policies with validation phases; as it delegates those to its "
34  "children");
35 
36 public:
37  using typename parent_type::children_type;
38  using typename parent_type::policies_type;
39 
42  using value_type = std::conditional_t<(std::variant_size_v<variant_type> == 1),
43  std::variant_alternative_t<0, variant_type>,
44  variant_type>;
45 
47  template <bool Flatten>
49  {
50  public:
51  using label = AR_STRING_SV(parent_type::display_name());
52  using description = AR_STRING("");
53  using children = typename parent_type::template children_help_data_type<Flatten>::children;
54 
55  template <typename OwnerNode, typename FilterFn>
56  [[nodiscard]] static vector<runtime_help_data> runtime_children(const OwnerNode& owner,
57  FilterFn&& f)
58  {
59  return parent_type::template children_help_data_type<Flatten>::runtime_children(
60  owner,
61  std::forward<FilterFn>(f));
62  }
63  };
64 
69  constexpr explicit one_of_t(Params... params) noexcept : parent_type{std::move(params)...} {}
70 
83  template <typename Validator, bool HasTarget, typename... Parents>
84  [[nodiscard]] std::optional<parsing::parse_target> pre_parse(
86  const Parents&... parents) const
87  {
88  // We need to wrap the pre_parse_data validator so that we can catch child type mismatches
89  // before the caller's validation, otherwise the user can get misleading error messages
90  const auto validator = [&](const auto& child, const auto&... parents) {
91  using child_type = std::decay_t<decltype(child)>;
92 
93  auto type_hash = utility::type_hash<child_type>();
94  if (last_typeid_) {
95  if (type_hash != *last_typeid_) {
97  parsing::node_token_type<one_of_t>()};
98  }
99  } else {
100  last_typeid_ = type_hash;
101  }
102 
103  return pre_parse_data.validator()(child, parents...);
104  };
105  auto wrapper =
106  std::optional<parsing::pre_parse_data<std::decay_t<decltype(validator)>, HasTarget>>{};
107  if constexpr (pre_parse_data.has_target) {
108  wrapper =
109  parsing::pre_parse_data{pre_parse_data.args(), pre_parse_data.target(), validator};
110  } else {
111  wrapper = parsing::pre_parse_data{pre_parse_data.args(), validator};
112  }
113 
114  auto found = std::optional<parsing::parse_target>{};
116  [&](auto /*i*/, const auto& child) {
117  if (!found) {
118  found = child.pre_parse(*wrapper, parents...);
119  if (found) {
120  // There is no requirement to use pre_parse_data validation, so we also
121  // need to manually check here
122  validator(child, parents...);
123  }
124  }
125  },
126  this->children());
127 
128  return found;
129  }
130 
131 private:
132  mutable std::optional<std::size_t> last_typeid_;
133 };
134 
142 template <typename... Params>
143 [[nodiscard]] constexpr auto one_of(Params... params) noexcept
144 {
145  return one_of_t{std::move(params)...};
146 }
147 } // namespace arg_router::dependency
std::conditional_t<(std::variant_size_v< variant_type >==1), std::variant_alternative_t< 0, variant_type >, variant_type > value_type
Definition: one_of.hpp:44
std::optional< parsing::parse_target > pre_parse(parsing::pre_parse_data< Validator, HasTarget > pre_parse_data, const Parents &... parents) const
Definition: one_of.hpp:84
constexpr one_of_t(Params... params) noexcept
Definition: one_of.hpp:69
constexpr auto one_of(Params... params) noexcept
Definition: one_of.hpp:143
constexpr std::enable_if_t< traits::is_tuple_like_v< std::decay_t< Tuple > > > tuple_iterator(F &&f, Tuple &&tuple)
std::vector< T, config::allocator< T > > vector
Definition: basic_types.hpp:39