libcruft-util/cmdopt2/args.hpp

169 lines
4.4 KiB
C++

/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2022, Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include <cruft/util/cast.hpp>
#include <cruft/util/bool.hpp>
#include <cruft/util/concepts/string.hpp>
#include <cruft/util/debug/assert.hpp>
#include <cruft/util/parse/value.hpp>
#include <optional>
#include <string>
#include <functional>
namespace cruft::cmdopt2 {
struct argument_t {
std::string name;
std::optional<std::string> description;
bool required_ = false;
using acceptor1_t = std::function<void(char const *)>;
std::optional<acceptor1_t> acceptor1;
};
template <typename T>
concept parseable = std::is_arithmetic_v<T> or std::is_same_v<T, cruft::tribool>;
template <typename BaseT>
struct ops_t : argument_t {
template <typename ValueT>
requires (!std::is_convertible_v<ValueT, acceptor1_t>)
BaseT bind (ValueT&&) = delete;
template <typename ValueT>
BaseT
bind (ValueT &ref)
{
CHECK (!acceptor1);
if constexpr (parseable<ValueT>) {
acceptor1 = [&ref] (char const* str) { ref = parse::from_string<ValueT> (str); };
} else {
acceptor1 = [&ref] (char const* str) { ref = str; };
}
return get ();
}
template <typename ValueT>
BaseT
bind (std::optional<ValueT> &ref)
{
CHECK (!acceptor1);
if constexpr (parseable<ValueT>) {
acceptor1 = [&ref] (char const* str) { ref = parse::from_string<ValueT> (str); };
} else {
acceptor1 = [&ref] (char const* str) { ref = str; };
}
return get ();
}
template <typename ValueT>
BaseT
bind (std::vector<ValueT> &ref)
{
if (!repeat_)
throw std::logic_error ("vector argument with non-repeatable argument");
if constexpr (parseable<ValueT>) {
acceptor1 = [&ref] (char const* str) {
ref.emplace_back (parse::from_string<ValueT> (str));
};
} else {
acceptor1 = [&ref] (char const* str) {
ref.emplace_back (str);
};
}
return get ();
}
BaseT
bind (acceptor1_t _acceptor1)
{
CHECK (!acceptor1);
acceptor1 = std::move (_acceptor1);
return get ();
}
BaseT
get (void) const
{
return reinterpret_cast<BaseT const&> (*this);
}
BaseT
acceptor (acceptor1_t _acceptor) const
{
BaseT res = get ();
res.acceptor1 = _acceptor;
return res;
}
bool required (void) const
{
return required_;
}
BaseT required (bool val) const
{
BaseT res = get ();
res.required_ = val;
return res;
}
bool repeat_;
BaseT repeat (bool val) const
{
BaseT res = get ();
res.repeat_ = val;
return res;
}
};
struct positional_t : public ops_t<positional_t> {
positional_t ignore (void) const;
};
positional_t positional (char const *name);
positional_t positional (std::string_view name);
positional_t positional (std::string const &name);
positional_t positional (std::string &&name);
struct keyword_t : public ops_t<keyword_t> {
using acceptor0_t = std::function<void(void)>;
std::optional<acceptor0_t> acceptor0;
using ops_t::acceptor;
keyword_t acceptor (acceptor0_t);
keyword_t ignore (void) const;
keyword_t flag (void) const;
keyword_t flag (std::string_view long_) const;
keyword_t flag (char short_) const;
keyword_t count (int &) const;
keyword_t present (bool &) const;
std::optional<char> short_;
std::optional<std::string> long_;
};
keyword_t keyword (char const *name);
keyword_t keyword (std::string_view name);
keyword_t keyword (std::string const &name);
keyword_t keyword (std::string &&name);
}