293 lines
9.9 KiB
C++
293 lines
9.9 KiB
C++
// Copyright (c) 2020-present, Roland Munguia & Tristan Florian Bouchard.
|
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
|
|
|
#ifndef CSYS_COMMAND_H
|
|
#define CSYS_COMMAND_H
|
|
#pragma once
|
|
|
|
#include <functional>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
#include "csys/arguments.h"
|
|
#include "csys/exceptions.h"
|
|
#include "csys/item.h"
|
|
|
|
namespace csys
|
|
{
|
|
/*!
|
|
* \brief
|
|
* Non-templated class that allows for the storage of commands as well as accessing certain functionality of
|
|
* said commands.
|
|
*/
|
|
struct CommandBase
|
|
{
|
|
/*!
|
|
* \brief
|
|
* Default virtual destructor
|
|
*/
|
|
virtual ~CommandBase() = default;
|
|
|
|
/*!
|
|
* \brief
|
|
* Parses and runs the function held within the child class
|
|
* \param input
|
|
* String of arguments for the command to parse and pass to the function
|
|
* \return
|
|
* Returns item error if the parsing in someway was messed up, and none if there was no issue
|
|
*/
|
|
virtual Item operator()(String &input) = 0;
|
|
|
|
/*!
|
|
* \brief
|
|
* Gets info about the command and usage
|
|
* \return
|
|
* String containing info about the command
|
|
*/
|
|
[[nodiscard]] virtual std::string Help() = 0;
|
|
|
|
/*!
|
|
* \brief
|
|
* Getter for the number of arguments the command takes
|
|
* \return
|
|
* Returns the number of arguments taken by the command
|
|
*/
|
|
[[nodiscard]] virtual size_t ArgumentCount() const = 0;
|
|
|
|
/*!
|
|
* \brief
|
|
* Deep copies a command
|
|
* \return
|
|
* Pointer to newly copied command
|
|
*/
|
|
[[nodiscard]] virtual CommandBase* Clone() const = 0;
|
|
};
|
|
|
|
/*!
|
|
* \brief
|
|
* Base template for a command that takes N amount of arguments
|
|
* \tparam Fn
|
|
* Decltype of function to be called when command is parsed and ran
|
|
* \tparam Args
|
|
* Argument type list that is proportional to the argument list of the function Fn
|
|
*/
|
|
template<typename Fn, typename ...Args>
|
|
class CSYS_API Command : public CommandBase
|
|
{
|
|
public:
|
|
/*!
|
|
* \brief
|
|
* Constructor that sets the name, description, function and arguments as well as add a null argument
|
|
* for parsing
|
|
* \param name
|
|
* Name of the command to call by
|
|
* \param description
|
|
* Info about the command
|
|
* \param function
|
|
* Function to run when command is called
|
|
* \param args
|
|
* Arguments to be used for parsing and passing into the function. Must be of type "Arg<T>"
|
|
*/
|
|
Command(String name, String description, Fn function, Args... args) : m_Name(std::move(name)),
|
|
m_Description(std::move(description)),
|
|
m_Function(function),
|
|
m_Arguments(args..., Arg<NULL_ARGUMENT>())
|
|
{}
|
|
|
|
/*!
|
|
* \brief
|
|
* Parses and runs the function m_Function
|
|
* \param input
|
|
* String of arguments for the command to parse and pass to the function
|
|
* \return
|
|
* Returns item error if the parsing in someway was messed up, and none if there was no issue
|
|
*/
|
|
Item operator()(String &input) final
|
|
{
|
|
try
|
|
{
|
|
// Try to parse and call the function
|
|
constexpr int argumentSize = sizeof... (Args);
|
|
Call(input, std::make_index_sequence<argumentSize + 1>{}, std::make_index_sequence<argumentSize>{});
|
|
}
|
|
catch (Exception &ae)
|
|
{
|
|
// Error happened with parsing
|
|
return Item(eERROR) << (m_Name.m_String + ": " + ae.what());
|
|
}
|
|
return Item(eNONE);
|
|
}
|
|
|
|
/*!
|
|
* \brief
|
|
* Gets info about the command and usage
|
|
* \return
|
|
* String containing info about the command
|
|
*/
|
|
[[nodiscard]] std::string Help() final
|
|
{
|
|
return m_Name.m_String + DisplayArguments(std::make_index_sequence<sizeof ...(Args)>{}) + "\n\t\t- " +
|
|
m_Description.m_String + "\n\n";
|
|
}
|
|
|
|
/*!
|
|
* \brief
|
|
* Getter for the number of arguments the command takes
|
|
* \return
|
|
* Returns the number of arguments taken by the command
|
|
*/
|
|
[[nodiscard]] size_t ArgumentCount() const final
|
|
{
|
|
return sizeof... (Args);
|
|
}
|
|
|
|
/*!
|
|
* \brief
|
|
* Deep copies a command
|
|
* \return
|
|
* Pointer to newly copied command
|
|
*/
|
|
[[nodiscard]] CommandBase* Clone() const final
|
|
{
|
|
return new Command<Fn, Args...>(*this);
|
|
}
|
|
private:
|
|
/*!
|
|
* \brief
|
|
* Parses arguments and passes them into the command to be ran
|
|
* \tparam Is_p
|
|
* Index sequence from 0 to Argument Count + 1, used for parsing
|
|
* \tparam Is_c
|
|
* Index sequence from 0 to Argument Count, used for passing into the function
|
|
* \param input
|
|
* String of arguments to be parsed
|
|
*/
|
|
template<size_t... Is_p, size_t... Is_c>
|
|
void Call(String &input, const std::index_sequence<Is_p...> &, const std::index_sequence<Is_c...> &)
|
|
{
|
|
size_t start = 0;
|
|
|
|
// Parse arguments
|
|
int _[]{0, (void(std::get<Is_p>(m_Arguments).Parse(input, start)), 0)...};
|
|
(void) (_);
|
|
|
|
// Call function with unpacked tuple
|
|
m_Function((std::get<Is_c>(m_Arguments).m_Arg.m_Value)...);
|
|
}
|
|
|
|
/*!
|
|
* \brief
|
|
* Displays the usage for running the command successfully
|
|
* \tparam Is
|
|
* Index sequence from 0 to Argument CountH
|
|
* \return
|
|
* Returns a string containing the usage of the command
|
|
*/
|
|
template<size_t ...Is>
|
|
std::string DisplayArguments(const std::index_sequence<Is...> &)
|
|
{
|
|
return (std::get<Is>(m_Arguments).Info() + ...);
|
|
}
|
|
|
|
const String m_Name; //!< Name of command
|
|
const String m_Description; //!< Description of the command
|
|
std::function<void(typename Args::ValueType...)> m_Function; //!< Function to be invoked as command
|
|
std::tuple<Args..., Arg<NULL_ARGUMENT>> m_Arguments; //!< Arguments to be passed into m_Function
|
|
};
|
|
|
|
/*!
|
|
* \brief
|
|
* Template specialization for a command that doesn't take any arguments
|
|
* \tparam Fn
|
|
* Decltype of function to be called when the command is invoked
|
|
*/
|
|
template<typename Fn>
|
|
class CSYS_API Command<Fn> : public CommandBase
|
|
{
|
|
public:
|
|
/*!
|
|
* \brief
|
|
* Constructor that sets the name, description and function. A null argument will be added to the arguments
|
|
* for parsing
|
|
* \param name
|
|
* Name of the command to call by
|
|
* \param description
|
|
* Info about the command
|
|
* \param function
|
|
* Function to run when command is called
|
|
*/
|
|
Command(String name, String description, Fn function) : m_Name(std::move(name)),
|
|
m_Description(std::move(description)),
|
|
m_Function(function), m_Arguments(Arg<NULL_ARGUMENT>())
|
|
{}
|
|
|
|
/*!
|
|
* \brief
|
|
* Parses and runs the function m_Function
|
|
* \param input
|
|
* String of arguments for the command to parse and pass to the function. This should be empty
|
|
* \return
|
|
* Returns item error if the parsing in someway was messed up, and none if there was no issue
|
|
*/
|
|
Item operator()(String &input) final
|
|
{
|
|
// call the function
|
|
size_t start = 0;
|
|
try
|
|
{
|
|
// Check to see if input is all whitespace
|
|
std::get<0>(m_Arguments).Parse(input, start);
|
|
}
|
|
catch (Exception &ae)
|
|
{
|
|
// Command had something passed into it
|
|
return Item(eERROR) << (m_Name.m_String + ": " + ae.what());
|
|
}
|
|
|
|
// Call function
|
|
m_Function();
|
|
return Item(eNONE);
|
|
}
|
|
|
|
/*!
|
|
* \brief
|
|
* Gets info about the command and usage
|
|
* \return
|
|
* String containing info about the command
|
|
*/
|
|
[[nodiscard]] std::string Help() final
|
|
{
|
|
return m_Name.m_String + "\n\t\t- " + m_Description.m_String + "\n\n";
|
|
}
|
|
|
|
/*!
|
|
* \brief
|
|
* Getter for the number of arguments the command takes
|
|
* \return
|
|
* 0
|
|
*/
|
|
[[nodiscard]] size_t ArgumentCount() const final
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
* \brief
|
|
* Deep copies a command
|
|
* \return
|
|
* Pointer to newly copied command
|
|
*/
|
|
[[nodiscard]] CommandBase* Clone() const final
|
|
{
|
|
return new Command<Fn>(*this);
|
|
}
|
|
private:
|
|
|
|
const String m_Name; //!< Name of command
|
|
const String m_Description; //!< Description of the command
|
|
std::function<void(void)> m_Function; //!< Function to be invoked as command
|
|
std::tuple<Arg<NULL_ARGUMENT>> m_Arguments; //!< Arguments to be passed into m_Function
|
|
};
|
|
}
|
|
|
|
#endif //CSYS_COMMAND_H
|