Using new command error system
This commit is contained in:
parent
664b73910c
commit
d42ec40a58
|
@ -95,6 +95,9 @@ set(SOURCE_FILES
|
|||
src/qlz/QuickLZ_L3.cpp
|
||||
src/qlz/QuickLZ_L1.cpp
|
||||
|
||||
src/converters/converter.cpp
|
||||
|
||||
src/query/command3.cpp
|
||||
src/query/command2.cpp
|
||||
src/query/Command.cpp
|
||||
src/query/escape.cpp
|
||||
|
@ -228,6 +231,7 @@ set(TEST_LIBRARIES
|
|||
jsoncpp_lib
|
||||
${ed25519_LIBRARIES_STATIC}
|
||||
${DataPipes_LIBRARIES_SHARED}
|
||||
ffi
|
||||
openssl::ssl::shared
|
||||
openssl::crypto::shared
|
||||
dl
|
||||
|
@ -262,7 +266,7 @@ if(BUILD_TESTS)
|
|||
add_executable(PorpertyTest test/PropertyTest.cpp ${SOURCE_FILES})
|
||||
target_link_libraries(PorpertyTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(BBTest test/BBTest.cpp ${SOURCE_FILES})
|
||||
add_executable(BBTest test/BBTest.cpp ${SOURCE_FILES} src/query/command_unused.h src/converters/converter.cpp src/query/command_handler.h)
|
||||
target_link_libraries(BBTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(LinkedTest test/LinkedTest.cpp ${SOURCE_FILES})
|
||||
|
|
|
@ -34,6 +34,9 @@ const std::vector<ErrorType> ts::avariableErrors = {
|
|||
{0x020F, "client_login_not_permitted" , "client is not permitted to log in" },
|
||||
{0x0210, "client_not_subscribed" , "client is not subscribed to the channel" },
|
||||
{0x0211, "client_unknown" , "client is not known" },
|
||||
{0x0212, "client_join_rate_limit_reached" , "client has reached his join attempt limit" },
|
||||
{0x0213, "client_is_already_member_of_group" , "client is already a member of the group" },
|
||||
{0x0213, "client_is_not_member_of_group" , "client is not a member of the group" },
|
||||
|
||||
{0x0300, "channel_invalid_id" , "invalid channelID" },
|
||||
{0x0301, "channel_protocol_limit_reached" , "max channels protocol limit reached" },
|
||||
|
@ -52,6 +55,7 @@ const std::vector<ErrorType> ts::avariableErrors = {
|
|||
{0x030E, "channel_is_private_channel" , "channel is private channel" },
|
||||
{0x030F, "channel_invalid_security_hash" , "invalid security hash supplied by client" },
|
||||
{0x0310, "channel_is_deleted" , "target channel is deleted" },
|
||||
{0x0311, "channel_name_invalid" , "channel name is invalid" },
|
||||
|
||||
{0x0400, "server_invalid_id" , "invalid serverID" },
|
||||
{0x0401, "server_running" , "server is running" },
|
||||
|
@ -70,6 +74,9 @@ const std::vector<ErrorType> ts::avariableErrors = {
|
|||
{0x040D, "server_already_joined" , "query client already joined to the server" },
|
||||
{0x040E, "server_is_not_shutting_down" , "server isn't shutting down" },
|
||||
{0x040F, "server_max_vs_reached" , "You reached the maximal virtual server limit" },
|
||||
{0x0410, "server_unbound" , "you are not bound to any server" },
|
||||
{0x0411, "server_join_rate_limit_reached" , "the server reached his join attempt limit" },
|
||||
|
||||
|
||||
{0x0500, "sql" , "sql error" },
|
||||
{0x0501, "database_empty_result" , "sql empty result set" },
|
||||
|
@ -139,7 +146,8 @@ const std::vector<ErrorType> ts::avariableErrors = {
|
|||
{0x1001, "web_handshake_invalid" , "Invalid handshake" },
|
||||
{0x1001, "web_handshake_unsupported" , "Handshake intention unsupported" },
|
||||
{0x1002, "web_handshake_identity_unsupported" , "Handshake identity unsupported" },
|
||||
{0x1002, "web_handshake_identity_proof_failed" , "Identity proof failed" },
|
||||
{0x1003, "web_handshake_identity_proof_failed" , "Identity proof failed" },
|
||||
{0x1004, "web_handshake_identity_outdated" , "data seems to be outdated" },
|
||||
|
||||
{0x1100, "music_invalid_id" , "invalid botID" },
|
||||
{0x1101, "music_limit_reached" , "Server music bot limit is reached" },
|
||||
|
@ -165,6 +173,7 @@ const std::vector<ErrorType> ts::avariableErrors = {
|
|||
|
||||
{0x1300, "group_invalid_id" , "Invalid group id" },
|
||||
{0x1301, "group_name_inuse" , "Group name is already in use" },
|
||||
{0x1302, "group_not_assigned_over_this_server" , "the group hasn't been assigned over this server" },
|
||||
|
||||
{0xE000, "resource_limit_reached" , "resource limit reached" },
|
||||
|
||||
|
|
35
src/Error.h
35
src/Error.h
|
@ -30,6 +30,7 @@ namespace ts {
|
|||
client_invalid_id = 0x200,
|
||||
client_nickname_inuse = 0x201,
|
||||
invalid_error_code = 0x202,
|
||||
|
||||
client_protocol_limit_reached = 0x203,
|
||||
client_invalid_type = 0x204,
|
||||
client_already_subscribed = 0x205,
|
||||
|
@ -44,6 +45,11 @@ namespace ts {
|
|||
client_cannot_verify_now = 0x20e,
|
||||
client_login_not_permitted = 0x20f,
|
||||
client_not_subscribed = 0x210,
|
||||
client_unknown = 0x0211,
|
||||
client_join_rate_limit_reached = 0x0212,
|
||||
client_is_already_member_of_group = 0x0213,
|
||||
client_is_not_member_of_group = 0x0214,
|
||||
|
||||
channel_invalid_id = 0x300,
|
||||
channel_protocol_limit_reached = 0x301,
|
||||
channel_already_in = 0x302,
|
||||
|
@ -61,6 +67,8 @@ namespace ts {
|
|||
channel_is_private_channel = 0x30e,
|
||||
channel_invalid_security_hash = 0x30f,
|
||||
channel_is_deleted = 0x310,
|
||||
channel_name_invalid = 0x311,
|
||||
|
||||
server_invalid_id = 0x400,
|
||||
server_running = 0x401,
|
||||
server_is_shutting_down = 0x402,
|
||||
|
@ -77,6 +85,10 @@ namespace ts {
|
|||
server_version_outdated = 0x40d,
|
||||
server_already_joined = 0x40d,
|
||||
server_is_not_shutting_down = 0x40e,
|
||||
server_max_vs_reached = 0x40f,
|
||||
server_unbound = 0x410,
|
||||
server_join_rate_limit_reached = 0x411,
|
||||
|
||||
sql = 0x500,
|
||||
database_empty_result = 0x501,
|
||||
database_duplicate_entry = 0x502,
|
||||
|
@ -136,7 +148,9 @@ namespace ts {
|
|||
web_handshake_invalid = 0x1001,
|
||||
web_handshake_unsupported = 0x1001,
|
||||
web_handshake_identity_unsupported = 0x1002,
|
||||
web_handshake_identity_proof_failed = 0x1002,
|
||||
web_handshake_identity_proof_failed = 0x1003,
|
||||
web_handshake_identity_outdated = 0x1004,
|
||||
|
||||
music_invalid_id = 0x1100,
|
||||
music_limit_reached = 0x1101,
|
||||
music_client_limit_reached = 0x1102,
|
||||
|
@ -150,6 +164,15 @@ namespace ts {
|
|||
playlist_is_in_use = 0x2103,
|
||||
query_not_exists = 0x1200,
|
||||
query_already_exists = 0x1201,
|
||||
|
||||
group_invalid_id = 0x1300,
|
||||
group_name_inuse = 0x1301,
|
||||
group_not_assigned_over_this_server = 0x1302,
|
||||
|
||||
conversation_invalid_id = 0x2200,
|
||||
conversation_more_data = 0x2201,
|
||||
conversation_is_private = 0x2202,
|
||||
|
||||
custom_error = 0xffff
|
||||
};
|
||||
};
|
||||
|
@ -186,10 +209,18 @@ namespace ts {
|
|||
static_assert(sizeof(permission::PermissionType) * 8 + sizeof(error::type) * 8 <= 62);
|
||||
|
||||
[[nodiscard]] inline error::type error_code() const {
|
||||
if(this->is_detailed()) return this->details()->error_id;
|
||||
|
||||
return (error::type) ((this->data >> OFFSET_ERROR) & MASK_ERROR);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool is_permission_error() const {
|
||||
return this->error_code() == error::server_insufficeient_permissions;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline permission::PermissionType permission_id() const {
|
||||
if(this->is_detailed()) return (permission::PermissionType) -1; /* not supported */
|
||||
|
||||
return (permission::PermissionType) ((this->data >> OFFSET_PERMISSION) & MASK_PERMISSION);
|
||||
}
|
||||
|
||||
|
@ -201,6 +232,8 @@ namespace ts {
|
|||
}
|
||||
|
||||
inline std::unique_ptr<detailed_command_result> release_details() {
|
||||
if(!this->is_detailed()) return nullptr;
|
||||
|
||||
auto result = this->details();
|
||||
this->data = 0;
|
||||
return std::unique_ptr<detailed_command_result>{result};
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
#include "converter.h"
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
using namespace ts;
|
||||
|
||||
#define CONVERTER_ST(type, m_decode, m_encode) \
|
||||
CONVERTER_METHOD_DECODE(type, impl::converter_ ##type ##_decode) { \
|
||||
m_decode; \
|
||||
} \
|
||||
\
|
||||
CONVERTER_METHOD_ENCODE(type, impl::converter_ ##type ##_encode) { \
|
||||
m_encode \
|
||||
}
|
||||
|
||||
#define CONVERTER_PRIMITIVE_ST(type, m_decode) CONVERTER_ST(type, \
|
||||
return m_decode;, \
|
||||
return std::to_string(std::any_cast<type>(value)); \
|
||||
)
|
||||
|
||||
CONVERTER_PRIMITIVE_ST(int8_t, std::stol(std::string{str}) & 0xFF);
|
||||
CONVERTER_PRIMITIVE_ST(uint8_t, std::stoul(std::string{str}) & 0xFF);
|
||||
|
||||
CONVERTER_PRIMITIVE_ST(int16_t, std::stol(std::string{str}) & 0xFFFF);
|
||||
CONVERTER_PRIMITIVE_ST(uint16_t, std::stoul(std::string{str}) & 0xFFFF);
|
||||
|
||||
CONVERTER_PRIMITIVE_ST(int32_t, std::stol(std::string{str}) & 0xFFFFFFFF);
|
||||
CONVERTER_PRIMITIVE_ST(uint32_t, std::stoul(std::string{str}) & 0xFFFFFFFF);
|
||||
|
||||
CONVERTER_PRIMITIVE_ST(int64_t, std::stoll(std::string{str}));
|
||||
CONVERTER_PRIMITIVE_ST(uint64_t, std::stoull(std::string{str}))
|
||||
|
||||
CONVERTER_PRIMITIVE_ST(bool, str == "1" || str == "true");
|
||||
CONVERTER_PRIMITIVE_ST(float, std::stof(std::string{str}));
|
||||
CONVERTER_PRIMITIVE_ST(double, std::stod(std::string{str}));
|
||||
CONVERTER_PRIMITIVE_ST(long_double, std::stold(std::string{str}));
|
||||
|
||||
CONVERTER_ST(std__string, return std::string{str};, return std::any_cast<std__string>(value););
|
||||
CONVERTER_ST(const_char__ , return str.data();, return std::string(std::any_cast<const_char__>(value)););
|
|
@ -1,6 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <any>
|
||||
#include <string>
|
||||
#include <cstddef>
|
||||
|
||||
namespace ts {
|
||||
typedef long double long_double;
|
||||
|
@ -20,10 +22,10 @@ namespace ts {
|
|||
static constexpr bool supported = true; \
|
||||
\
|
||||
static constexpr std::string(*to_string)(const std::any&) = encode; \
|
||||
static constexpr type(*from_string)(const std::string&) = decode; \
|
||||
static constexpr type(*from_string)(const std::string_view&) = decode; \
|
||||
};
|
||||
|
||||
#define CONVERTER_METHOD_DECODE(type, name) type name(const std::string& str)
|
||||
#define CONVERTER_METHOD_DECODE(type, name) type name(const std::string_view& str)
|
||||
#define CONVERTER_METHOD_ENCODE(type, name) std::string name(const std::any& value)
|
||||
|
||||
/* helper for primitive types */
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
#include "Command.h"
|
||||
#include "command_exception.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <pipes/buffer.h>
|
||||
#include "log/LogUtils.h"
|
||||
#include "escape.h"
|
||||
#include "command2.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#include "command2.h"
|
||||
#include "escape.h"
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
@ -6,178 +5,7 @@
|
|||
using namespace std;
|
||||
using namespace ts;
|
||||
|
||||
#define CONVERTER_ST(type, m_decode, m_encode) \
|
||||
CONVERTER_METHOD_DECODE(type, impl::converter_ ##type ##_decode) { \
|
||||
m_decode; \
|
||||
} \
|
||||
\
|
||||
CONVERTER_METHOD_ENCODE(type, impl::converter_ ##type ##_encode) { \
|
||||
m_encode \
|
||||
}
|
||||
|
||||
#define CONVERTER_PRIMITIVE_ST(type, m_decode) CONVERTER_ST(type, \
|
||||
return m_decode;, \
|
||||
return std::to_string(std::any_cast<type>(value)); \
|
||||
)
|
||||
|
||||
CONVERTER_PRIMITIVE_ST(int8_t, std::stol(str) & 0xFF);
|
||||
CONVERTER_PRIMITIVE_ST(uint8_t, std::stoul(str) & 0xFF);
|
||||
|
||||
CONVERTER_PRIMITIVE_ST(int16_t, std::stol(str) & 0xFFFF);
|
||||
CONVERTER_PRIMITIVE_ST(uint16_t, std::stoul(str) & 0xFFFF);
|
||||
|
||||
CONVERTER_PRIMITIVE_ST(int32_t, std::stol(str) & 0xFFFFFFFF);
|
||||
CONVERTER_PRIMITIVE_ST(uint32_t, std::stoul(str) & 0xFFFFFFFF);
|
||||
|
||||
CONVERTER_PRIMITIVE_ST(int64_t, std::stoll(str));
|
||||
CONVERTER_PRIMITIVE_ST(uint64_t, std::stoull(str))
|
||||
|
||||
CONVERTER_PRIMITIVE_ST(bool, str == "1" || str == "true");
|
||||
CONVERTER_PRIMITIVE_ST(float, std::stof(str));
|
||||
CONVERTER_PRIMITIVE_ST(double, std::stod(str));
|
||||
CONVERTER_PRIMITIVE_ST(long_double, std::stold(str));
|
||||
|
||||
CONVERTER_ST(std__string, return str;, return std::any_cast<std__string>(value););
|
||||
CONVERTER_ST(const_char__ , return str.c_str();, return std::string(std::any_cast<const_char__>(value)););
|
||||
|
||||
command::command(const std::string& command, bool editable) {
|
||||
this->handle = make_shared<impl::command_data>();
|
||||
this->handle->editable = editable;
|
||||
this->handle->command = command;
|
||||
}
|
||||
|
||||
const std::string& command::identifier() const {
|
||||
return this->handle->command;
|
||||
}
|
||||
|
||||
void command::set_identifier(const std::string &command) {
|
||||
this->handle->command = command;
|
||||
}
|
||||
|
||||
command_bulk command::bulk(size_t index) {
|
||||
if(this->handle->bulks.size() <= index) {
|
||||
if(!this->handle->editable)
|
||||
throw command_bulk_exceed_index_exception();
|
||||
|
||||
while(this->handle->bulks.size() <= index) {
|
||||
auto bulk = make_shared<impl::command_bulk>();
|
||||
bulk->handle = this->handle.get();
|
||||
this->handle->bulks.push_back(std::move(bulk));
|
||||
}
|
||||
}
|
||||
|
||||
return {index, this->handle->bulks[index]};
|
||||
}
|
||||
|
||||
const command_bulk command::bulk(size_t index) const {
|
||||
if(this->handle->bulks.size() <= index)
|
||||
throw command_bulk_exceed_index_exception();
|
||||
|
||||
return {index, this->handle->bulks[index]};
|
||||
}
|
||||
|
||||
size_t command::bulk_count() const {
|
||||
return this->handle->bulks.size();
|
||||
}
|
||||
|
||||
|
||||
command_entry command::value(const std::string &key) {
|
||||
return this->bulk(0)[key];
|
||||
}
|
||||
|
||||
const command_entry command::value(const std::string &key) const {
|
||||
return this->bulk(0)[key];
|
||||
}
|
||||
|
||||
bool command::has_value(const std::string &key) const {
|
||||
if(this->bulk_count() == 0) return false;
|
||||
|
||||
return this->bulk(0).has(key);
|
||||
}
|
||||
|
||||
bool command::has_trigger(const std::string &key) const {
|
||||
for(const auto& trigger : this->handle->triggers)
|
||||
if(trigger == key)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void command::set_trigger(const std::string &key, bool value) {
|
||||
auto& triggers = this->handle->triggers;
|
||||
auto it = find(triggers.begin(), triggers.end(), key);
|
||||
if(it == triggers.end() && value) {
|
||||
triggers.push_back(key);
|
||||
} else if(it != triggers.end() && !value) {
|
||||
triggers.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
command command::parse(const std::string_view &data, bool expect_type, bool drop_non_utf8) {
|
||||
command result;
|
||||
|
||||
size_t current_index = std::string::npos, end_index;
|
||||
if(expect_type) {
|
||||
current_index = data.find(' ', 0);
|
||||
if(current_index == std::string::npos){
|
||||
result.set_identifier(std::string(data));
|
||||
return result;
|
||||
} else {
|
||||
result.set_identifier(std::string(data.substr(0, current_index)));
|
||||
}
|
||||
}
|
||||
|
||||
size_t bulk_index = 0;
|
||||
while(++current_index > 0 || (current_index == 0 && !expect_type)) {
|
||||
expect_type = true;
|
||||
|
||||
end_index = data.find_first_of(" |", current_index);
|
||||
|
||||
if(end_index != current_index) { /* else we've found another space or a pipe */
|
||||
if(data[current_index] == '-') {
|
||||
string trigger(data.substr(current_index + 1, end_index - current_index - 1));
|
||||
result.set_trigger(trigger);
|
||||
} else {
|
||||
auto index_assign = data.find_first_of('=', current_index);
|
||||
string key, value;
|
||||
if(index_assign == string::npos || index_assign > end_index) {
|
||||
key = data.substr(current_index, end_index - current_index);
|
||||
} else {
|
||||
key = data.substr(current_index, index_assign - current_index);
|
||||
try {
|
||||
value = query::unescape(string(data.substr(index_assign + 1, end_index - index_assign - 1)), true);
|
||||
} catch(const std::invalid_argument& ex) {
|
||||
(void) ex;
|
||||
|
||||
/* invalid character at index X */
|
||||
if(!drop_non_utf8)
|
||||
throw;
|
||||
|
||||
goto skip_assign;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const static auto key_validator = [](char c){ return !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '-'); };
|
||||
auto invalid_index = find_if(key.begin(), key.end(), key_validator);
|
||||
if(invalid_index != key.end())
|
||||
throw command_malformed_exception(current_index + distance(key.begin(), invalid_index));
|
||||
|
||||
if(!key.empty() && !result[bulk_index].has(key))
|
||||
result[bulk_index][key] = value;
|
||||
}
|
||||
|
||||
skip_assign:;
|
||||
}
|
||||
}
|
||||
|
||||
if(end_index < data.length() && data[end_index] == '|')
|
||||
bulk_index++;
|
||||
current_index = end_index;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
std::string command::build(ts::command::format::value type) {
|
||||
if(type == format::QUERY || type == format::BRACE_ESCAPED_QUERY) {
|
||||
std::stringstream ss;
|
||||
|
@ -223,34 +51,4 @@ std::string command::build(ts::command::format::value type) {
|
|||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool command_bulk::has(const std::string &key) const {
|
||||
auto& values = this->handle->values;
|
||||
auto index = values.find(key);
|
||||
return index != values.end();
|
||||
}
|
||||
|
||||
command_entry command_bulk::value(const std::string &key) {
|
||||
auto& values = this->handle->values;
|
||||
auto index = values.find(key);
|
||||
if(index == values.end()) {
|
||||
if(!this->handle->handle->editable)
|
||||
throw command_value_missing_exception(this->bulk_index, key);
|
||||
|
||||
auto result = make_shared<impl::command_value>();
|
||||
values[key] = result;
|
||||
return command_entry(result);
|
||||
}
|
||||
return command_entry(index->second);
|
||||
}
|
||||
|
||||
const command_entry command_bulk::value(const std::string &key) const {
|
||||
auto& values = this->handle->values;
|
||||
auto index = values.find(key);
|
||||
if(index == values.end())
|
||||
throw command_value_missing_exception(this->bulk_index, key);
|
||||
|
||||
return command_entry(index->second);
|
||||
}
|
||||
|
||||
command_entry command_entry::empty{};
|
||||
*/
|
||||
|
|
|
@ -1,641 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <any>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cassert>
|
||||
#include <string_view>
|
||||
#include <deque>
|
||||
#include <tuple>
|
||||
|
||||
#include "Error.h"
|
||||
|
||||
#include "command_exception.h"
|
||||
#include "converters/converter.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#define __attribute__used
|
||||
#else
|
||||
#define __attribute__used __attribute__((used))
|
||||
#endif
|
||||
|
||||
namespace ts {
|
||||
/* data impl stuff */
|
||||
namespace impl {
|
||||
struct command_data;
|
||||
|
||||
struct command_value {
|
||||
bool casted = false; /* true if value isn't a std::string */
|
||||
std::any value;
|
||||
std::string(*to_string)(const std::any&);
|
||||
};
|
||||
|
||||
struct command_bulk {
|
||||
command_data* handle;
|
||||
std::map<std::string, std::shared_ptr<command_value>> values;
|
||||
};
|
||||
|
||||
struct command_data {
|
||||
std::string command;
|
||||
bool editable;
|
||||
std::deque<std::shared_ptr<command_bulk>> bulks;
|
||||
std::deque<std::string> triggers;
|
||||
};
|
||||
}
|
||||
|
||||
/* Container stuff */
|
||||
class command_bulk;
|
||||
class command_entry;
|
||||
class command {
|
||||
public:
|
||||
struct format {
|
||||
enum value {
|
||||
QUERY,
|
||||
BRACE_ESCAPED_QUERY,
|
||||
JSON
|
||||
};
|
||||
};
|
||||
static command parse(const std::string_view& /* command data */, bool /* expect type */ = true, bool /* drop non UTF-8 characters */ = false);
|
||||
explicit command(const std::string& /* command */ = "", bool /* editable */ = true);
|
||||
|
||||
[[nodiscard]] const std::string& identifier() const;
|
||||
void set_identifier(const std::string& /* command */);
|
||||
|
||||
command_bulk bulk(size_t /* bulk index */);
|
||||
[[nodiscard]] const command_bulk bulk(size_t /* bulk index */) const;
|
||||
[[nodiscard]] size_t bulk_count() const;
|
||||
inline command_bulk operator[](size_t /* index */);
|
||||
inline const command_bulk operator[](size_t /* index */) const;
|
||||
|
||||
command_entry value(const std::string& /* key */);
|
||||
[[nodiscard]] const command_entry value(const std::string& /* key */) const;
|
||||
[[nodiscard]] bool has_value(const std::string& /* key */) const;
|
||||
command_entry operator[](const std::string& /* key */);
|
||||
const command_entry operator[](const std::string& /* key */) const;
|
||||
|
||||
[[nodiscard]] bool has_trigger(const std::string& /* key */) const;
|
||||
void set_trigger(const std::string& /* key */, bool /* value */ = true);
|
||||
|
||||
std::string build(format::value /* format */ = format::QUERY);
|
||||
/* TODO add a json object build method */
|
||||
private:
|
||||
std::shared_ptr<impl::command_data> handle;
|
||||
};
|
||||
|
||||
class command_bulk {
|
||||
friend class command;
|
||||
public:
|
||||
[[nodiscard]] bool has(const std::string& /* key */) const;
|
||||
command_entry value(const std::string& /* key */);
|
||||
[[nodiscard]] command_entry const value(const std::string& /* key */) const;
|
||||
|
||||
|
||||
inline command_entry operator[](const std::string& /* key */);
|
||||
inline const command_entry operator[](const std::string& /* key */) const;
|
||||
private:
|
||||
command_bulk(size_t index, std::shared_ptr<impl::command_bulk> handle) : bulk_index(index), handle(std::move(handle)) {}
|
||||
|
||||
size_t bulk_index;
|
||||
std::shared_ptr<impl::command_bulk> handle;
|
||||
};
|
||||
|
||||
class command_entry {
|
||||
public:
|
||||
static command_entry empty;
|
||||
|
||||
command_entry() : handle(std::make_shared<impl::command_value>()) {}
|
||||
command_entry(const command_entry& ref) : handle(ref.handle) {}
|
||||
command_entry(command_entry&& ref) : handle(std::move(ref.handle)) {}
|
||||
|
||||
command_entry&operator=(const command_entry& other) {
|
||||
this->handle = other.handle;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool is_empty() const { return !this->handle->value.has_value(); }
|
||||
|
||||
command_entry& reset() {
|
||||
this->handle->value.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string string() const {
|
||||
if(this->is_empty()) return "";
|
||||
|
||||
if(!this->handle->casted || this->handle->value.type() == typeid(std::string)) //No cast needed
|
||||
return std::any_cast<std::string>(this->handle->value);
|
||||
|
||||
if(!this->handle->to_string) throw command_cannot_uncast_exception();
|
||||
return this->handle->to_string(this->handle->value);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const std::string value() const { return (std::string) this->string(); }
|
||||
|
||||
[[nodiscard]] inline operator std::string() const {
|
||||
return this->string();
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<!std::is_same<T, std::string>::value, int> = 0>
|
||||
T as() {
|
||||
static_assert(converter<T>::supported, "Target type isn't supported!");
|
||||
static_assert(!converter<T>::supported || converter<T>::from_string, "Target type dosn't support parsing");
|
||||
|
||||
if(this->is_empty()) return T();
|
||||
|
||||
if(this->handle->casted) {
|
||||
if(this->handle->value.type() == typeid(T))
|
||||
return std::any_cast<T>(this->handle->value);
|
||||
else
|
||||
throw command_casted_exception();
|
||||
} else {
|
||||
const auto& ref = std::any_cast<const std::string&>(this->handle->value);
|
||||
this->handle->value = converter<T>::from_string(ref);
|
||||
this->handle->to_string = converter<T>::to_string;
|
||||
this->handle->casted = true;
|
||||
}
|
||||
|
||||
return std::any_cast<T>(this->handle->value);
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_same<T, std::string>::value, int> = 0>
|
||||
T as() {
|
||||
return this->string();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline operator T() {
|
||||
return this->as<T>();
|
||||
}
|
||||
|
||||
command_entry& melt() {
|
||||
if(this->handle->casted) {
|
||||
this->handle->value = this->handle->to_string(this->handle->value);
|
||||
this->handle->casted = false;
|
||||
this->handle->to_string = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename std::enable_if<!std::is_same<T, std::string>::value && !std::is_same<T, const char*>::value && !std::is_same<T, const char (&)[]>::value, int>::type = 0>
|
||||
void set(const T& value) {
|
||||
static_assert(converter<T>::supported, "Target type isn't supported!");
|
||||
static_assert(!converter<T>::supported || converter<T>::to_string, "Target type dosn't support encode");
|
||||
|
||||
this->handle->casted = true;
|
||||
this->handle->value = std::move(value);
|
||||
this->handle->to_string = converter<T>::to_string;
|
||||
}
|
||||
|
||||
template <typename T, typename std::enable_if<std::is_same<T, std::string>::value, int>::type = 0>
|
||||
void set(const T& value) {
|
||||
this->handle->value = value;
|
||||
this->handle->casted = false;
|
||||
this->handle->to_string = nullptr;
|
||||
}
|
||||
|
||||
template <int N>
|
||||
void set(const char (&string)[N]) {
|
||||
this->set(std::string(string, N - 1));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
command_entry&operator=(const T& value) {
|
||||
this->set(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit command_entry(std::shared_ptr<impl::command_value> handle) : handle(std::move(handle)) {}
|
||||
|
||||
private:
|
||||
std::shared_ptr<impl::command_value> handle;
|
||||
};
|
||||
|
||||
namespace descriptor {
|
||||
namespace tliterals {
|
||||
template <char... chars>
|
||||
using tstring = std::integer_sequence<char, chars...>;
|
||||
|
||||
#ifndef WIN32
|
||||
template <typename T, T... chars>
|
||||
constexpr tstring<chars...> operator""_tstr() { return { }; }
|
||||
#endif
|
||||
template <typename>
|
||||
struct tliteral;
|
||||
|
||||
template <char... elements>
|
||||
struct tliteral<tstring<elements...>> {
|
||||
static constexpr char string[sizeof...(elements) + 1] = { elements..., '\0' };
|
||||
};
|
||||
}
|
||||
|
||||
namespace impl {
|
||||
namespace templates {
|
||||
template <bool...>
|
||||
struct _or_ {
|
||||
constexpr static bool value = false;
|
||||
};
|
||||
|
||||
template <bool T, bool... Args>
|
||||
struct _or_<T, Args...> {
|
||||
constexpr static bool value = T || _or_<Args...>::value;
|
||||
};
|
||||
|
||||
template <typename... >
|
||||
struct index;
|
||||
|
||||
template <typename... >
|
||||
struct tuple_index;
|
||||
|
||||
template <typename T, typename... R>
|
||||
struct index<T, T, R...> : std::integral_constant<size_t, 0>
|
||||
{ };
|
||||
|
||||
template <typename T, typename F, typename... R>
|
||||
struct index<T, F, R...> : std::integral_constant<size_t, 1 + index<T, R...>::value>
|
||||
{ };
|
||||
|
||||
template <typename T, typename... R>
|
||||
struct tuple_index<T, std::tuple<R...>> : std::integral_constant<size_t, index<T, R...>::value>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct remove_cr {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct remove_cr<const T&> {
|
||||
typedef T type;
|
||||
};
|
||||
}
|
||||
|
||||
struct base;
|
||||
|
||||
template <class key_t, typename value_type_t, class options, class... extends>
|
||||
struct field;
|
||||
|
||||
struct field_data;
|
||||
struct field_base;
|
||||
struct optional_extend;
|
||||
struct bulk_extend;
|
||||
|
||||
template <typename...>
|
||||
struct command_parser {
|
||||
constexpr static bool supported = false;
|
||||
};
|
||||
|
||||
inline void parse_field(const std::shared_ptr<field_data>& description, field_base* field, command& cmd);
|
||||
|
||||
struct option_data {
|
||||
bool bulked;
|
||||
bool optional;
|
||||
};
|
||||
|
||||
template <bool bulked_t, bool optional_t>
|
||||
struct options {
|
||||
using object_data_t = option_data;
|
||||
static constexpr auto is_bulked = bulked_t;
|
||||
static constexpr auto is_optional = optional_t;
|
||||
|
||||
protected:
|
||||
inline static object_data_t options_object() {
|
||||
return {
|
||||
is_bulked,
|
||||
is_optional
|
||||
};
|
||||
}
|
||||
};
|
||||
using default_options = options<false, false>;
|
||||
|
||||
struct base {
|
||||
virtual ~base() = default;
|
||||
};
|
||||
|
||||
struct base_data {
|
||||
int type; /* 1 = field | 2 = switch | 3 = command handle */
|
||||
option_data options;
|
||||
};
|
||||
|
||||
struct field_base : public base {
|
||||
virtual std::vector<command_entry>& ref_values() = 0;
|
||||
virtual const std::vector<command_entry>& ref_values() const = 0;
|
||||
};
|
||||
|
||||
struct field_data : public base_data {
|
||||
const char* key;
|
||||
const std::type_info& field_type;
|
||||
|
||||
void* from_string;
|
||||
void* to_string;
|
||||
};
|
||||
|
||||
template <class key_t, typename value_type_t, class options, class... extends>
|
||||
struct field : public field_base, public options, public extends... {
|
||||
friend struct command_parser<field<key_t, value_type_t, options, extends...>>;
|
||||
static_assert(converter<value_type_t>::supported, "Target type isn't supported!");
|
||||
static_assert(!converter<value_type_t>::supported || converter<value_type_t>::from_string, "Target type dosn't support parsing");
|
||||
static_assert(impl::templates::_or_<!std::is_empty<extends>::value...>::value == false, "Extensions could not have data members");
|
||||
|
||||
protected:
|
||||
using object_t = field_data;
|
||||
using value_type = value_type_t;
|
||||
static constexpr auto key = key_t::string;
|
||||
static constexpr auto from_string = converter<value_type_t>::from_string;
|
||||
|
||||
public:
|
||||
template <bool flag = true /*, std::enable_if_t<!templates::_or_<std::is_same<extends, optional_extend>::value...>::value, int> = 0 */>
|
||||
using as_optional = field<key_t, value_type_t, impl::options<options::is_bulked, flag>, optional_extend, extends...>;
|
||||
|
||||
template <bool flag = true /*, std::enable_if_t<!templates::_or_<std::is_same<extends, bulk_extend>::value...>::value, int> = 0 */>
|
||||
using as_bulked = field<key_t, value_type_t, impl::options<flag, options::is_optional>, bulk_extend, extends...>;
|
||||
|
||||
using optional = as_optional<true>;
|
||||
using bulked = as_bulked<true>;
|
||||
|
||||
inline static std::shared_ptr<object_t> describe() {
|
||||
return std::make_shared<object_t>(
|
||||
object_t {
|
||||
1,
|
||||
options::options_object(),
|
||||
key,
|
||||
typeid(value_type_t),
|
||||
(void*) converter<value_type_t>::from_string,
|
||||
(void*) converter<value_type_t>::to_string
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
inline value_type_t value() const {
|
||||
command_entry& value = this->get_command_entry();
|
||||
return value.as<value_type_t>();
|
||||
}
|
||||
|
||||
inline command_entry& get_command_entry() const {
|
||||
if(this->values.empty())
|
||||
throw command_value_missing_exception{0, key};
|
||||
|
||||
const auto& front = this->values.front();
|
||||
return *(command_entry*) &front;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T as() const {
|
||||
command_entry& value = this->get_command_entry();
|
||||
return value.as<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline operator T() const {
|
||||
return this->as<T>();
|
||||
}
|
||||
|
||||
std::vector<command_entry>& ref_values() final { return this->values; }
|
||||
const std::vector<command_entry>& ref_values() const final { return this->values; }
|
||||
protected:
|
||||
std::vector<command_entry> values;
|
||||
};
|
||||
|
||||
struct optional_extend {
|
||||
public:
|
||||
inline bool has_value() const {
|
||||
auto base = dynamic_cast<field_base*>((struct base*) this);
|
||||
assert(base);
|
||||
|
||||
const auto& values = base->ref_values();
|
||||
return !values.empty() && !values[0].is_empty();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T get_or(T&& value = T{}) const {
|
||||
auto base = dynamic_cast<field_base*>((struct base*) this);
|
||||
assert(base);
|
||||
|
||||
auto& values = base->ref_values();
|
||||
if(values.empty() || values[0].is_empty())
|
||||
return value;
|
||||
|
||||
return values.front().as<T>();
|
||||
}
|
||||
};
|
||||
|
||||
struct bulk_extend {
|
||||
public:
|
||||
inline bool has_index(size_t index) const {
|
||||
return !this->at(index).is_empty();
|
||||
}
|
||||
|
||||
inline size_t length() const {
|
||||
auto base = dynamic_cast<field_base*>((struct base*) this);
|
||||
assert(base);
|
||||
|
||||
return base->ref_values().size();
|
||||
}
|
||||
|
||||
inline command_entry at(size_t index) const {
|
||||
auto base = dynamic_cast<field_base*>((struct base*) this);
|
||||
assert(base);
|
||||
|
||||
auto& values = base->ref_values();
|
||||
if(index > values.size())
|
||||
throw command_bulk_exceed_index_exception();
|
||||
|
||||
return values[index];
|
||||
}
|
||||
|
||||
inline command_entry operator[](size_t index) const {
|
||||
return this->at(index);
|
||||
}
|
||||
};
|
||||
|
||||
struct trigger_base : public base {
|
||||
virtual bool& ref_flag() = 0;
|
||||
};
|
||||
|
||||
struct trigger_data : public base_data {
|
||||
const char* key;
|
||||
};
|
||||
|
||||
template <class key_t, class options>
|
||||
struct trigger : public trigger_base, public options {
|
||||
protected:
|
||||
static constexpr auto key = key_t::string;
|
||||
public:
|
||||
using object_t = trigger_data;
|
||||
|
||||
inline static std::shared_ptr<object_t> describe() {
|
||||
return std::make_shared<object_t>(
|
||||
object_t {
|
||||
2,
|
||||
options::options_object(),
|
||||
key
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
inline bool is_set() const { return this->flag_set; }
|
||||
operator bool() const { return this->flag_set; }
|
||||
|
||||
bool& ref_flag() override {
|
||||
return this->flag_set;
|
||||
}
|
||||
|
||||
private:
|
||||
bool flag_set = false;
|
||||
};
|
||||
|
||||
template <class key_t, class options, class... extends>
|
||||
struct command_parser<field<key_t, options, extends...>> {
|
||||
constexpr static bool supported = true;
|
||||
|
||||
typedef field<key_t, options, extends...> field_t;
|
||||
using descriptor_t = std::shared_ptr<typename field_t::object_t>;
|
||||
|
||||
inline static descriptor_t describe() {
|
||||
return field_t::describe();
|
||||
}
|
||||
|
||||
inline static field_t apply(descriptor_t& descriptor, command& cmd) {
|
||||
assert(descriptor->type == 1);
|
||||
|
||||
field_t result{};
|
||||
|
||||
//if(!description->options.optional && !cmd.has_value(description->key))
|
||||
// throw command_value_missing_exception();
|
||||
auto& values = result.ref_values();
|
||||
values.clear();
|
||||
|
||||
if(descriptor->options.bulked) {
|
||||
values.resize(cmd.bulk_count());
|
||||
for(size_t bulk_index = 0; bulk_index < cmd.bulk_count(); bulk_index++) {
|
||||
if(!cmd[bulk_index].has(descriptor->key)) {
|
||||
if(!descriptor->options.optional)
|
||||
throw command_value_missing_exception(bulk_index, descriptor->key);
|
||||
else
|
||||
values[bulk_index] = command_entry::empty;
|
||||
} else {
|
||||
values[bulk_index] = cmd[bulk_index][descriptor->key];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(!cmd.has_value(descriptor->key)) {
|
||||
if(!descriptor->options.optional)
|
||||
throw command_value_missing_exception(0, descriptor->key);
|
||||
else
|
||||
values.push_back(command_entry::empty);
|
||||
} else
|
||||
values.push_back(cmd[descriptor->key]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename key_t, class options>
|
||||
struct command_parser<trigger<key_t, options>> {
|
||||
constexpr static bool supported = true;
|
||||
|
||||
typedef trigger<key_t, options> trigger_t;
|
||||
using descriptor_t = std::shared_ptr<typename trigger_t::object_t>;
|
||||
|
||||
inline static descriptor_t describe() {
|
||||
return trigger_t::describe();
|
||||
}
|
||||
|
||||
inline static trigger_t apply(descriptor_t& descriptor, command& cmd) {
|
||||
assert(descriptor->type == 2);
|
||||
|
||||
trigger_t result{};
|
||||
result.ref_flag() = cmd.has_trigger(descriptor->key);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct command_data : public base_data { };
|
||||
|
||||
template <>
|
||||
struct command_parser<command&> {
|
||||
constexpr static bool supported = true;
|
||||
|
||||
using descriptor_t = std::shared_ptr<command_data>;
|
||||
|
||||
inline static descriptor_t describe() { return std::make_shared<command_data>(command_data{{3, {false, false}}}); }
|
||||
|
||||
inline static command& apply(descriptor_t& descriptor, command& cmd) {
|
||||
assert(descriptor->type == 3);
|
||||
return cmd;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename C>
|
||||
struct command_parser<C> {
|
||||
constexpr static bool supported = false;
|
||||
|
||||
using descriptor_t = std::shared_ptr<nullptr_t>;
|
||||
|
||||
inline static descriptor_t describe() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline static command& apply(descriptor_t& descriptor, command& cmd) {
|
||||
return cmd;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <class key_t, typename value_type_t>
|
||||
using field = impl::field<key_t, value_type_t, impl::default_options>;
|
||||
|
||||
template <class key_t>
|
||||
using trigger = impl::trigger<key_t, impl::default_options>;
|
||||
|
||||
template <typename... args_t>
|
||||
inline std::array<std::shared_ptr<struct impl::base_data>, sizeof...(args_t)> describe_function(void(*)(args_t...)) {
|
||||
static_assert(!impl::templates::_or_<!impl::command_parser<typename impl::templates::remove_cr<args_t>::type>::supported...>::value, "Not any function argument type is supported");
|
||||
return {impl::command_parser<typename impl::templates::remove_cr<args_t>::type>::describe()...};
|
||||
}
|
||||
|
||||
struct invocable_function {
|
||||
void operator()(command& command) { this->invoke(command); }
|
||||
|
||||
virtual void invoke(command& command) = 0;
|
||||
};
|
||||
|
||||
template <typename... args_t>
|
||||
struct typed_invocable_function : public invocable_function {
|
||||
using args_tuple_t = std::tuple<args_t...>;
|
||||
template <typename arg_t>
|
||||
using command_parser_t = impl::command_parser<typename impl::templates::remove_cr<arg_t>::type>;
|
||||
using descriptors_t = std::tuple<typename command_parser_t<args_t>::descriptor_t...>;
|
||||
|
||||
descriptors_t descriptors;
|
||||
void(*function)(args_t...);
|
||||
|
||||
void invoke(command& command) override {
|
||||
this->function(command_parser_t<args_t>::apply(std::get<impl::templates::tuple_index<args_t, args_tuple_t>::value>(descriptors), command)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... args_t, typename typed_function = typed_invocable_function<args_t...>>
|
||||
std::shared_ptr<invocable_function> parse_function(void(*function)(args_t...)) {
|
||||
auto result = std::make_shared<typed_function>();
|
||||
result->function = function;
|
||||
result->descriptors = {impl::command_parser<typename impl::templates::remove_cr<args_t>::type>::describe()...};
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename... args_t>
|
||||
void invoke_function(void(*function)(args_t...), command& command) {
|
||||
auto descriptor = parse_function(function);
|
||||
(*descriptor)(command);
|
||||
}
|
||||
|
||||
/* converts a literal into a template literal */
|
||||
#define _tlit(literal) ::ts::descriptor::tliterals::tliteral<decltype(literal ##_tstr)>
|
||||
#define tl(lit) _tlit(lit)
|
||||
}
|
||||
|
||||
//using desc = descriptor::base<descriptor::impl::default_options>;
|
||||
}
|
||||
|
||||
#include "command_internal.h"
|
|
@ -0,0 +1,38 @@
|
|||
//
|
||||
// Created by wolverindev on 25.01.20.
|
||||
//
|
||||
|
||||
#include "command3.h"
|
||||
|
||||
using namespace ts;
|
||||
|
||||
command_bulk command_parser::empty_bulk{std::string::npos, ""};
|
||||
|
||||
bool command_parser::parse(bool command) {
|
||||
this->data = this->_command;
|
||||
this->index = std::string::npos;
|
||||
|
||||
size_t index{0}, findex;
|
||||
if(command) {
|
||||
index = this->_command.find(' ', index);
|
||||
if(index == std::string::npos) {
|
||||
this->command_type = this->_command;
|
||||
return true;
|
||||
} else {
|
||||
this->command_type = this->data.substr(0, index);
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
this->_bulks.reserve(4);
|
||||
while(index < this->_command.size()) {
|
||||
findex = this->_command.find('|', index);
|
||||
if(findex == std::string::npos)
|
||||
findex = this->_command.size();
|
||||
|
||||
auto& bulk = this->_bulks.emplace_back(this->_bulks.size() - 1, this->data.substr(index, findex - index));
|
||||
index = findex + 1;
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#include "escape.h"
|
||||
#include "converters/converter.h"
|
||||
#include "command_exception.h"
|
||||
|
||||
namespace ts {
|
||||
namespace impl {
|
||||
class command_string_parser {
|
||||
public:
|
||||
[[nodiscard]] inline bool is_empty() const noexcept { return this->data.empty(); }
|
||||
|
||||
[[nodiscard]] inline std::string_view value_raw(const std::string_view& key) const {
|
||||
bool tmp;
|
||||
auto result = this->value_raw(key, tmp);
|
||||
if(!tmp) throw command_value_missing_exception{index, std::string{key}};
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string_view value_raw(const std::string_view& key, bool& has_been_found) const noexcept {
|
||||
has_been_found = false;
|
||||
|
||||
size_t index{0}, findex, max{this->data.size()}, key_size{key.size()};
|
||||
do {
|
||||
findex = this->data.find(key, index);
|
||||
if(findex > max) return std::string_view{};
|
||||
|
||||
/* not starting with a space so not a match */
|
||||
if(findex != 0 && this->data[findex - 1] != ' ') {
|
||||
index = findex + key_size;
|
||||
continue;
|
||||
}
|
||||
|
||||
findex += key_size;
|
||||
if(findex < max) {
|
||||
if(findex < max && this->data[findex] != '=') {
|
||||
index = findex + key_size;
|
||||
continue;
|
||||
}
|
||||
|
||||
has_been_found = true;
|
||||
return this->data.substr(findex + 1, this->data.find(' ', findex + 1) - findex - 1);
|
||||
} else {
|
||||
has_been_found = true;
|
||||
return std::string_view{};
|
||||
}
|
||||
} while(true);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string value(const std::string_view& key) const {
|
||||
const auto value = this->value_raw(key);
|
||||
if(value.empty()) return std::string{};
|
||||
|
||||
return query::unescape(std::string{value}, false);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] inline T value_as(const std::string_view& key) const {
|
||||
static_assert(converter<T>::supported, "Target type isn't supported!");
|
||||
static_assert(!converter<T>::supported || converter<T>::from_string, "Target type dosn't support parsing");
|
||||
|
||||
return converter<T>::from_string(this->value(key));
|
||||
}
|
||||
|
||||
protected:
|
||||
command_string_parser(size_t index, std::string_view data) : index{index}, data{std::move(data)} {}
|
||||
|
||||
size_t index{};
|
||||
std::string_view data{};
|
||||
};
|
||||
}
|
||||
|
||||
struct command_bulk : public impl::command_string_parser {
|
||||
command_bulk(size_t index, std::string_view data) : command_string_parser{index, std::move(data)} {}
|
||||
};
|
||||
|
||||
class command_parser : public impl::command_string_parser {
|
||||
public:
|
||||
enum struct parse_status {
|
||||
succeeded,
|
||||
failed
|
||||
};
|
||||
|
||||
explicit command_parser(std::string command) : _command{std::move(command)}, impl::command_string_parser{std::string::npos, this->_command} { }
|
||||
|
||||
bool parse(bool /* contains identifier */);
|
||||
|
||||
[[nodiscard]] inline const std::string_view& identifier() const noexcept { return this->command_type; }
|
||||
[[nodiscard]] inline size_t bulk_count() const noexcept { return this->_bulks.size(); }
|
||||
[[nodiscard]] inline const command_bulk& bulk(size_t index) const noexcept {
|
||||
if(this->_bulks.size() <= index) return empty_bulk;
|
||||
return this->_bulks[index];
|
||||
}
|
||||
|
||||
const command_bulk& operator[](size_t index) const { return this->bulk(index); }
|
||||
|
||||
[[nodiscard]] inline bool has_switch(const std::string_view& key) const noexcept {
|
||||
size_t index{0};
|
||||
do {
|
||||
index = this->_command_view.find(key, index);
|
||||
index -= 1;
|
||||
if(index > key.size()) return false;
|
||||
if(this->_command_view[index] == '-') return index == 0 || this->_command_view[index - 1] == ' ';
|
||||
index += 2;
|
||||
} while(true);
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<command_bulk>& bulks() const { return this->_bulks; }
|
||||
private:
|
||||
static command_bulk empty_bulk;
|
||||
|
||||
const std::string _command{};
|
||||
const std::string_view _command_view{};
|
||||
|
||||
std::string_view command_type{};
|
||||
|
||||
std::vector<command_bulk> _bulks{};
|
||||
std::vector<std::string_view> flags{};
|
||||
};
|
||||
}
|
|
@ -1,23 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "Definitions.h"
|
||||
#include "command2.h"
|
||||
#include "command_handler.h"
|
||||
|
||||
namespace ts {
|
||||
namespace cconstants {
|
||||
|
||||
typedef descriptor::field<tl("return_code"), std::string> return_code;
|
||||
typedef command_handler::field<tl("return_code"), std::string> return_code;
|
||||
|
||||
typedef descriptor::field<tl("sid"), ServerId> server_id;
|
||||
typedef command_handler::field<tl("sid"), ServerId> server_id;
|
||||
|
||||
typedef descriptor::field<tl("clid"), ClientId> client_id;
|
||||
typedef descriptor::field<tl("cldbid"), ClientDbId> client_database_id;
|
||||
typedef command_handler::field<tl("clid"), ClientId> client_id;
|
||||
typedef command_handler::field<tl("cldbid"), ClientDbId> client_database_id;
|
||||
|
||||
typedef descriptor::field<tl("cid"), ChannelId> channel_id;
|
||||
typedef descriptor::field<tl("cpid"), ChannelId> channel_parent_id;
|
||||
typedef command_handler::field<tl("cid"), ChannelId> channel_id;
|
||||
typedef command_handler::field<tl("cpid"), ChannelId> channel_parent_id;
|
||||
|
||||
typedef descriptor::field<tl("cgid"), GroupId> channel_group_id;
|
||||
typedef descriptor::field<tl("cgid"), GroupId> server_group_id;
|
||||
typedef command_handler::field<tl("cgid"), GroupId> channel_group_id;
|
||||
typedef command_handler::field<tl("cgid"), GroupId> server_group_id;
|
||||
|
||||
//FIXME
|
||||
/* typedef descriptor::field<tl("permid"), permission::PermissionType> permission_id;
|
||||
|
|
|
@ -0,0 +1,391 @@
|
|||
#pragma once
|
||||
|
||||
#include <any>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cassert>
|
||||
#include <string_view>
|
||||
#include <deque>
|
||||
#include <tuple>
|
||||
|
||||
#include "Error.h"
|
||||
|
||||
#include "command_exception.h"
|
||||
#include "converters/converter.h"
|
||||
#include "command3.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#define __attribute__used
|
||||
#else
|
||||
#define __attribute__used __attribute__((used))
|
||||
#endif
|
||||
|
||||
namespace ts {
|
||||
namespace command_handler {
|
||||
namespace tliterals {
|
||||
template <char... chars>
|
||||
using tstring = std::integer_sequence<char, chars...>;
|
||||
|
||||
#ifndef WIN32
|
||||
template <typename T, T... chars>
|
||||
constexpr tstring<chars...> operator""_tstr() { return { }; }
|
||||
#endif
|
||||
template <typename>
|
||||
struct tliteral;
|
||||
|
||||
template <char... elements>
|
||||
struct tliteral<tstring<elements...>> {
|
||||
static constexpr char string[sizeof...(elements) + 1] = { elements..., '\0' };
|
||||
};
|
||||
}
|
||||
|
||||
/* general description of a function */
|
||||
struct parameter_description {
|
||||
int type; /* 1 = field | 2 = switch | 3 = command handle */
|
||||
};
|
||||
|
||||
struct parameter_description_field : public parameter_description {
|
||||
const char* key;
|
||||
bool optional;
|
||||
const std::type_info& field_type;
|
||||
};
|
||||
|
||||
struct parameter_description_switch : public parameter_description {
|
||||
const char* key;
|
||||
};
|
||||
|
||||
struct parameter_description_command : public parameter_description { };
|
||||
|
||||
|
||||
struct invocable_function {
|
||||
void operator()(command_parser& command) { this->invoke(command); }
|
||||
virtual void invoke(command_parser& command) = 0;
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
namespace templates {
|
||||
template <bool...>
|
||||
struct _or_ {
|
||||
constexpr static bool value = false;
|
||||
};
|
||||
|
||||
template <bool T, bool... Args>
|
||||
struct _or_<T, Args...> {
|
||||
constexpr static bool value = T || _or_<Args...>::value;
|
||||
};
|
||||
|
||||
template <typename... >
|
||||
struct index;
|
||||
|
||||
template <typename... >
|
||||
struct tuple_index;
|
||||
|
||||
template <typename T, typename... R>
|
||||
struct index<T, T, R...> : std::integral_constant<size_t, 0>
|
||||
{ };
|
||||
|
||||
template <typename T, typename F, typename... R>
|
||||
struct index<T, F, R...> : std::integral_constant<size_t, 1 + index<T, R...>::value>
|
||||
{ };
|
||||
|
||||
template <typename T, typename... R>
|
||||
struct tuple_index<T, std::tuple<R...>> : std::integral_constant<size_t, index<T, R...>::value>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct remove_cr {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct remove_cr<const T&> {
|
||||
typedef T type;
|
||||
};
|
||||
}
|
||||
|
||||
template <typename...>
|
||||
struct command_invoker {
|
||||
constexpr static bool supported = false;
|
||||
};
|
||||
|
||||
struct function_parameter {
|
||||
virtual ~function_parameter() = default;
|
||||
|
||||
virtual void parse(const command_parser& /* parser */) = 0;
|
||||
};
|
||||
|
||||
template <typename key_t, typename value_t, bool optional, bool bulked>
|
||||
class value_container;
|
||||
|
||||
/* single value implementation */
|
||||
template <typename value_t>
|
||||
class single_value_base {
|
||||
public:
|
||||
[[nodiscard]] inline const value_t& value() const {
|
||||
if(!this->_value.has_value()) throw command_value_missing_exception{0, "unknown"}; /* this should never happen! */
|
||||
assert(this->_value.has_value());
|
||||
|
||||
return this->_value.value();
|
||||
}
|
||||
|
||||
inline operator value_t() const {
|
||||
return this->value();
|
||||
}
|
||||
|
||||
protected:
|
||||
static constexpr bool bulked_value = false;
|
||||
std::optional<value_t> _value{};
|
||||
};
|
||||
|
||||
template <typename key_t, typename value_t>
|
||||
class value_container<key_t, value_t, false, false> : public single_value_base<value_t> {
|
||||
protected:
|
||||
void _parse(const command_parser& parser) {
|
||||
this->_value = std::make_optional(parser.value_as<value_t>(key_t::string)); /* will cause a not found exception if missing */
|
||||
}
|
||||
};
|
||||
|
||||
template <typename key_t, typename value_t>
|
||||
class value_container<key_t, value_t, true, false> : public single_value_base<value_t> {
|
||||
public:
|
||||
[[nodiscard]] inline bool has_value() const { return this->_value.has_value(); }
|
||||
|
||||
[[nodiscard]] inline const value_t& value_or(value_t&& fallback) const {
|
||||
if(this->_value.has_value())
|
||||
return this->value();
|
||||
return fallback;
|
||||
}
|
||||
|
||||
protected:
|
||||
void _parse(const command_parser& parser) {
|
||||
bool found{};
|
||||
(void) parser.value_raw(key_t::string, found);
|
||||
if(found)
|
||||
this->_value = parser.value_as<value_t>(key_t::string);
|
||||
}
|
||||
};
|
||||
|
||||
/* optional bulk implementation */
|
||||
template <typename key_t, typename value_t>
|
||||
class value_container<key_t, value_t, true, true> {
|
||||
public:
|
||||
[[nodiscard]] inline bool has_value(size_t index) const { return this->_values[index].has_value(); }
|
||||
|
||||
[[nodiscard]] inline const value_t& value(size_t index) const {
|
||||
if(!this->_values[index].has_value()) throw command_value_missing_exception{0, "unknown"}; /* this should never happen! */
|
||||
assert(this->_values[index].has_value());
|
||||
|
||||
return this->_values[index].value();
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]] inline const value_t& value_or(size_t index, value_t&& fallback) const {
|
||||
if(this->has_value(index))
|
||||
return this->value(index);
|
||||
return fallback;
|
||||
}
|
||||
protected:
|
||||
static constexpr bool bulked_value = true;
|
||||
|
||||
void _parse(const command_parser& parser) {
|
||||
this->_values.reserve(parser.bulk_count());
|
||||
for(const auto& bulk : parser.bulks()) {
|
||||
auto& value = this->_values.emplace_back();
|
||||
|
||||
bool found{};
|
||||
(void) bulk.value_raw(key_t::string, found);
|
||||
if(found)
|
||||
value = bulk.value_as<value_t>(key_t::string);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::optional<value_t>> _values{};
|
||||
};
|
||||
|
||||
/* non optional bulk implementation */
|
||||
template <typename key_t, typename value_t>
|
||||
class value_container<key_t, value_t, false, true> {
|
||||
public:
|
||||
[[nodiscard]] inline const value_t& value(size_t index) const {
|
||||
return this->_values[index];
|
||||
}
|
||||
|
||||
protected:
|
||||
static constexpr bool bulked_value = true;
|
||||
|
||||
void _parse(const command_parser& parser) {
|
||||
this->_values.reserve(parser.bulk_count());
|
||||
for(const auto& bulk : parser.bulks())
|
||||
this->_values.push_back(bulk.value_as<value_t>(key_t::string)); /* will cause a not found exception if missing */
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<value_t> _values{};
|
||||
};
|
||||
|
||||
template <class key_t, typename value_type_t, class is_optional_t = std::false_type, class bulk_extend = value_container<key_t, value_type_t, is_optional_t::value, false>>
|
||||
struct field : public function_parameter, public bulk_extend {
|
||||
friend struct command_invoker<field<key_t, value_type_t, is_optional_t, bulk_extend>>;
|
||||
static_assert(converter<value_type_t>::supported, "Target type isn't supported!");
|
||||
static_assert(!converter<value_type_t>::supported || converter<value_type_t>::from_string, "Target type dosn't support parsing");
|
||||
|
||||
public:
|
||||
template <bool flag = true>
|
||||
using as_optional = field<key_t, value_type_t, std::integral_constant<bool, flag>, value_container<key_t, value_type_t, flag, bulk_extend::bulked_value>>;
|
||||
|
||||
template <bool flag>
|
||||
using as_bulked = field<key_t, value_type_t, is_optional_t, value_container<key_t, value_type_t, is_optional_t::value, flag>>;
|
||||
|
||||
using optional = as_optional<true>;
|
||||
using bulked = as_bulked<true>;
|
||||
|
||||
inline static const parameter_description* describe() {
|
||||
static std::unique_ptr<parameter_description> description;
|
||||
if(!description) {
|
||||
description = std::make_unique<parameter_description>(parameter_description_field{
|
||||
1,
|
||||
key_t::string,
|
||||
is_optional_t::value,
|
||||
typeid(value_type_t)
|
||||
});
|
||||
}
|
||||
return &*description;
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]] inline constexpr bool is_optional() { return is_optional_t::value; }
|
||||
[[nodiscard]] inline constexpr bool is_bulked() { return bulk_extend::bulked_value; }
|
||||
|
||||
|
||||
~field() override = default;
|
||||
void parse(const command_parser& parser) override { this->_parse(parser); }
|
||||
};
|
||||
|
||||
template <class key_t>
|
||||
struct trigger : public function_parameter {
|
||||
public:
|
||||
inline static const parameter_description* describe() {
|
||||
static std::unique_ptr<parameter_description_switch> description;
|
||||
if(!description) {
|
||||
description = std::make_unique<parameter_description_switch>(parameter_description_switch{
|
||||
2,
|
||||
key_t::string
|
||||
});
|
||||
}
|
||||
return &*description;
|
||||
}
|
||||
|
||||
inline bool is_set() const { return this->flag_set; }
|
||||
operator bool() const { return this->flag_set; }
|
||||
|
||||
|
||||
void parse(const command_parser& parser) override { this->flag_set = parser.has_switch(key_t::string); }
|
||||
private:
|
||||
bool flag_set = false;
|
||||
};
|
||||
|
||||
template <typename key_t, typename value_t, class optional_extend, class bulk_extend>
|
||||
struct command_invoker<field<key_t, value_t, optional_extend, bulk_extend>> {
|
||||
constexpr static bool supported = true;
|
||||
|
||||
typedef field<key_t, value_t, optional_extend, bulk_extend> field_t;
|
||||
|
||||
inline static const parameter_description* describe() {
|
||||
return field_t::describe();
|
||||
}
|
||||
|
||||
inline static field_t apply(command_parser& cmd) {
|
||||
field_t result{};
|
||||
result.parse(cmd);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename key_t>
|
||||
struct command_invoker<trigger<key_t>> {
|
||||
constexpr static bool supported = true;
|
||||
|
||||
inline static const parameter_description* describe() {
|
||||
return trigger<key_t>::describe();
|
||||
}
|
||||
|
||||
inline static trigger<key_t> apply(command_parser& cmd) {
|
||||
trigger<key_t> result{};
|
||||
result.parse(cmd);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct command_invoker<command_parser&> {
|
||||
constexpr static bool supported = true;
|
||||
|
||||
inline static const parameter_description* describe() {
|
||||
static std::unique_ptr<parameter_description> description;
|
||||
if(!description)
|
||||
description = std::make_unique<parameter_description>(parameter_description_command{3});
|
||||
return &*description;
|
||||
}
|
||||
|
||||
inline static command_parser& apply(command_parser& cmd) {
|
||||
return cmd;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename C>
|
||||
struct command_invoker<C> {
|
||||
constexpr static bool supported = false;
|
||||
|
||||
using descriptor_t = std::shared_ptr<nullptr_t>;
|
||||
|
||||
inline static descriptor_t describe() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline static command_parser& apply(descriptor_t& descriptor, command_parser& cmd) {
|
||||
return cmd;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... args_t>
|
||||
struct typed_invocable_function : public invocable_function {
|
||||
template <typename arg_t>
|
||||
using command_invoker_t = command_invoker<typename impl::templates::remove_cr<arg_t>::type>;
|
||||
|
||||
void(*function)(args_t...);
|
||||
void invoke(command_parser& command) override {
|
||||
this->function(command_invoker_t<args_t>::apply(command)...);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <class key_t, typename value_type_t>
|
||||
using field = impl::field<key_t, value_type_t>;
|
||||
|
||||
template <class key_t>
|
||||
using trigger = impl::trigger<key_t>;
|
||||
|
||||
template <typename... args_t>
|
||||
inline std::array<const parameter_description*, sizeof...(args_t)> describe_function(void(*)(args_t...)) {
|
||||
static_assert(!impl::templates::_or_<(!impl::command_invoker<typename impl::templates::remove_cr<args_t>::type>::supported)...>::value, "Not any function argument type is supported");
|
||||
return {impl::command_invoker<typename impl::templates::remove_cr<args_t>::type>::describe()...};
|
||||
}
|
||||
|
||||
template <typename... args_t, typename typed_function = impl::typed_invocable_function<args_t...>>
|
||||
std::shared_ptr<invocable_function> parse_function(void(*function)(args_t...)) {
|
||||
auto result = std::make_shared<typed_function>();
|
||||
result->function = function;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* converts a literal into a template literal */
|
||||
#define _tlit(literal) ::ts::command_handler::tliterals::tliteral<decltype(literal ##_tstr)>
|
||||
#define tl(lit) _tlit(lit)
|
||||
}
|
||||
|
||||
//using desc = descriptor::base<descriptor::impl::default_options>;
|
||||
}
|
||||
|
||||
#include "command_internal.h"
|
|
@ -2,31 +2,9 @@
|
|||
|
||||
namespace ts {
|
||||
/* some inlineable implementations */
|
||||
inline command_bulk command::operator[](size_t index) {
|
||||
return this->bulk(index);
|
||||
}
|
||||
|
||||
inline command_entry command::operator[](const std::string &key) {
|
||||
return this->value(key);
|
||||
}
|
||||
|
||||
inline command_entry command_bulk::operator[](const std::string &key) {
|
||||
return this->value(key);
|
||||
}
|
||||
|
||||
inline const command_bulk command::operator[](size_t index) const {
|
||||
return this->bulk(index);
|
||||
}
|
||||
|
||||
inline const command_entry command::operator[](const std::string &key) const {
|
||||
return this->value(key);
|
||||
}
|
||||
|
||||
inline const command_entry command_bulk::operator[](const std::string &key) const {
|
||||
return this->value(key);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
using ts::descriptor::tliterals::operator""_tstr;
|
||||
using ts::command_handler::tliterals::operator""_tstr;
|
||||
#endif
|
|
@ -0,0 +1,8 @@
|
|||
//
|
||||
// Created by wolverindev on 25.01.20.
|
||||
//
|
||||
|
||||
#ifndef TEASPEAK_PARENT_COMMAND_UNUSED_H
|
||||
#define TEASPEAK_PARENT_COMMAND_UNUSED_H
|
||||
|
||||
#endif //TEASPEAK_PARENT_COMMAND_UNUSED_H
|
|
@ -2,9 +2,7 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
namespace ts {
|
||||
namespace query {
|
||||
extern std::string escape(std::string);
|
||||
extern std::string unescape(std::string, bool /* throw error */);
|
||||
}
|
||||
namespace ts::query {
|
||||
extern std::string escape(std::string);
|
||||
extern std::string unescape(std::string, bool /* throw error */);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
#include <src/query/command2.h>
|
||||
#include <src/query/command3.h>
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#include <string>
|
||||
|
@ -9,6 +9,7 @@
|
|||
#include <functional>
|
||||
#include "PermissionManager.h"
|
||||
|
||||
#include "src/query/command_handler.h"
|
||||
#include "src/query/command_constants.h"
|
||||
|
||||
using namespace std;
|
||||
|
@ -16,34 +17,13 @@ using namespace ts;
|
|||
using namespace license::teamspeak;
|
||||
|
||||
template <class key_t, typename value_type_t>
|
||||
using field = ts::descriptor::field<key_t, value_type_t>;
|
||||
using field = ts::command_handler::field<key_t, value_type_t>;
|
||||
|
||||
template <class key_t>
|
||||
using trigger = ts::descriptor::trigger<key_t>;
|
||||
|
||||
template<unsigned N>
|
||||
class FixedString {
|
||||
public:
|
||||
constexpr FixedString(char const* s) {
|
||||
for (unsigned i = 0; i < N; ++i)
|
||||
buf[i] = s[i];
|
||||
}
|
||||
|
||||
constexpr operator const char*() const { return buf; }
|
||||
[[nodiscard]] constexpr const char* c_str() const { return buf; }
|
||||
private:
|
||||
char buf[N + 1]{};
|
||||
};
|
||||
template<unsigned N> FixedString(char const (&)[N]) -> FixedString<N - 1>;
|
||||
|
||||
template<FixedString T>
|
||||
void test() {
|
||||
std::cout << "Parameter: " << T.c_str() << "\n";
|
||||
}
|
||||
|
||||
using trigger = ts::command_handler::trigger<key_t>;
|
||||
|
||||
void handleCommand(
|
||||
ts::command& _cmd,
|
||||
ts::command_parser& parser,
|
||||
const cconstants::return_code::optional& return_code,
|
||||
const field<tl("key_a"), int>& key_a,
|
||||
const field<tl("key_b"), string>::optional& key_b,
|
||||
|
@ -53,20 +33,15 @@ void handleCommand(
|
|||
if(key_a.value() < 10) {
|
||||
__asm__("nop");
|
||||
}
|
||||
__asm__("nop");
|
||||
auto b = key_c.as<string>();
|
||||
__asm__("nop");
|
||||
string key_c_str = key_c;
|
||||
|
||||
__asm__("nop");
|
||||
auto c = key_b.has_value();
|
||||
|
||||
__asm__("nop");
|
||||
(void) key_c[1].value();
|
||||
(void) key_c.value(1);
|
||||
__asm__("nop");
|
||||
(void) return_code.get_or<string>("XXX");
|
||||
//cout << << endl;
|
||||
//cout << "Return code: " << return_code.get_or<string>("XXX") << endl;
|
||||
(void) return_code.value_or("XXX");
|
||||
cout << key_b.has_value() << endl;
|
||||
cout << "Return code: " << return_code.value_or("XXX") << endl;
|
||||
__asm__("nop");
|
||||
}
|
||||
|
||||
|
@ -93,38 +68,16 @@ void eval_test(command_result x) {
|
|||
}
|
||||
}
|
||||
|
||||
struct A {
|
||||
virtual ~A() { puts("~A\n"); }
|
||||
};
|
||||
|
||||
struct B : public A {
|
||||
virtual ~B() { puts("~B\n"); }
|
||||
};
|
||||
|
||||
int main() {
|
||||
make_command_result(error::accounting_slot_limit_reached, "");
|
||||
/*
|
||||
0x559e5259a479 <main()+41>: lea 0xa0(%rsp),%rbx
|
||||
0x559e5259a481 <main()+49>: lea 0x30(%rsp),%r14
|
||||
0x559e5259a486 <main()+54>: callq 0x559e525579d0 <operator new(unsigned long)@plt>
|
||||
0x559e5259a48b <main()+59>: lea 0x17e6a6(%rip),%rdi # 0x559e52718b38
|
||||
0x559e5259a492 <main()+66>: mov %rax,%rbp
|
||||
0x559e5259a495 <main()+69>: callq 0x559e52558b10 <puts@plt>
|
||||
0x559e5259a49a <main()+74>: mov $0x1,%esi
|
||||
0x559e5259a49f <main()+79>: mov %rbp,%rdi
|
||||
0x559e5259a4a2 <main()+82>: callq 0x559e525573d0 <operator delete(void*, unsigned long)@plt>
|
||||
*/
|
||||
{
|
||||
A* var = new B{};
|
||||
delete var;
|
||||
}
|
||||
test<"abs">();
|
||||
ts::command_handler::impl::field<tl("A"), int>::as_bulked<false> a;
|
||||
std::cout << "Optional: " << a.is_optional() << "\n";
|
||||
//test<"abs">();
|
||||
//for(const auto& error : avariableErrors)
|
||||
// cout << error.name << " = " << hex << "0x" << error.errorId << "," << endl;
|
||||
|
||||
eval_test(test());
|
||||
eval_test(test2());
|
||||
eval_test(test3());
|
||||
//eval_test(test());
|
||||
//eval_test(test2());
|
||||
//eval_test(test3());
|
||||
/*
|
||||
ios_base::sync_with_stdio(false); // Avoids synchronization with C stdio on gcc
|
||||
// (either localize both or disable sync)
|
||||
|
@ -160,9 +113,12 @@ int main() {
|
|||
|
||||
//register_function(handleCommand);
|
||||
|
||||
/*
|
||||
cout << sizeof(command_result) << endl;
|
||||
ts::command cmd("notify");
|
||||
*/
|
||||
|
||||
/*
|
||||
cout << ts::command::parse("test a=b ").build(ts::command::format::BRACE_ESCAPED_QUERY) << endl;
|
||||
cout << ts::command::parse("test a=").build(ts::command::format::BRACE_ESCAPED_QUERY) << endl;
|
||||
cout << ts::command::parse("test a").build(ts::command::format::BRACE_ESCAPED_QUERY) << endl;
|
||||
|
@ -170,7 +126,17 @@ int main() {
|
|||
cout << ts::command::parse("a=c | a=c -x", false).build(ts::command::format::BRACE_ESCAPED_QUERY) << endl;
|
||||
cout << ts::command::parse("a a=c|a=c").build(ts::command::format::BRACE_ESCAPED_QUERY) << endl;
|
||||
cout << ts::command::parse("a a=c a=c2 -z | -? a=c").build(ts::command::format::BRACE_ESCAPED_QUERY) << endl;
|
||||
*/
|
||||
|
||||
std::cout << "Command v3:\n";
|
||||
{
|
||||
auto command = ts::command_parser{"a a=c a=c2 -z | -? a=2 key_c=c"};
|
||||
if(!command.parse(true)) return 1;
|
||||
|
||||
std::cout << command.bulk_count() << "\n";
|
||||
std::cout << command.bulk(1).value("a") << "\n";
|
||||
std::cout << command.has_switch("?") << "\n";
|
||||
};
|
||||
/*
|
||||
*
|
||||
cmd[0]["key_a"] = 2;
|
||||
|
@ -182,18 +148,14 @@ int main() {
|
|||
cmd.set_trigger("test2");
|
||||
cout << "Key_A => " << cmd[0]["key_a"].string() << endl;
|
||||
*/
|
||||
cmd["key_a"] = "0";
|
||||
cmd["key_b"] = "key_b_value";
|
||||
cmd["return_code"] = "ASD";
|
||||
cmd[0]["key_c"] = "key_c_value_0";
|
||||
cmd[1]["key_c"] = "key_c_value_1";
|
||||
cmd.set_trigger("test");
|
||||
|
||||
auto result = ts::descriptor::describe_function(handleCommand);
|
||||
auto result = ts::command_handler::describe_function(handleCommand);
|
||||
auto cmd_handler = ts::command_handler::parse_function(handleCommand);
|
||||
|
||||
auto cmd = ts::command_parser{"a key_a=77 a=c a=c2 -z | -? key_c=3333 c=22 a=c return_code=234"};
|
||||
if(!cmd.parse(true)) return 1;
|
||||
|
||||
auto cmd_handler = ts::descriptor::parse_function(handleCommand);
|
||||
cmd_handler->invoke(cmd);
|
||||
cout << cmd.build() << endl;
|
||||
|
||||
//auto v = ts::descriptor::entry::bulked::val;
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue