// Copyright (C) 2022 TiltedPhoques SRL. // For licensing information see LICENSE at the root of this distribution. #pragma once #include #include #include #include namespace Console { // CommandNode // CommandData class CommandBase { friend class ConsoleRegistry; public: enum class Type { kBoolean, kNumeric, kString, kUnknown // I think we should introduce signed_numeric // and unsigned numeric }; // TODO: arguments. enum class Flags { kAdminOnly, KUserCreated, }; CommandBase(CommandBase*& parent, const char* n, const char* d, size_t argc) : m_name(n) , m_desc(d) , m_argCount(argc) , next(parent) { parent = this; } explicit CommandBase(const char* n, const char* d, size_t argc) : CommandBase(ROOT(), n, d, argc) { } protected: // // TODO: does it make sense to even accept any string... // TODO: make concept. // template // static constexpr bool IsStringType = _Is_any_of_v, const char*, std::string>; template static constexpr bool IsAnyOf = // true if and only if _Ty is in _Types std::disjunction_v...>; template static constexpr Type ToValueTypeIndex() { if constexpr (std::is_same_v) return Type::kBoolean; if constexpr (std::is_integral_v) return Type::kNumeric; if constexpr (IsAnyOf, const char*, std::string>) return Type::kString; // static_assert(false, "Unsupported type."); return Type::kUnknown; } private: static inline CommandBase*& ROOT() noexcept { static CommandBase* root{nullptr}; return root; } void Invoke() {} public: const char* m_name; const char* m_desc; // Type info const size_t m_argCount; Type* m_pArgIndicesArray = nullptr; std::function m_Handler; // Next static node. CommandBase* next = nullptr; }; // We must specify the expected argument types through the template to be able // to do proper error checking template class Command : public CommandBase { static constexpr size_t N = sizeof...(Ts); public: // Construct the command and fill the indices list at runtime. // and no, it couldnd be done with std::function template explicit Command(const char* acName, const char* acDesc, const TFunctor& functor) : m_indices{(ToValueTypeIndex())..., Type::kUnknown} , CommandBase(acName, acDesc, N) { CommandBase::m_pArgIndicesArray = reinterpret_cast(&m_indices); CommandBase::m_Handler = functor; } constexpr size_t arg_count() { return N; } private: // At the end we store a stop gap type that should never be hit. // We also do this to avoid a potential array of size null Type m_indices[N + 1]; }; } // namespace Console