diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 7a8872a..e0b3c74 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -1,6 +1,6 @@ # Setup source files set(SOURCE_FILES - timer/timer.cpp timer/timer_manager.cpp thread_pool.cpp timer/timer_context.cpp timer/cancel_token.cpp timer/synchronized_timer.cpp object.cpp parser/parser.cpp parser/parser_manager.cpp config.cpp serialize.cpp parsers/json.cpp unicode.cpp io/message.cpp app_parameters.cpp) + timer/timer.cpp timer/timer_manager.cpp thread_pool.cpp timer/timer_context.cpp timer/cancel_token.cpp timer/synchronized_timer.cpp object.cpp parser/parser.cpp parser/parser_manager.cpp config.cpp serialize.cpp parsers/json.cpp unicode.cpp io/command.cpp io/command_context.cpp io/message.cpp app_parameters.cpp) # Setup library build target add_library(jessilib ${SOURCE_FILES}) diff --git a/src/common/io/command.cpp b/src/common/io/command.cpp new file mode 100644 index 0000000..981ad99 --- /dev/null +++ b/src/common/io/command.cpp @@ -0,0 +1,50 @@ +/** + * Copyright (C) 2019 Jessica James. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Written by Jessica James + */ + +#include "io/command.hpp" +#include "io/command_manager.hpp" + +namespace jessilib { +namespace io { + +command::command(callback_t in_callback, std::string_view in_label) + : m_callback{ std::move(in_callback) }, + m_label{ std::move(in_label) } { + // Register command + command_manager::instance().register_command(*this); +} + +command::~command() { + // Unregister command + command_manager::instance().unregister_command(*this); +} + +std::string_view command::label() const { + return m_label; +} + +void command::execute(command_context& in_context) const { + m_callback(in_context); +} + +command test_command{ [](command_context&) { + // do stuff +}, "test" }; + +} // namespace io +} // namespace jessilib diff --git a/src/common/io/command_context.cpp b/src/common/io/command_context.cpp new file mode 100644 index 0000000..6a2cff9 --- /dev/null +++ b/src/common/io/command_context.cpp @@ -0,0 +1,97 @@ +/** + * Copyright (C) 2019 Jessica James. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Written by Jessica James + */ + +#include "io/command_context.hpp" + +namespace jessilib { +namespace io { + +command_context::command_context(std::string_view in_input) + : m_input{ in_input } { + // Strip leading whitespace + std::size_t pos = in_input.find_first_not_of(' '); + if (pos != std::string_view::npos) { + in_input.remove_prefix(pos); + + // Whitespace is stripped; parse keyword from input + pos = in_input.find(' '); + if (pos == std::string_view::npos) { + pos = in_input.size(); + } + m_keyword = in_input.substr(0, pos); + in_input.remove_prefix(pos); + + // Strip leading whitespace and parse parameter from remaining input + pos = in_input.find_first_not_of(' '); + if (pos != std::string_view::npos) { + in_input.remove_prefix(pos); + m_parameter = in_input; + } + } +} + +command_context::command_context(std::string_view in_input, std::string_view in_keyword, std::string_view in_parameter) + : m_input{ std::move(in_input) }, + m_keyword{ std::move(in_keyword) }, + m_parameter{ std::move(in_parameter) } { + // Empty ctor body +} + +std::string_view command_context::input() const { + return m_input; +} + +std::string_view command_context::keyword() const { + return m_keyword; +} + +std::string_view command_context::parameter() const { + return m_parameter; +} + +std::vector command_context::paramaters() const { + std::vector result; + std::string_view parameter = m_parameter; + + // Strip leading whitespace + std::size_t pos = parameter.find_first_not_of(' '); + if (pos == std::string_view::npos) { + // parameter is empty; return empty vector + return result; + } + parameter.remove_prefix(pos); + + // Parse parameter into result + while (!parameter.empty()) { + // Parse word from parameter into result + pos = parameter.find(' '); + if (pos == std::string_view::npos) { + pos = parameter.size(); + } + result.push_back(parameter.substr(0, pos)); + + // Strip word and trailing whitespace + parameter.remove_prefix(pos); + parameter.remove_prefix(std::min(parameter.find_first_not_of(' '), parameter.size())); + } + + return result; +}; + +} // namespace io +} // namespace jessilib diff --git a/src/include/io/command.hpp b/src/include/io/command.hpp new file mode 100644 index 0000000..43ee7c9 --- /dev/null +++ b/src/include/io/command.hpp @@ -0,0 +1,65 @@ +/** + * Copyright (C) 2019 Jessica James. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Written by Jessica James + */ + +#pragma once + +#include +#include +#include "command_context.hpp" + +namespace jessilib { +namespace io { + +class basic_command { +public: + virtual ~basic_command() = default; + virtual std::string_view label() const = 0; + virtual void execute(command_context& in_context) const = 0; +}; // class basic_command + +class command : public basic_command { +public: + // Types + using callback_t = std::function; + + // Delete all implicit constructors and assignment operators + command() = delete; + command(const command&) = delete; + command(command&&) = delete; + command& operator=(const command&) = delete; + command& operator=(command&&) = delete; + + // Instantiates and self-registers a command + command(callback_t in_callback, std::string_view in_label); + + // Cleans up and unregisters the command + virtual ~command(); + + // Unique label associated with command + virtual std::string_view label() const override; + + // Executes the command + virtual void execute(command_context& in_context) const override; + +private: + callback_t m_callback; + std::string_view m_label; +}; // class command + +} // namespace io +} // namespace jessilib \ No newline at end of file diff --git a/src/include/io/command_context.hpp b/src/include/io/command_context.hpp new file mode 100644 index 0000000..5bdfe35 --- /dev/null +++ b/src/include/io/command_context.hpp @@ -0,0 +1,54 @@ +/** + * Copyright (C) 2019 Jessica James. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Written by Jessica James + */ + +#pragma once + +#include +#include "object.hpp" +#include "message.hpp" + +namespace jessilib { +namespace io { + +class command_context { +public: + command_context(std::string_view in_input); + command_context(std::string_view in_input, std::string_view in_keyword, std::string_view in_parameter); + + /** User input */ + std::string_view input() const; + std::string_view keyword() const; + std::string_view parameter() const; + std::vector paramaters() const; + + /** Reply */ + virtual bool privateReply(const formatted_message& in_message); // Reply to invoker privately (i.e: PM) + virtual bool publicReply(const formatted_message& in_message); // Reply to invoker publicly (i.e: channel) + + /** Additional contextual details */ + virtual object details() const = 0; // Additional details + virtual std::string getText(std::string_view tag) const = 0; // Get localized text + +private: + std::string_view m_input; + std::string_view m_keyword; + std::string_view m_parameter; +}; // class command_context + +} // namespace io +} // namespace jessilib diff --git a/src/include/io/command_manager.hpp b/src/include/io/command_manager.hpp new file mode 100644 index 0000000..df03fb6 --- /dev/null +++ b/src/include/io/command_manager.hpp @@ -0,0 +1,69 @@ +/** + * Copyright (C) 2019 Jessica James. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Written by Jessica James + */ + +#pragma once + +#include +#include "command.hpp" + +namespace jessilib { +namespace io { + +class command_manager { +public: + struct entry { + basic_command* m_command; + }; + + void register_command(basic_command& in_command); + void unregister_command(basic_command& in_command); + bool execute_command(const command_context& in_context); + + // executes a predicate for each command, until the predicate returns false or no commands remain + template // TODO: add check for non-const + void foreach(predicate_t&& in_predicate) { + std::lock_guard guard{ m_commands_mutex }; + for (auto& command_entry : m_commands) { + if (!in_predicate(command_entry)) { + // Predicate returned false; we're done here + return; + } + } + } + + // executes a predicate for each command, until the predicate returns false or no commands remain + template // TODO: add check for const + void foreach(predicate_t&& in_predicate) const { + std::shared_lock guard{ m_commands_mutex }; + for (const auto& command_entry : m_commands) { + if (!in_predicate(command_entry)) { + // Predicate returned false; we're done here + return; + } + } + } + + static command_manager& instance(); + +private: + std::vector m_commands; + mutable std::shared_mutex m_commands_mutex; +}; + +} // namespace io +} // namespace jessilib \ No newline at end of file diff --git a/src/test/object.cpp b/src/test/object.cpp index f8142e0..bcd324e 100644 --- a/src/test/object.cpp +++ b/src/test/object.cpp @@ -28,6 +28,20 @@ using unsigned_char_t = unsigned char; using long_long_t = long long; using long_double_t = long double; +using map_str_str = std::map; +using map_str_strv = std::map; +using map_str_obj = std::map; +using map_strv_str = std::map; +using map_strv_strv = std::map; +using map_strv_obj = std::map; + +using unordered_map_str_str = std::unordered_map; +using unordered_map_str_strv = std::unordered_map; +using unordered_map_str_obj = std::unordered_map; +using unordered_map_strv_str = std::unordered_map; +using unordered_map_strv_strv = std::unordered_map; +using unordered_map_strv_obj = std::unordered_map; + /** basic tests; these test function calls against null objects and heavily test for compilation errors */ TEST(ObjectTest, basic) { @@ -148,20 +162,15 @@ TEST(ObjectTest, basic_has_unordered_set) { EXPECT_FALSE(obj.has>()); } -using map_str_str = std::map; -using map_str_strv = std::map; -using map_str_obj = std::map; - -using unordered_map_str_str = std::unordered_map; -using unordered_map_str_strv = std::unordered_map; -using unordered_map_str_obj = std::unordered_map; - TEST(ObjectTest, basic_has_map) { object obj; EXPECT_FALSE(obj.has()); EXPECT_FALSE(obj.has()); EXPECT_FALSE(obj.has()); + EXPECT_FALSE(obj.has()); + EXPECT_FALSE(obj.has()); + EXPECT_FALSE(obj.has()); } TEST(ObjectTest, basic_has_unordered_map) { @@ -170,6 +179,9 @@ TEST(ObjectTest, basic_has_unordered_map) { EXPECT_FALSE(obj.has()); EXPECT_FALSE(obj.has()); EXPECT_FALSE(obj.has()); + EXPECT_FALSE(obj.has()); + EXPECT_FALSE(obj.has()); + EXPECT_FALSE(obj.has()); } /** basic_get tests */