mirror of
https://github.com/transmission/transmission
synced 2024-12-22 07:42:37 +00:00
refactor: allow Settings to register custom serializers / deserializers (#6667)
This commit is contained in:
parent
152f3e91a5
commit
11b794e656
3 changed files with 211 additions and 223 deletions
|
@ -80,7 +80,7 @@ public:
|
|||
[[nodiscard]] virtual time_t time() = 0;
|
||||
};
|
||||
|
||||
constexpr explicit tr_session_alt_speeds(Mediator& mediator) noexcept
|
||||
explicit tr_session_alt_speeds(Mediator& mediator) noexcept
|
||||
: mediator_{ mediator }
|
||||
{
|
||||
}
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
// License text can be found in the licenses/ folder.
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // int64_t, uint32_t
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
#include <fmt/core.h>
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
|||
#include "libtransmission/settings.h"
|
||||
#include "libtransmission/utils.h" // for tr_strv_strip(), tr_strlower()
|
||||
#include "libtransmission/variant.h"
|
||||
#include "libtransmission/tr-assert.h"
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
|
@ -30,115 +31,56 @@ namespace libtransmission
|
|||
{
|
||||
namespace
|
||||
{
|
||||
struct VariantConverter
|
||||
{
|
||||
public:
|
||||
template<typename T>
|
||||
static std::optional<T> load(tr_variant const& src);
|
||||
template<typename T, size_t N>
|
||||
using Lookup = std::array<std::pair<std::string_view, T>, N>;
|
||||
|
||||
template<typename T>
|
||||
static tr_variant save(T const& val);
|
||||
// ---
|
||||
|
||||
private:
|
||||
template<typename T, size_t N>
|
||||
using Lookup = std::array<std::pair<std::string_view, T>, N>;
|
||||
|
||||
static auto constexpr EncryptionKeys = Lookup<tr_encryption_mode, 3U>{ {
|
||||
{ "required", TR_ENCRYPTION_REQUIRED },
|
||||
{ "preferred", TR_ENCRYPTION_PREFERRED },
|
||||
{ "allowed", TR_CLEAR_PREFERRED },
|
||||
} };
|
||||
|
||||
static auto constexpr LogKeys = Lookup<tr_log_level, 7U>{ {
|
||||
{ "critical", TR_LOG_CRITICAL },
|
||||
{ "debug", TR_LOG_DEBUG },
|
||||
{ "error", TR_LOG_ERROR },
|
||||
{ "info", TR_LOG_INFO },
|
||||
{ "off", TR_LOG_OFF },
|
||||
{ "trace", TR_LOG_TRACE },
|
||||
{ "warn", TR_LOG_WARN },
|
||||
} };
|
||||
|
||||
static auto constexpr PreallocationKeys = Lookup<tr_open_files::Preallocation, 5U>{ {
|
||||
{ "off", tr_open_files::Preallocation::None },
|
||||
{ "none", tr_open_files::Preallocation::None },
|
||||
{ "fast", tr_open_files::Preallocation::Sparse },
|
||||
{ "sparse", tr_open_files::Preallocation::Sparse },
|
||||
{ "full", tr_open_files::Preallocation::Full },
|
||||
} };
|
||||
|
||||
static auto constexpr VerifyModeKeys = Lookup<tr_verify_added_mode, 2U>{ {
|
||||
{ "fast", TR_VERIFY_ADDED_FAST },
|
||||
{ "full", TR_VERIFY_ADDED_FULL },
|
||||
} };
|
||||
|
||||
static auto constexpr PreferredTransportKeys = Lookup<tr_preferred_transport, TR_NUM_PREFERRED_TRANSPORT>{ {
|
||||
{ "utp", TR_PREFER_UTP },
|
||||
{ "tcp", TR_PREFER_TCP },
|
||||
} };
|
||||
};
|
||||
|
||||
template<>
|
||||
std::optional<bool> VariantConverter::load(tr_variant const& src)
|
||||
bool load_bool(tr_variant const& src, bool* tgt)
|
||||
{
|
||||
if (auto val = src.get_if<bool>(); val != nullptr)
|
||||
{
|
||||
return *val;
|
||||
*tgt = *val;
|
||||
return true;
|
||||
}
|
||||
|
||||
return {};
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
tr_variant VariantConverter::save(bool const& val)
|
||||
tr_variant save_bool(bool const& val)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
template<>
|
||||
std::optional<std::chrono::milliseconds> VariantConverter::load(tr_variant const& src)
|
||||
{
|
||||
if (auto val = src.get_if<int64_t>(); val != nullptr)
|
||||
{
|
||||
return std::chrono::milliseconds(*val);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
tr_variant VariantConverter::save(std::chrono::milliseconds const& val)
|
||||
{
|
||||
return val.count();
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
template<>
|
||||
std::optional<double> VariantConverter::load(tr_variant const& src)
|
||||
bool load_double(tr_variant const& src, double* tgt)
|
||||
{
|
||||
if (auto val = src.get_if<double>(); val != nullptr)
|
||||
{
|
||||
return *val;
|
||||
*tgt = *val;
|
||||
return true;
|
||||
}
|
||||
|
||||
return {};
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
tr_variant VariantConverter::save(double const& val)
|
||||
tr_variant save_double(double const& val)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
template<>
|
||||
std::optional<tr_encryption_mode> VariantConverter::load(tr_variant const& src)
|
||||
auto constexpr EncryptionKeys = Lookup<tr_encryption_mode, 3U>{ {
|
||||
{ "required", TR_ENCRYPTION_REQUIRED },
|
||||
{ "preferred", TR_ENCRYPTION_PREFERRED },
|
||||
{ "allowed", TR_CLEAR_PREFERRED },
|
||||
} };
|
||||
|
||||
bool load_encryption_mode(tr_variant const& src, tr_encryption_mode* tgt)
|
||||
{
|
||||
static constexpr auto Keys = EncryptionKeys;
|
||||
static constexpr auto& Keys = EncryptionKeys;
|
||||
|
||||
if (auto const* val = src.get_if<std::string_view>(); val != nullptr)
|
||||
{
|
||||
|
@ -148,7 +90,8 @@ std::optional<tr_encryption_mode> VariantConverter::load(tr_variant const& src)
|
|||
{
|
||||
if (key == needle)
|
||||
{
|
||||
return encryption;
|
||||
*tgt = encryption;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -159,26 +102,35 @@ std::optional<tr_encryption_mode> VariantConverter::load(tr_variant const& src)
|
|||
{
|
||||
if (encryption == *val)
|
||||
{
|
||||
return encryption;
|
||||
*tgt = encryption;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
tr_variant VariantConverter::save(tr_encryption_mode const& val)
|
||||
tr_variant save_encryption_mode(tr_encryption_mode const& val)
|
||||
{
|
||||
return static_cast<int64_t>(val);
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
template<>
|
||||
std::optional<tr_log_level> VariantConverter::load(tr_variant const& src)
|
||||
auto constexpr LogKeys = Lookup<tr_log_level, 7U>{ {
|
||||
{ "critical", TR_LOG_CRITICAL },
|
||||
{ "debug", TR_LOG_DEBUG },
|
||||
{ "error", TR_LOG_ERROR },
|
||||
{ "info", TR_LOG_INFO },
|
||||
{ "off", TR_LOG_OFF },
|
||||
{ "trace", TR_LOG_TRACE },
|
||||
{ "warn", TR_LOG_WARN },
|
||||
} };
|
||||
|
||||
bool load_log_level(tr_variant const& src, tr_log_level* tgt)
|
||||
{
|
||||
static constexpr auto Keys = LogKeys;
|
||||
static constexpr auto& Keys = LogKeys;
|
||||
|
||||
if (auto const* val = src.get_if<std::string_view>(); val != nullptr)
|
||||
{
|
||||
|
@ -188,7 +140,8 @@ std::optional<tr_log_level> VariantConverter::load(tr_variant const& src)
|
|||
{
|
||||
if (needle == name)
|
||||
{
|
||||
return log_level;
|
||||
*tgt = log_level;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -199,72 +152,96 @@ std::optional<tr_log_level> VariantConverter::load(tr_variant const& src)
|
|||
{
|
||||
if (log_level == *val)
|
||||
{
|
||||
return log_level;
|
||||
*tgt = log_level;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
tr_variant VariantConverter::save(tr_log_level const& val)
|
||||
tr_variant save_log_level(tr_log_level const& val)
|
||||
{
|
||||
return static_cast<int64_t>(val);
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
template<>
|
||||
std::optional<tr_mode_t> VariantConverter::load(tr_variant const& src)
|
||||
bool load_mode_t(tr_variant const& src, tr_mode_t* tgt)
|
||||
{
|
||||
if (auto const* val = src.get_if<std::string_view>(); val != nullptr)
|
||||
{
|
||||
if (auto const mode = tr_num_parse<uint32_t>(*val, nullptr, 8); mode)
|
||||
{
|
||||
return static_cast<tr_mode_t>(*mode);
|
||||
*tgt = static_cast<tr_mode_t>(*mode);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (auto const* val = src.get_if<int64_t>(); val != nullptr)
|
||||
{
|
||||
return static_cast<tr_mode_t>(*val);
|
||||
*tgt = static_cast<tr_mode_t>(*val);
|
||||
return true;
|
||||
}
|
||||
|
||||
return {};
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
tr_variant VariantConverter::save(tr_mode_t const& val)
|
||||
tr_variant save_mode_t(tr_mode_t const& val)
|
||||
{
|
||||
return fmt::format("{:#03o}", val);
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
template<>
|
||||
std::optional<tr_port> VariantConverter::load(tr_variant const& src)
|
||||
bool load_msec(tr_variant const& src, std::chrono::milliseconds* tgt)
|
||||
{
|
||||
if (auto val = src.get_if<int64_t>(); val != nullptr)
|
||||
{
|
||||
*tgt = std::chrono::milliseconds(*val);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
tr_variant save_msec(std::chrono::milliseconds const& src)
|
||||
{
|
||||
return src.count();
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
bool load_port(tr_variant const& src, tr_port* tgt)
|
||||
{
|
||||
if (auto const* val = src.get_if<int64_t>(); val != nullptr)
|
||||
{
|
||||
return tr_port::from_host(*val);
|
||||
*tgt = tr_port::from_host(*val);
|
||||
return true;
|
||||
}
|
||||
|
||||
return {};
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
tr_variant VariantConverter::save(tr_port const& val)
|
||||
tr_variant save_port(tr_port const& val)
|
||||
{
|
||||
return int64_t{ val.host() };
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
template<>
|
||||
std::optional<tr_open_files::Preallocation> VariantConverter::load(tr_variant const& src)
|
||||
auto constexpr PreallocationKeys = Lookup<tr_open_files::Preallocation, 5U>{ {
|
||||
{ "off", tr_open_files::Preallocation::None },
|
||||
{ "none", tr_open_files::Preallocation::None },
|
||||
{ "fast", tr_open_files::Preallocation::Sparse },
|
||||
{ "sparse", tr_open_files::Preallocation::Sparse },
|
||||
{ "full", tr_open_files::Preallocation::Full },
|
||||
} };
|
||||
|
||||
bool load_preallocation_mode(tr_variant const& src, tr_open_files::Preallocation* tgt)
|
||||
{
|
||||
static constexpr auto Keys = PreallocationKeys;
|
||||
static constexpr auto& Keys = PreallocationKeys;
|
||||
|
||||
if (auto const* val = src.get_if<std::string_view>(); val != nullptr)
|
||||
{
|
||||
|
@ -274,7 +251,8 @@ std::optional<tr_open_files::Preallocation> VariantConverter::load(tr_variant co
|
|||
{
|
||||
if (name == needle)
|
||||
{
|
||||
return value;
|
||||
*tgt = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -285,26 +263,30 @@ std::optional<tr_open_files::Preallocation> VariantConverter::load(tr_variant co
|
|||
{
|
||||
if (value == static_cast<tr_open_files::Preallocation>(*val))
|
||||
{
|
||||
return value;
|
||||
*tgt = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
tr_variant VariantConverter::save(tr_open_files::Preallocation const& val)
|
||||
tr_variant save_preallocation_mode(tr_open_files::Preallocation const& val)
|
||||
{
|
||||
return static_cast<int64_t>(val);
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
template<>
|
||||
std::optional<tr_preferred_transport> VariantConverter::load(tr_variant const& src)
|
||||
auto constexpr PreferredTransportKeys = Lookup<tr_preferred_transport, TR_NUM_PREFERRED_TRANSPORT>{ {
|
||||
{ "utp", TR_PREFER_UTP },
|
||||
{ "tcp", TR_PREFER_TCP },
|
||||
} };
|
||||
|
||||
bool load_preferred_transport(tr_variant const& src, tr_preferred_transport* tgt)
|
||||
{
|
||||
static constexpr auto Keys = PreferredTransportKeys;
|
||||
static constexpr auto& Keys = PreferredTransportKeys;
|
||||
|
||||
if (auto const* val = src.get_if<std::string_view>(); val != nullptr)
|
||||
{
|
||||
|
@ -314,7 +296,8 @@ std::optional<tr_preferred_transport> VariantConverter::load(tr_variant const& s
|
|||
{
|
||||
if (name == needle)
|
||||
{
|
||||
return value;
|
||||
*tgt = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -325,16 +308,16 @@ std::optional<tr_preferred_transport> VariantConverter::load(tr_variant const& s
|
|||
{
|
||||
if (value == *val)
|
||||
{
|
||||
return value;
|
||||
*tgt = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
tr_variant VariantConverter::save(tr_preferred_transport const& val)
|
||||
tr_variant save_preferred_transport(tr_preferred_transport const& val)
|
||||
{
|
||||
for (auto const& [key, value] : PreferredTransportKeys)
|
||||
{
|
||||
|
@ -349,70 +332,77 @@ tr_variant VariantConverter::save(tr_preferred_transport const& val)
|
|||
|
||||
// ---
|
||||
|
||||
template<>
|
||||
std::optional<size_t> VariantConverter::load(tr_variant const& src)
|
||||
bool load_size_t(tr_variant const& src, size_t* tgt)
|
||||
{
|
||||
if (auto const* val = src.get_if<int64_t>(); val != nullptr)
|
||||
{
|
||||
return static_cast<size_t>(*val);
|
||||
*tgt = static_cast<size_t>(*val);
|
||||
return true;
|
||||
}
|
||||
|
||||
return {};
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
tr_variant VariantConverter::save(size_t const& val)
|
||||
tr_variant save_size_t(size_t const& val)
|
||||
{
|
||||
return uint64_t{ val };
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
template<>
|
||||
std::optional<std::string> VariantConverter::load(tr_variant const& src)
|
||||
bool load_string(tr_variant const& src, std::string* tgt)
|
||||
{
|
||||
if (auto const* val = src.get_if<std::string_view>(); val != nullptr)
|
||||
{
|
||||
return std::string{ *val };
|
||||
*tgt = std::string{ *val };
|
||||
return true;
|
||||
}
|
||||
|
||||
return {};
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
tr_variant VariantConverter::save(std::string const& val)
|
||||
tr_variant save_string(std::string const& val)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
template<>
|
||||
std::optional<tr_tos_t> VariantConverter::load(tr_variant const& src)
|
||||
bool load_tos_t(tr_variant const& src, tr_tos_t* tgt)
|
||||
{
|
||||
if (auto const* val = src.get_if<std::string_view>(); val != nullptr)
|
||||
{
|
||||
return tr_tos_t::from_string(*val);
|
||||
if (auto const tos = tr_tos_t::from_string(*val); tos)
|
||||
{
|
||||
*tgt = *tos;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (auto const* val = src.get_if<int64_t>(); val != nullptr)
|
||||
{
|
||||
return tr_tos_t{ static_cast<int>(*val) };
|
||||
*tgt = tr_tos_t{ static_cast<int>(*val) };
|
||||
return true;
|
||||
}
|
||||
|
||||
return {};
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
tr_variant VariantConverter::save(tr_tos_t const& val)
|
||||
tr_variant save_tos_t(tr_tos_t const& val)
|
||||
{
|
||||
return val.toString();
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
template<>
|
||||
std::optional<tr_verify_added_mode> VariantConverter::load(tr_variant const& src)
|
||||
auto constexpr VerifyModeKeys = Lookup<tr_verify_added_mode, 2U>{ {
|
||||
{ "fast", TR_VERIFY_ADDED_FAST },
|
||||
{ "full", TR_VERIFY_ADDED_FULL },
|
||||
} };
|
||||
|
||||
bool load_verify_added_mode(tr_variant const& src, tr_verify_added_mode* tgt)
|
||||
{
|
||||
static constexpr auto& Keys = VerifyModeKeys;
|
||||
|
||||
|
@ -424,7 +414,8 @@ std::optional<tr_verify_added_mode> VariantConverter::load(tr_variant const& src
|
|||
{
|
||||
if (name == needle)
|
||||
{
|
||||
return value;
|
||||
*tgt = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -435,16 +426,16 @@ std::optional<tr_verify_added_mode> VariantConverter::load(tr_variant const& src
|
|||
{
|
||||
if (value == *val)
|
||||
{
|
||||
return value;
|
||||
*tgt = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
tr_variant VariantConverter::save(tr_verify_added_mode const& val)
|
||||
tr_variant save_verify_added_mode(tr_verify_added_mode const& val)
|
||||
{
|
||||
for (auto const& [key, value] : VerifyModeKeys)
|
||||
{
|
||||
|
@ -456,47 +447,25 @@ tr_variant VariantConverter::save(tr_verify_added_mode const& val)
|
|||
|
||||
return static_cast<int64_t>(val);
|
||||
}
|
||||
|
||||
struct LoadVisitor
|
||||
{
|
||||
explicit constexpr LoadVisitor(tr_variant const& src)
|
||||
: src_{ src }
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void operator()(T* const tgt)
|
||||
{
|
||||
if (auto val = VariantConverter::load<T>(src_))
|
||||
{
|
||||
*tgt = *val;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
tr_variant const& src_;
|
||||
};
|
||||
|
||||
struct SaveVisitor
|
||||
{
|
||||
constexpr SaveVisitor(tr_variant::Map& tgt, tr_quark key)
|
||||
: tgt_{ tgt }
|
||||
, key_{ key }
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void operator()(T const* const src)
|
||||
{
|
||||
tgt_.try_emplace(key_, VariantConverter::save(*src));
|
||||
}
|
||||
|
||||
private:
|
||||
tr_variant::Map& tgt_;
|
||||
tr_quark key_;
|
||||
};
|
||||
} // unnamed namespace
|
||||
|
||||
Settings::Settings()
|
||||
{
|
||||
add_type_handler(load_bool, save_bool);
|
||||
add_type_handler(load_double, save_double);
|
||||
add_type_handler(load_encryption_mode, save_encryption_mode);
|
||||
add_type_handler(load_log_level, save_log_level);
|
||||
add_type_handler(load_mode_t, save_mode_t);
|
||||
add_type_handler(load_msec, save_msec);
|
||||
add_type_handler(load_port, save_port);
|
||||
add_type_handler(load_preallocation_mode, save_preallocation_mode);
|
||||
add_type_handler(load_preferred_transport, save_preferred_transport);
|
||||
add_type_handler(load_size_t, save_size_t);
|
||||
add_type_handler(load_string, save_string);
|
||||
add_type_handler(load_tos_t, save_tos_t);
|
||||
add_type_handler(load_verify_added_mode, save_verify_added_mode);
|
||||
}
|
||||
|
||||
void Settings::load(tr_variant const& src)
|
||||
{
|
||||
auto const* map = src.get_if<tr_variant::Map>();
|
||||
|
@ -505,11 +474,13 @@ void Settings::load(tr_variant const& src)
|
|||
return;
|
||||
}
|
||||
|
||||
for (auto& [key, prop_vptr] : fields())
|
||||
for (auto& field : fields())
|
||||
{
|
||||
if (auto const iter = map->find(key); iter != std::end(*map))
|
||||
if (auto const iter = map->find(field.key); iter != std::end(*map))
|
||||
{
|
||||
std::visit(LoadVisitor{ iter->second }, prop_vptr);
|
||||
auto const type_index = std::type_index{ field.type };
|
||||
TR_ASSERT(load_.count(type_index) == 1U);
|
||||
load_.at(type_index)(iter->second, field.ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -520,9 +491,11 @@ tr_variant Settings::save() const
|
|||
|
||||
auto map = tr_variant::Map{ std::size(fields) };
|
||||
|
||||
for (auto const& [key, prop_vptr] : fields)
|
||||
for (auto const& field : fields)
|
||||
{
|
||||
std::visit(SaveVisitor{ map, key }, prop_vptr);
|
||||
auto const type_index = std::type_index{ field.type };
|
||||
TR_ASSERT(save_.count(type_index) == 1U);
|
||||
map.try_emplace(field.key, save_.at(type_index)(field.ptr));
|
||||
}
|
||||
|
||||
return map;
|
||||
|
|
|
@ -5,19 +5,12 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <cstddef> // for size_t
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <functional>
|
||||
#include <typeindex>
|
||||
#include <typeinfo>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "libtransmission/transmission.h"
|
||||
|
||||
#include "libtransmission/log.h" // for tr_log_level
|
||||
#include "libtransmission/net.h" // for tr_port, tr_tos_t
|
||||
#include "libtransmission/open-files.h" // for tr_open_files::Preallocation
|
||||
#include "libtransmission/peer-io.h" // tr_preferred_transport
|
||||
#include "libtransmission/quark.h"
|
||||
#include "libtransmission/variant.h"
|
||||
|
||||
|
@ -32,26 +25,48 @@ public:
|
|||
[[nodiscard]] tr_variant save() const;
|
||||
|
||||
protected:
|
||||
using field_key_type = tr_quark;
|
||||
using field_mapped_type = std::variant<
|
||||
bool*,
|
||||
double*,
|
||||
size_t*,
|
||||
std::chrono::milliseconds*,
|
||||
std::string*,
|
||||
tr_encryption_mode*,
|
||||
tr_log_level*,
|
||||
tr_mode_t*,
|
||||
tr_open_files::Preallocation*,
|
||||
tr_port*,
|
||||
tr_preferred_transport*,
|
||||
tr_tos_t*,
|
||||
tr_verify_added_mode*>;
|
||||
using field_value_type = std::pair<field_key_type const, field_mapped_type>;
|
||||
using Fields = std::vector<field_value_type>;
|
||||
Settings();
|
||||
|
||||
Settings() = default;
|
||||
// convert from tr_variant to T
|
||||
template<typename T>
|
||||
using Load = bool (*)(tr_variant const& src, T* tgt);
|
||||
|
||||
// convert from T to tr_variant
|
||||
template<typename T>
|
||||
using Save = tr_variant (*)(T const& src);
|
||||
|
||||
template<typename T>
|
||||
void add_type_handler(Load<T> load, Save<T> save)
|
||||
{
|
||||
auto const key = std::type_index(typeid(T*));
|
||||
|
||||
// wrap load + save with void* wrappers so that
|
||||
// they can be stored in the save_ and load_ maps
|
||||
load_.insert_or_assign(key, [load](tr_variant const& src, void* tgt) { return load(src, static_cast<T*>(tgt)); });
|
||||
save_.insert_or_assign(key, [save](void const* src) { return save(*static_cast<T const*>(src)); });
|
||||
}
|
||||
|
||||
struct Field
|
||||
{
|
||||
template<typename T>
|
||||
Field(tr_quark key_in, T* ptr_in)
|
||||
: key{ key_in }
|
||||
, type{ typeid(T*) }
|
||||
, ptr{ ptr_in }
|
||||
{
|
||||
}
|
||||
|
||||
tr_quark key;
|
||||
std::type_info const& type;
|
||||
void* ptr;
|
||||
};
|
||||
|
||||
using Fields = std::vector<Field>;
|
||||
|
||||
[[nodiscard]] virtual Fields fields() = 0;
|
||||
|
||||
private:
|
||||
std::unordered_map<std::type_index, std::function<tr_variant(void const* src)>> save_;
|
||||
std::unordered_map<std::type_index, std::function<bool(tr_variant const& src, void* tgt)>> load_;
|
||||
};
|
||||
} // namespace libtransmission
|
||||
|
|
Loading…
Reference in a new issue