argparser/src/single-opt.h
2023-05-17 10:17:56 +02:00

85 lines
2.5 KiB
C++

#ifndef ARGPARSER_SINGLE_OPT_H
#define ARGPARSER_SINGLE_OPT_H
#include <cassert>
#include <format>
#include <memory>
#include <optional>
#include <string>
#include "option.h"
#include "parse-result.h"
#include "type.h"
namespace argparser {
template<typename T>
class option_impl : public option, public std::enable_shared_from_this<option_impl<T>> {
public:
option_impl(std::string name, type_handle_impl<T> type) : option(std::move(name)), type(std::move(type)) {}
std::shared_ptr<option_impl<T>> required() {
required_ = true;
return this->shared_from_this();
}
std::shared_ptr<option_impl<T>> default_value(T val) {
this->default_value_ = val;
this->has_default_value = true;
return this->shared_from_this();
}
void validate(const parse_result &res) const override {
if (this->required_) {
if (!res.has_opt(this->name)) {
throw errors::missing_option_error(this->name);
}
}
}
[[nodiscard]] bool consumes_value() const override {
return true;
}
[[nodiscard]] T get(const parse_result &pr) const {
auto v = pr.get_opt(name);
if (!v.has_value()) {
if (has_default_value) {
return default_value_;
}
throw std::runtime_error(std::format("option {} was not provided", name));
}
return std::any_cast<T>(v);
}
[[nodiscard]] bool has(const parse_result &pr) const {
return pr.has_opt(name);
}
private:
void do_parse(std::optional<std::string> arg, std::any &val) override {
assert(arg.has_value());
const char *parse_end;
auto begin = &*arg->begin();
auto end = &*arg->end();
val = this->type->parse(begin, end, parse_end, internal::parser_allow_undelimited::Any);
if (parse_end != end) {
throw errors::type_parsing_error(this->type->get_name(), std::string(begin, end), parse_end - begin, "unexpected input");
}
}
type_handle_impl<T> type;
bool required_ = false;
bool has_default_value = false;
T default_value_;
};
template<typename T>
using option_handle_impl = std::shared_ptr<option_impl<T>>;
}// namespace argparser
#endif//ARGPARSER_SINGLE_OPT_H