35 #include <type_traits>
36 #include <unordered_map>
46 enum class Type { Empty, Boolean, Integer,
Float, String };
75 constexpr
explicit operator bool()
const {
return !!(*this); }
109 using Interface = std::function<Variable(const std::vector<Variable>&)>;
119 std::string
help = std::string());
123 template<
typename R,
typename... Args>
126 std::string
help = std::string());
127 template<
typename R,
typename... Args>
129 std::string name,
R (*
func)(Args...), std::string
help = std::string());
130 template<
typename T,
typename R,
typename... Args>
132 std::string name,
R (
T::*member_func)(Args...),
T*
t,
133 std::string
help = std::string());
136 template<
typename... Args>
140 const std::string& name,
const std::vector<std::string>& args);
143 const std::string& name,
const std::vector<Variable>& args);
146 std::vector<std::string>
commands()
const;
148 const std::string&
help(
const std::string& name)
const;
163 if (type == Type::Boolean) {
165 }
else if (type == Type::Integer) {
169 }
else if (type == Type::String) {
178 if (v.
type() == Variable::Type::Boolean) {
180 }
else if (v.
m_type == Variable::Type::Integer) {
184 }
else if (v.
m_type == Variable::Type::String) {
196 if (
v.m_type == Type::Boolean) {
198 }
else if (
v.m_type == Type::Integer) {
202 }
else if (
v.m_type == Type::String) {
211 if (v.
m_type == Type::Boolean) {
213 }
else if (v.
m_type == Type::Integer) {
217 }
else if (v.
m_type == Type::String) {
225 struct Variable::Converter<bool> {
226 static constexpr
Type type() {
return Type::Boolean; }
230 struct Variable::Converter<float> {
233 return static_cast<float>(v.
m_float);
237 struct Variable::Converter<double> {
242 struct Variable::Converter<std::string> {
243 static constexpr
Type type() {
return Type::String; }
250 static constexpr
Type type() {
return Type::Integer; }
275 if (
m_type != Variable::Converter<T>::type()) {
276 throw std::invalid_argument(
277 "Requested type is incompatible with stored type");
279 return Variable::Converter<T>::as_t(*
this);
284 namespace dispatcher_impl {
288 template<
typename R,
typename... Args>
289 struct InterfaceWrappper {
292 Variable operator()(
const std::vector<Variable>& args) {
293 return call(args, std::index_sequence_for<Args...>());
295 template<std::size_t...
I>
296 Variable call(
const std::vector<Variable>& args, std::index_sequence<I...>) {
297 return Variable(
func(args.at(I).as<
typename std::decay_t<Args>>()...));
302 template<
typename... Args>
303 struct InterfaceWrappper<
void, Args...> {
306 Variable operator()(
const std::vector<Variable>& args) {
307 return call(args, std::index_sequence_for<Args...>());
309 template<std::size_t...
I>
310 Variable call(
const std::vector<Variable>& args, std::index_sequence<I...>) {
311 func(args.at(I).as<
typename std::decay_t<Args>>()...);
316 template<
typename R,
typename... Args>
319 return InterfaceWrappper<
R, Args...>{std::move(
function)};
322 template<
typename R,
typename... Args>
323 std::vector<Variable::Type>
325 return {Variable(std::decay_t<Args>()).type()...};
334 std::vector<Variable::Type>&& arg_types, std::string
help) {
336 throw std::invalid_argument(
"Can not register command with empty name");
339 throw std::invalid_argument(
340 "Can not register command '" + name +
"' more than once");
343 Command{std::move(
func), std::move(arg_types), std::move(help)};
346 template<
typename R,
typename... Args>
350 auto args = dispatcher_impl::make_types(
func);
352 std::move(name), dispatcher_impl::make_wrapper(std::move(
func)),
353 std::move(args), std::move(help));
356 template<
typename R,
typename... Args>
359 assert(
func &&
"Function pointer must be non-null");
363 template<
typename T,
typename R,
typename... Args>
366 std::string name,
R (
T::*member_func)(Args...),
T*
t, std::string
help) {
367 assert(member_func &&
"Member function pointer must be non-null");
368 assert(t &&
"Object pointer must be non-null");
371 return (t->*member_func)(args...);
377 Dispatcher::call_native(
378 const std::string& name,
const std::vector<Variable>& args) {
379 auto cmd = m_commands.find(name);
380 if (cmd == m_commands.end()) {
381 throw std::invalid_argument(
"Unknown command '" + name +
"'");
383 if (args.size() != cmd->second.argument_types.size()) {
384 throw std::invalid_argument(
"Invalid number of arguments");
386 return cmd->second.func(args);
390 Dispatcher::call_parsed(
391 const std::string& name,
const std::vector<std::string>& args) {
393 auto cmd = m_commands.find(name);
394 if (cmd == m_commands.end()) {
395 throw std::invalid_argument(
"Unknown command '" + name +
"'");
397 if (args.size() != cmd->second.argument_types.size()) {
398 throw std::invalid_argument(
"Invalid number of arguments");
401 std::vector<Variable> vargs;
402 for (std::size_t i = 0; i < args.size(); ++i) {
403 vargs.push_back(Variable::parse_as(args[i], cmd->second.argument_types[i]));
405 return cmd->second.func(vargs);
408 template<
typename... Args>
410 Dispatcher::call(
const std::string& name, Args&&... args) {
412 name, std::vector<Variable>{
Variable(std::forward<Args>(args))...});
415 inline std::vector<std::string>
416 Dispatcher::commands()
const {
417 std::vector<std::string> cmds;
419 for (
const auto& cmd : m_commands) {
420 cmds.emplace_back(cmd.first);
425 inline const std::string&
427 return m_commands.at(name).help;