di 0.1.0
Loading...
Searching...
No Matches
error.h
Go to the documentation of this file.
1#pragma once
2
5#include "di/format/style.h"
9#include "di/types/prelude.h"
16
17namespace di::cli {
25
35
37 char short_name { 0 };
38
39 auto operator==(ShortOptionMissingRequiredValue const&) const -> bool = default;
40};
41
47
54
62
64 char bad_character { 0 };
65
66 auto operator==(UnknownShortOption const&) const -> bool = default;
67};
68
75
81
88
95
97 auto operator==(MissingSubcommand const&) const -> bool = default;
98};
99
104
107 bool use_colors { false };
108
109 auto operator==(ConcreteError const&) const -> bool = default;
110};
111
112class Error {
113public:
114 Error() = default;
115
116 constexpr explicit Error(ErrorVariant error, bool use_colors)
117 : m_value(di::make_box<ConcreteError>(di::move(error), use_colors)) {}
118
119 constexpr auto empty() const { return !m_value; }
120
121 constexpr auto inner() const -> ConcreteError const& { return *m_value; }
122
123 constexpr auto operator==(Error const& other) const -> bool {
124 if (this->empty() != other.empty()) {
125 return false;
126 }
127 if (this->empty()) {
128 return true;
129 }
130 return *this->m_value == *other.m_value;
131 }
132
133private:
134 constexpr friend auto tag_invoke(Tag<concepts::trivially_relocatable>, InPlaceType<Error>) -> bool { return true; }
135
137};
138
139class ErrorDomain;
140
142
143class ErrorDomain final : public StatusCodeDomain {
144private:
145 using Base = StatusCodeDomain;
146
147public:
148 using Value = Error;
150
151 constexpr explicit ErrorDomain(UniqueId id = 0x3acfeb8908d1656b) : Base(id) {}
152
153 ErrorDomain(ErrorDomain const&) = default;
155
156 auto operator=(ErrorDomain const&) -> ErrorDomain& = default;
157 auto operator=(ErrorDomain&&) -> ErrorDomain& = default;
158
159 constexpr static auto get() -> ErrorDomain const&;
160
161 auto name() const -> container::ErasedString override { return container::ErasedString(u8"CLI Error Domain"); }
162
163 auto payload_info() const -> PayloadInfo override {
164 return { sizeof(Value), sizeof(Value) + sizeof(StatusCodeDomain const*),
165 container::max(alignof(Value), alignof(StatusCodeDomain const*)) };
166 }
167
168protected:
169 constexpr auto do_failure(vocab::StatusCode<void> const& code) const -> bool override {
170 auto const& value = down_cast(code);
171 return !value.value().empty();
172 }
173
174 constexpr auto do_equivalent(vocab::StatusCode<void> const& a, vocab::StatusCode<void> const& b) const
175 -> bool override {
176 DI_ASSERT(a.domain() == *this);
177 return b.domain() == *this && down_cast(a).value() == down_cast(b).value();
178 }
179
180 constexpr auto do_convert_to_generic(vocab::StatusCode<void> const& a) const -> vocab::GenericCode override {
181 DI_ASSERT(a.domain() == *this);
182 return a.failure() ? platform::BasicError::InvalidArgument : platform::BasicError::Success;
183 }
184
185 constexpr auto do_message(vocab::StatusCode<void> const& code) const -> container::ErasedString override {
186 DI_ASSERT(code.domain() == *this);
187 using Enc = di::String::Encoding;
188
189 constexpr auto argument_effect = di::FormatColor::Green;
190 constexpr auto option_effect = di::FormatColor::Cyan;
191 constexpr auto value_effect = di::FormatEffect::Bold;
192 constexpr auto subcommand_effect = di::FormatEffect::Bold;
193
194 auto const& value = down_cast(code).value().inner();
195 auto writer = StringWriter<>(value.use_colors);
197 [&](ParseArgumentError const& error) {
198 writer_print<Enc>(writer, "Failed to parse '{}' as values for argument '{}': {}"_sv,
199 di::Styled(error.bad_values, value_effect),
200 di::Styled(error.argument_name, argument_effect), error.parse_error);
201 },
202 [&](ParseOptionError const& error) {
203 auto option_name = error.short_name != 0 ? di::format("-{}"_sv, error.short_name)
204 : di::format("--{}"_sv, error.long_name);
205 writer_print<Enc>(writer, "Failed to parse '{}' as value for option '{}': {}"_sv,
206 di::Styled(error.bad_value, value_effect),
207 di::Styled(option_name, option_effect), error.parse_error);
208 },
209 [&](ShortOptionMissingRequiredValue const& error) {
210 auto option_name = di::format("-{}"_sv, error.short_name);
211 writer_print<Enc>(writer, "Missing required value for option '{}'"_sv,
212 di::Styled(option_name, option_effect));
213 },
214 [&](LongOptionMissingRequiredValue const& error) {
215 auto option_name = di::format("--{}"_sv, error.long_name);
216 writer_print<Enc>(writer, "Missing required value for option '{}'"_sv,
217 di::Styled(option_name, option_effect));
218 },
219 [&](MissingRequiredOption const& error) {
220 auto option_name = ""_s;
221 if (error.short_name) {
222 option_name.push_back('-');
223 option_name.push_back(error.short_name.value());
224 }
225 if (error.long_name) {
226 if (!option_name.empty()) {
227 option_name.push_back('/');
228 }
229 option_name.push_back('-');
230 option_name.push_back('-');
231 option_name.append(di::to_string(error.long_name.value()));
232 }
233 writer_print<Enc>(writer, "Option '{}' must be specified"_sv,
234 di::Styled(option_name, option_effect));
235 },
236 [&](MissingRequiredArgument const& error) {
237 writer_print<Enc>(writer, "Argument '{}' must be provided"_sv,
238 di::Styled(error.argument_name, argument_effect));
239 },
240 [&](UnknownShortOption const& error) {
241 auto option_name = di::format("-{}"_sv, error.bad_character);
242 writer_print<Enc>(writer, "Option '{}' is not a valid option"_sv,
243 di::Styled(option_name, option_effect));
244 },
245 [&](UnknownLongOption const& error) {
246 auto option_name = di::format("--{}"_sv, error.bad_option);
247 writer_print<Enc>(writer, "Option '{}' is not a valid option"_sv,
248 di::Styled(option_name, option_effect));
249 if (error.closest_match) {
251 writer, ". Did you mean '{}'?"_sv,
252 di::Styled(di::format("--{}"_sv, error.closest_match.value()), option_effect));
253 }
254 },
255 [&](ExtraArguments const& error) {
256 writer_print<Enc>(writer, "Extra arguments {} are not recognized"_sv,
257 di::Styled(error.extra_arguments, value_effect));
258 },
259 [&](ParseSubcommandError const& error) {
260 writer_print<Enc>(writer, "Failed parsing arguments for subcommand '{}': {}"_sv,
261 di::Styled(error.subcommand_name, subcommand_effect), error.parse_error);
262 },
263 [&](UnknownSubcommand const& error) {
264 writer_print<Enc>(writer, "Subcommand '{}' is not recognized"_sv,
265 di::Styled(error.bad_subcommand, subcommand_effect));
266 if (error.closest_match) {
267 writer_print<Enc>(writer, ". Did you mean '{}'?"_sv,
268 di::Styled(error.closest_match.value(), subcommand_effect));
269 }
270 },
271 [&](MissingSubcommand const&) {
272 writer_print<Enc>(writer, "No subcommand argument specified"_sv);
273 }),
274 value.error);
275 return di::move(writer).output();
276 }
277
278private:
279 template<typename Domain>
281
282 constexpr auto down_cast(vocab::StatusCode<void> const& code) const -> ErrorCode const& {
283 DI_ASSERT(code.domain() == *this);
284 return static_cast<ErrorCode const&>(code);
285 }
286};
287
288constexpr inline auto error_domain = ErrorDomain {};
289
290constexpr auto ErrorDomain::get() -> ErrorDomain const& {
291 return error_domain;
292}
293
295 return ErrorCode(di::in_place, di::move(error));
296}
297}
#define DI_ASSERT(...)
Definition assert_bool.h:7
Definition error.h:143
constexpr auto do_message(vocab::StatusCode< void > const &code) const -> container::ErasedString override
Definition error.h:185
Base::UniqueId UniqueId
Definition error.h:149
constexpr auto do_convert_to_generic(vocab::StatusCode< void > const &a) const -> vocab::GenericCode override
Definition error.h:180
constexpr auto do_equivalent(vocab::StatusCode< void > const &a, vocab::StatusCode< void > const &b) const -> bool override
Definition error.h:174
auto name() const -> container::ErasedString override
Definition error.h:161
constexpr auto do_failure(vocab::StatusCode< void > const &code) const -> bool override
Definition error.h:169
ErrorDomain(ErrorDomain const &)=default
auto operator=(ErrorDomain const &) -> ErrorDomain &=default
constexpr ErrorDomain(UniqueId id=0x3acfeb8908d1656b)
Definition error.h:151
auto operator=(ErrorDomain &&) -> ErrorDomain &=default
Error Value
Definition error.h:148
auto payload_info() const -> PayloadInfo override
Definition error.h:163
static constexpr auto get() -> ErrorDomain const &
Definition error.h:290
ErrorDomain(ErrorDomain &&)=default
Definition error.h:112
Error()=default
constexpr auto inner() const -> ConcreteError const &
Definition error.h:121
constexpr friend auto tag_invoke(Tag< concepts::trivially_relocatable >, InPlaceType< Error >) -> bool
Definition error.h:134
constexpr Error(ErrorVariant error, bool use_colors)
Definition error.h:116
constexpr auto operator==(Error const &other) const -> bool
Definition error.h:123
constexpr auto empty() const
Definition error.h:119
Definition erased_string.h:21
Definition vector.h:25
Definition style.h:131
Definition string_writer.h:14
Definition box.h:28
Definition optional_forward_declaration.h:5
constexpr StatusCodeDomain(UniqueId id)
Definition status_code_domain.h:29
constexpr auto id() const
Definition status_code_domain.h:12
u64 UniqueId
Definition status_code_domain.h:10
Definition status_code_forward_declaration.h:11
Definition variant.h:30
Definition argument.h:13
constexpr auto error_domain
Definition error.h:288
vocab::StatusCode< ErrorDomain > ErrorCode
Definition error.h:141
Variant< ParseArgumentError, ParseOptionError, ShortOptionMissingRequiredValue, LongOptionMissingRequiredValue, MissingRequiredOption, MissingRequiredArgument, UnknownShortOption, UnknownLongOption, ExtraArguments, ParseSubcommandError, UnknownSubcommand, MissingSubcommand > ErrorVariant
Definition error.h:100
Definition sequence.h:12
string::StringViewImpl< string::Utf8Encoding > StringView
Definition string_view.h:12
constexpr auto max
Definition max.h:49
string::StringViewImpl< string::TransparentEncoding > TransparentStringView
Definition string_view.h:13
size_t usize
Definition integers.h:33
__UINT8_TYPE__ u8
Definition integers.h:9
di::meta::Decay< decltype(T)> Tag
Definition tag_invoke.h:28
StatusCode< platform::GenericDomain > GenericCode
Definition status_code_forward_declaration.h:13
StatusCode< Erased< long > > Error
Definition error.h:8
Definition any_storable.h:9
constexpr auto make_box
Definition box.h:171
constexpr tag_invoke_detail::TagInvokeFn tag_invoke
Definition tag_invoke.h:22
constexpr auto format
Definition format.h:7
constexpr auto writer_print
Definition writer_print.h:21
constexpr auto visit(Vis &&visitor, Vars &&... variants) -> R
Definition visit.h:39
constexpr auto to_string
Definition to_string.h:14
constexpr auto in_place
Definition in_place.h:8
constexpr auto overload
Definition overload.h:28
Definition error.h:105
bool use_colors
Definition error.h:107
ErrorVariant error
Definition error.h:106
auto operator==(ConcreteError const &) const -> bool=default
Definition error.h:76
di::Vector< di::TransparentStringView > extra_arguments
Definition error.h:77
auto operator==(ExtraArguments const &) const -> bool=default
auto operator==(LongOptionMissingRequiredValue const &) const -> bool=default
di::TransparentStringView long_name
Definition error.h:43
usize count_received
Definition error.h:57
di::StringView argument_name
Definition error.h:56
auto operator==(MissingRequiredArgument const &) const -> bool=default
usize count_needed
Definition error.h:58
Definition error.h:48
auto operator==(MissingRequiredOption const &) const -> bool=default
di::Optional< char > short_name
Definition error.h:49
di::Optional< di::TransparentStringView > long_name
Definition error.h:50
Definition error.h:96
auto operator==(MissingSubcommand const &) const -> bool=default
Definition error.h:18
di::Vector< di::TransparentStringView > bad_values
Definition error.h:20
di::Error parse_error
Definition error.h:21
di::StringView argument_name
Definition error.h:19
auto operator==(ParseArgumentError const &) const -> bool=default
Definition error.h:26
di::TransparentStringView bad_value
Definition error.h:29
char short_name
Definition error.h:27
auto operator==(ParseOptionError const &) const -> bool=default
di::TransparentStringView long_name
Definition error.h:28
di::Error parse_error
Definition error.h:31
bool is_long
Definition error.h:30
Definition error.h:82
di::TransparentStringView subcommand_name
Definition error.h:83
auto operator==(ParseSubcommandError const &) const -> bool=default
di::Error parse_error
Definition error.h:84
auto operator==(ShortOptionMissingRequiredValue const &) const -> bool=default
char short_name
Definition error.h:37
Definition error.h:69
auto operator==(UnknownLongOption const &) const -> bool=default
di::Optional< di::TransparentStringView > closest_match
Definition error.h:71
di::TransparentStringView bad_option
Definition error.h:70
Definition error.h:63
char bad_character
Definition error.h:64
auto operator==(UnknownShortOption const &) const -> bool=default
Definition error.h:89
di::TransparentStringView bad_subcommand
Definition error.h:90
di::Optional< di::TransparentStringView > closest_match
Definition error.h:91
auto operator==(UnknownSubcommand const &) const -> bool=default
Definition in_place_type.h:5
Definition status_code_domain.h:16