#include <arg_router/arg_router.hpp>
#include <cstdlib>
namespace arp = ar::policy;
using namespace std::string_view_literals;
namespace
{
constexpr auto version = "v1.0.0"sv;
}
template <typename S>
class smiley_description_t
{
public:
[[nodiscard]] constexpr
static std::string_view
description() noexcept
{
return S::template append_t<
S_(
" 🙂")>::get();
}
private:
static_assert(!S::empty(), "Descriptions must not be empty");
};
template <typename S>
constexpr auto smiley_description = smiley_description_t<S>{};
template <typename T>
struct arp::is_policy<smiley_description_t<T>> : std::true_type {
};
template <typename ValueType>
class is_even
{
static_assert(std::is_integral_v<ValueType>, "ValueType must be an integer");
public:
template <typename... Parents>
void validation_phase(const ValueType& value, [[maybe_unused]] const Parents&... parents) const
{
if (value % 2 != 0) {
throw ar::parse_exception{"Value not even: " + std::to_string(value)};
}
}
};
template <typename ValueType>
struct arp::is_policy<is_even<ValueType>> : std::true_type {
};
template <typename T, typename... Policies>
class single_positional_arg_t :
public ar::multi_arg_base_t<T,
1,
arp::min_max_count_t<ar::traits::integral_constant<std::size_t{1}>,
ar::traits::integral_constant<std::size_t{1}>>,
Policies...>
{
static_assert(arp::is_all_policies_v<std::tuple<Policies...>>,
"Positional args must only contain policies (not other nodes)");
using parent_type =
ar::multi_arg_base_t<T,
1,
arp::min_max_count_t<ar::traits::integral_constant<std::size_t{1}>,
ar::traits::integral_constant<std::size_t{1}>>,
Policies...>;
static_assert(ar::traits::has_display_name_method_v<single_positional_arg_t>,
"Positional arg must have a display name policy");
static_assert(!ar::traits::has_long_name_method_v<single_positional_arg_t>,
"Positional arg must not have a long name policy");
static_assert(!ar::traits::has_short_name_method_v<single_positional_arg_t>,
"Positional arg must not have a short name policy");
static_assert(!ar::traits::has_none_name_method_v<single_positional_arg_t>,
"Positional arg must not have a none name policy");
public:
using typename parent_type::policies_type;
using value_type = typename parent_type::value_type;
template <bool Flatten>
class help_data_type
{
[[nodiscard]] constexpr static auto label_generator() noexcept
{
constexpr auto name = single_positional_arg_t::display_name();
return S_(
"<"){} +
S_(name){} +
S_(
"> "){} +
parent_type::template default_leaf_help_data_type<Flatten>::count_suffix();
}
public:
using label = std::decay_t<decltype(label_generator())>;
typename parent_type::template default_leaf_help_data_type<Flatten>::description;
using children = std::tuple<>;
};
constexpr explicit single_positional_arg_t(Policies... policies) noexcept :
parent_type{arp::min_max_count_t<ar::traits::integral_constant<std::size_t{1}>,
ar::traits::integral_constant<std::size_t{1}>>{},
std::move(policies)...}
{
}
template <typename Validator, bool HasTarget, typename... Parents>
[[nodiscard]] std::optional<ar::parsing::parse_target> pre_parse(
ar::parsing::pre_parse_data<Validator, HasTarget> pre_parse_data,
const Parents&... parents) const
{
return parent_type::pre_parse(pre_parse_data, *this, parents...);
}
template <typename... Parents>
[[nodiscard]] value_type parse(ar::parsing::parse_target target,
const Parents&... parents) const
{
return parent_type::parse(target, *this, parents...);
}
private:
static_assert(!parent_type::template any_phases_v<value_type, arp::has_routing_phase_method>,
"Single positional arg does not support policies with routing phases "
"(e.g. router)");
};
template <typename T, typename... Policies>
[[nodiscard]] constexpr auto single_positional_arg(Policies... policies) noexcept
{
return std::apply(
[](auto... converted_policies) {
return single_positional_arg_t<T, std::decay_t<decltype(converted_policies)>...>{
std::move(converted_policies)...};
},
ar::utility::string_to_policy::convert<
ar::utility::string_to_policy::first_text_mapper<arp::display_name_t>,
ar::utility::string_to_policy::second_text_mapper<smiley_description_t>>(
std::move(policies)...));
}
using original_rules = typename decltype(arp::validation::default_validator)::rules_type;
using smiley_rules = arp::validation::utility::insert_rule_t<
0,
arp::validation::rule_q<
arp::validation::common_rules::despecialised_any_of_rule<smiley_description_t>,
arp::validation::despecialised_unique_in_owner,
arp::validation::policy_parent_must_not_have_policy<arp::description_t>>,
arp::validation::utility::default_rules>;
using new_rules = arp::validation::utility::add_to_rule_types_by_rule_t<
arp::validation::common_rules::despecialised_any_of_rule<ar::positional_arg_t>,
single_positional_arg_t,
smiley_rules>;
using my_validator = arp::validation::validator_from_tuple<new_rules>;
int main(int argc, char* argv[])
{
ar::root(my_validator{},
arp::program_name<
S_(
"is_even")>,
arp::program_version<
S_(version)>,
arp::program_addendum<
S_(
"An example program for arg_router.")>,
smiley_description<
S_(
"Display this help and exit")>),
ar::flag(arp::long_name<
S_(
"version")>,
smiley_description<
S_(
"Output version information and exit")>,
arp::router{[](bool) {
std::cout << version << std::endl;
std::exit(EXIT_SUCCESS);
}}),
ar::mode(single_positional_arg<int>(arp::required,
is_even<int>{}),
arp::router{[](int value) { std::cout << "Value: " << value << std::endl; }}))
.parse(argc, argv);
return EXIT_SUCCESS;
}
constexpr auto description