Skip to content

Commit 249c0e1

Browse files
committed
improve diagnostics
1 parent ecee62b commit 249c0e1

3 files changed

Lines changed: 53 additions & 44 deletions

File tree

include/rsl/_impl/default_construct.hpp

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include <concepts>
55
#include <ranges>
66
#include <algorithm>
7-
#include <tuple> // use rsl::tuple?
7+
#include <tuple> // use rsl::tuple?
88
#include <utility>
99
#include <stdexcept>
1010

@@ -14,10 +14,7 @@ namespace rsl::_impl {
1414
template <std::meta::info R>
1515
consteval std::meta::info make_arg_tuple() {
1616
std::vector<std::meta::info> args;
17-
auto make_optional = [](auto r) {
18-
return substitute(^^std::optional, {
19-
r});
20-
};
17+
auto make_optional = [](auto r) { return substitute(^^std::optional, {r}); };
2118

2219
if constexpr (is_function(R)) {
2320
for (auto& arg : parameters_of(R)) {
@@ -33,8 +30,7 @@ consteval std::meta::info make_arg_tuple() {
3330
constexpr auto ctx = std::meta::access_context::current();
3431
for (auto&& base : bases_of(dealias(R), ctx)) {
3532
args.push_back(extract<std::meta::info (*)()>(
36-
substitute(^^make_arg_tuple, {
37-
reflect_constant(type_of(base))}))());
33+
substitute(^^make_arg_tuple, {reflect_constant(type_of(base))}))());
3834
}
3935
for (auto&& arg : nonstatic_data_members_of(R, ctx)) {
4036
args.push_back(make_optional(type_of(arg)));
@@ -53,12 +49,14 @@ namespace _default_impl {
5349
consteval std::size_t required_args_count(std::meta::info reflection) {
5450
if (is_function(reflection)) {
5551
auto members = parameters_of(reflection);
56-
return std::count_if(members.begin(), members.end(),
57-
[](auto x) { return !has_default_argument(x); });
52+
return std::count_if(members.begin(), members.end(), [](auto x) {
53+
return !has_default_argument(x);
54+
});
5855
} else if (is_type(reflection)) {
5956
auto members = nonstatic_data_members_of(reflection, std::meta::access_context::current());
60-
return std::count_if(members.begin(), members.end(),
61-
[](auto x) { return !has_default_member_initializer(x); });
57+
return std::count_if(members.begin(), members.end(), [](auto x) {
58+
return !has_default_member_initializer(x);
59+
});
6260
} else {
6361
return {};
6462
}
@@ -76,13 +74,13 @@ decltype(auto) do_visit(F visitor, std::size_t index, Args&&... extra_args) {
7674

7775
template <std::size_t Bases, std::size_t Required, typename T, typename F, typename... Args>
7876
decltype(auto) visit(F visitor, ArgumentTuple<T> const& args, Args&&... extra_args) {
79-
constexpr static int size = std::tuple_size_v<ArgumentTuple<T>>;
80-
constexpr static int optional_min = Bases + Required;
81-
constexpr static int branches = size - optional_min;
77+
constexpr static std::size_t size = std::tuple_size_v<ArgumentTuple<T>>;
78+
constexpr static std::size_t optional_min = Bases + Required;
79+
constexpr static std::size_t branches = size - optional_min;
8280

8381
std::size_t index = 0;
84-
template for(constexpr auto Idx : std::views::iota(0zu, size - Bases)) {
85-
if (get<Bases + Idx>(args).has_value()) {
82+
template for (constexpr auto Idx : std::views::iota(Bases, size)) {
83+
if (get<Idx>(args).has_value()) {
8684
++index;
8785
} else {
8886
break;
@@ -91,15 +89,16 @@ decltype(auto) visit(F visitor, ArgumentTuple<T> const& args, Args&&... extra_ar
9189

9290
if (index < Required) {
9391
// fail more gracefully
94-
throw std::runtime_error("not all required arguments are given");
92+
throw std::runtime_error(std::format("expected {} arguments, got {}", size, index));
9593
}
9694

9795
if constexpr (branches == 0) {
9896
// no optional arguments
9997
return visitor(std::make_index_sequence<size - Bases>(), std::forward<Args>(extra_args)...);
10098
} else {
101-
return do_visit<Required, branches>(
102-
visitor, index - Required, std::forward<Args>(extra_args)...);
99+
return do_visit<Required, branches>(visitor,
100+
index - Required,
101+
std::forward<Args>(extra_args)...);
103102
}
104103
}
105104

@@ -109,27 +108,30 @@ template <std::meta::info R>
109108
constexpr inline std::size_t required_arg_count = _default_impl::required_args_count(R);
110109

111110
template <typename T>
112-
constexpr inline std::size_t base_count = bases_of(^^T, std::meta::access_context::current()).size();
111+
constexpr inline std::size_t base_count =
112+
bases_of(^^T, std::meta::access_context::current()).size();
113113

114114
template <typename T>
115115
requires(std::is_aggregate_v<T> && !std::is_array_v<T>)
116116
T default_construct(ArgumentTuple<T> const& args) {
117117
constexpr static auto num_bases = base_count<T>;
118-
constexpr static auto ctx = std::meta::access_context::current();
118+
constexpr static auto ctx = std::meta::access_context::current();
119119

120120
return _default_impl::visit<num_bases, required_arg_count<dealias(^^T)>, T>(
121121
[&]<std::size_t... Idx, std::size_t... BIdx>(std::index_sequence<Idx...>,
122122
std::index_sequence<BIdx...>) {
123-
return T{default_construct<typename [:type_of(bases_of(^^T, ctx)[BIdx]):]>(get<BIdx>(args))...,
124-
*get<num_bases + Idx>(args)...};
123+
return T{
124+
default_construct<typename[:type_of(bases_of(^^T, ctx)[BIdx]):]>(get<BIdx>(args))...,
125+
*get<num_bases + Idx>(args)...};
125126
},
126-
args, std::make_index_sequence<num_bases>());
127+
args,
128+
std::make_index_sequence<num_bases>());
127129
}
128130

129131
template <std::meta::info R>
130132
requires(meta::function<R> || meta::static_member_function<R>)
131-
decltype(auto) default_invoke(ArgumentTuple<typename [:type_of(R):]> const& args) {
132-
return _default_impl::visit<0, required_arg_count<R>, typename [:type_of(R):]>(
133+
decltype(auto) default_invoke(ArgumentTuple<typename[:type_of(R):]> const& args) {
134+
return _default_impl::visit<0, required_arg_count<R>, typename[:type_of(R):]>(
133135
[&]<std::size_t... Idx>(std::index_sequence<Idx...>) { return [:R:](*get<Idx>(args)...); },
134136
args);
135137
}
@@ -141,11 +143,11 @@ decltype(auto) default_invoke() =
141143

142144
template <std::meta::info R, typename T>
143145
requires(meta::nonstatic_member_function<R>)
144-
decltype(auto) default_invoke(T&& self, ArgumentTuple<typename [:type_of(R):]> const& args) {
145-
static_assert(std::convertible_to<std::remove_cvref_t<T>, typename [:parent_of(R):]>,
146+
decltype(auto) default_invoke(T&& self, ArgumentTuple<typename[:type_of(R):]> const& args) {
147+
static_assert(std::convertible_to<std::remove_cvref_t<T>, typename[:parent_of(R):]>,
146148
"wrong type for self argument");
147149

148-
return _default_impl::visit<0, required_arg_count<R>, typename [:type_of(R):]>(
150+
return _default_impl::visit<0, required_arg_count<R>, typename[:type_of(R):]>(
149151
[&]<std::size_t... Idx>(std::index_sequence<Idx...>) {
150152
std::forward<T>(self).[:R:](*get<Idx>(args)...);
151153
},

include/rsl/cli/option.hpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ struct Option {
4141

4242
Unevaluated::handler_type _impl_handler = nullptr;
4343
rsl::string_view name;
44-
// rsl::string_view description = "";
44+
rsl::string_view description;
4545
rsl::span<Argument const> arguments;
4646

4747
std::optional<Unevaluated> parse(ArgParser& parser) {
@@ -74,9 +74,10 @@ struct Option {
7474

7575
consteval Option(std::string_view name, std::meta::info reflection)
7676
: name(std::define_static_string(name)) {
77-
// if (auto desc = annotation_of_type<annotations::Description>(reflection); desc) {
78-
// description = desc->data;
79-
// }
77+
if (auto desc = annotation_of_type<annotations::Description>(reflection); desc) {
78+
description = std::define_static_string(desc->data);
79+
}
80+
8081
std::vector<Argument> args;
8182
std::size_t index = 0;
8283
if (is_object_type(type_of(reflection))) {

include/rsl/config

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ class config {
3737
std::string_view description);
3838

3939
public:
40-
static constexpr auto option = annotations::option;
41-
static constexpr auto value = rsl::placeholders::_0;
40+
static constexpr auto option = annotations::option;
41+
static constexpr auto value = rsl::placeholders::_0;
4242

4343
using shorthand = annotations::Shorthand;
4444
using description = annotations::Description;
@@ -59,6 +59,7 @@ public:
5959

6060
class cli : public config {
6161
static std::string& get_config_path();
62+
6263
public:
6364
static constexpr auto option = annotations::option;
6465
static constexpr auto positional = annotations::positional;
@@ -70,8 +71,7 @@ public:
7071
static std::string_view config_path() { return get_config_path(); }
7172

7273
template <typename T>
73-
[[= option]]
74-
static void config_path(std::string new_path) {
74+
[[= option]] static void config_path(std::string new_path) {
7575
get_config_path() = new_path;
7676
}
7777

@@ -99,16 +99,22 @@ T load_config(std::vector<std::string_view> args_in) {
9999
auto config = json5::load(T::config_path());
100100
config.template update_argtuple<T>(args_tuple);
101101

102-
103102
for (auto argument : parsed_args) {
104103
argument(&args_tuple);
105104
}
106105

107-
// for (auto arg : spec.arguments | std::views::drop(parsed_args.size())) {
108-
// if (!arg.is_optional) {
109-
// parser.fail("Missing required argument `{}`", arg.name);
110-
// }
111-
// }
106+
constexpr auto ctx = std::meta::access_context::current();
107+
constexpr static auto members = std::define_static_array(nonstatic_data_members_of(^^T, ctx));
108+
constexpr auto base_count = bases_of(^^T, ctx).size();
109+
110+
template for (constexpr auto Idx : std::views::iota(0zu, members.size())) {
111+
constexpr static bool has_default = has_default_member_initializer(members[Idx]);
112+
constexpr static auto name = std::define_static_string(identifier_of(members[Idx]));
113+
114+
if (!get<base_count + Idx>(args_tuple).has_value() && !has_default) {
115+
parser.fail("Missing required argument `{}`", name);
116+
}
117+
}
112118

113119
T object = _impl::default_construct<T>(args_tuple);
114120

@@ -122,7 +128,7 @@ T load_config(std::vector<std::string_view> args_in) {
122128

123129
template <typename T>
124130
T load_config(int argc, char** argv) {
125-
return load_config<T>({argv, argv+argc});
131+
return load_config<T>({argv, argv + argc});
126132
}
127133

128134
} // namespace rsl

0 commit comments

Comments
 (0)