cfg: implement serialization to json

This commit is contained in:
DH 2025-03-17 19:31:41 +03:00
parent 01cdc83aeb
commit 3702a75cb0
5 changed files with 393 additions and 13 deletions

3
.gitmodules vendored
View file

@ -107,4 +107,7 @@
[submodule "3rdparty/GPUOpen/VulkanMemoryAllocator"]
path = 3rdparty/GPUOpen/VulkanMemoryAllocator
url = ../../Megamouse/VulkanMemoryAllocator.git
[submodule "3rdparty/json"]
path = 3rdparty/json
url = ../../nlohmann/json.git
ignore = dirty

View file

@ -353,6 +353,10 @@ add_subdirectory(opencv EXCLUDE_FROM_ALL)
# FUSION
add_subdirectory(fusion EXCLUDE_FROM_ALL)
# nlohmann json
add_library(3rdparty_json INTERFACE)
target_include_directories(3rdparty_json INTERFACE json/include)
# add nice ALIAS targets for ease of use
if(USE_SYSTEM_LIBUSB)
add_library(3rdparty::libusb ALIAS usb-1.0-shared)
@ -385,3 +389,4 @@ add_library(3rdparty::miniupnpc ALIAS libminiupnpc-static)
add_library(3rdparty::rtmidi ALIAS rtmidi)
add_library(3rdparty::opencv ALIAS ${OPENCV_TARGET})
add_library(3rdparty::fusion ALIAS Fusion)
add_library(3rdparty::json ALIAS 3rdparty_json)

View file

@ -531,6 +531,54 @@ std::string cfg::node::to_string() const
return {out.c_str(), out.size()};
}
nlohmann::json cfg::node::to_json() const
{
auto result = nlohmann::json::object();
for (const auto& node : get_nodes())
{
result[node->get_name()] = node->to_json();
}
return result;
}
bool cfg::node::from_json(const nlohmann::json &json, bool dynamic)
{
if (!json.is_object())
{
return false;
}
auto find_node = [this](std::string_view name) -> _base *
{
for (const auto& node : get_nodes())
{
if (node->get_name() == name)
{
return node;
}
}
return nullptr;
};
for (auto &[key, value] : json.get<nlohmann::json::object_t>())
{
auto keyNode = find_node(key);
if (keyNode == nullptr || (dynamic && !keyNode->get_is_dynamic()))
{
continue;
}
keyNode->from_json(value, dynamic);
}
return false;
}
bool cfg::node::from_string(std::string_view value, bool dynamic)
{
auto [result, error] = yaml_load(std::string(value));

View file

@ -5,6 +5,7 @@
#include "util/logs.hpp"
#include "util/atomic.hpp"
#include "util/shared_ptr.hpp"
#include "nlohmann/json.hpp"
#include <algorithm>
#include <utility>
@ -96,6 +97,9 @@ namespace cfg
return {};
}
virtual nlohmann::json to_json() const = 0;
virtual bool from_json(const nlohmann::json &, bool dynamic = false) = 0;
// Convert default to string (optional)
virtual std::string def_to_string() const
{
@ -145,9 +149,11 @@ namespace cfg
// Serialize node
std::string to_string() const override;
nlohmann::json to_json() const override;
// Deserialize node
bool from_string(std::string_view value, bool dynamic = false) override;
bool from_json(const nlohmann::json &, bool dynamic = false) override;
// Set default values
void from_default() override;
@ -184,6 +190,16 @@ namespace cfg
return m_value ? "true" : "false";
}
nlohmann::json to_json() const override
{
return
{
{"type", "bool"},
{"value", m_value.load()},
{"default", def},
};
}
std::string def_to_string() const override
{
return def ? "true" : "false";
@ -209,6 +225,17 @@ namespace cfg
return true;
}
bool from_json(const nlohmann::json &json, bool) override
{
if (!json.is_boolean())
{
return false;
}
m_value = json.get<nlohmann::json::boolean_t>();
return true;
}
void set(const bool& value)
{
m_value = value;
@ -263,6 +290,17 @@ namespace cfg
return result; // TODO: ???
}
nlohmann::json to_json() const override
{
return
{
{"type", "enum"},
{"value", to_string()},
{"default", def_to_string()},
{"variants", to_list()},
};
}
std::string def_to_string() const override
{
std::string result;
@ -284,6 +322,16 @@ namespace cfg
return false;
}
bool from_json(const nlohmann::json &json, bool dynamic) override
{
if (!json.is_string())
{
return false;
}
return from_string(json.get<nlohmann::json::string_t>(), dynamic);
}
std::vector<std::string> to_list() const override
{
return try_to_enum_list(&fmt_class_string<T>::format);
@ -335,6 +383,18 @@ namespace cfg
return std::to_string(m_value);
}
nlohmann::json to_json() const override
{
return
{
{"type", "int"},
{"value", m_value.load()},
{"default", def},
{"min", min},
{"man", max},
};
}
std::string def_to_string() const override
{
return std::to_string(def);
@ -352,6 +412,23 @@ namespace cfg
return false;
}
bool from_json(const nlohmann::json &json, bool) override
{
if (!json.is_number_integer())
{
return false;
}
auto value = json.get<nlohmann::json::number_integer_t>();
if (value < min || value > max)
{
return false;
}
m_value = value;
return true;
}
void set(const s64& value)
{
ensure(value >= Min && value <= Max);
@ -413,6 +490,18 @@ namespace cfg
return "0.0";
}
nlohmann::json to_json() const override
{
return
{
{"type", "float"},
{"value", m_value.load()},
{"default", def},
{"min", min},
{"man", max},
};
}
std::string def_to_string() const override
{
std::string result;
@ -436,6 +525,23 @@ namespace cfg
return false;
}
bool from_json(const nlohmann::json &json, bool) override
{
if (!json.is_number_float())
{
return false;
}
auto value = json.get<nlohmann::json::number_float_t>();
if (value < min || value > max)
{
return false;
}
m_value = value;
return true;
}
void set(const f64& value)
{
ensure(value >= Min && value <= Max);
@ -499,6 +605,18 @@ namespace cfg
return std::to_string(m_value);
}
nlohmann::json to_json() const override
{
return
{
{"type", "uint"},
{"value", m_value.load()},
{"default", def},
{"min", min},
{"man", max},
};
}
std::string def_to_string() const override
{
return std::to_string(def);
@ -516,6 +634,23 @@ namespace cfg
return false;
}
bool from_json(const nlohmann::json &json, bool) override
{
if (!json.is_number_unsigned())
{
return false;
}
auto value = json.get<nlohmann::json::number_unsigned_t>();
if (value < min || value > max)
{
return false;
}
m_value = value;
return true;
}
void set(const u64& value)
{
ensure(value >= Min && value <= Max);
@ -561,6 +696,16 @@ namespace cfg
return *m_value.load().get();
}
nlohmann::json to_json() const override
{
return
{
{"type", "string"},
{"value", to_string()},
{"default", def_to_string()},
};
}
std::string def_to_string() const override
{
return def;
@ -571,6 +716,17 @@ namespace cfg
m_value = std::string(value);
return true;
}
bool from_json(const nlohmann::json &json, bool) override
{
if (!json.is_string())
{
return false;
}
m_value = json.get<nlohmann::json::string_t>();
return true;
}
};
// Simple set entry (TODO: template for various types)
@ -602,12 +758,46 @@ namespace cfg
return { m_set.begin(), m_set.end() };
}
nlohmann::json to_json() const override
{
return
{
{"type", "set"},
{"value", to_list()},
};
}
bool from_list(std::vector<std::string>&& list) override
{
m_set = { std::make_move_iterator(list.begin()), std::make_move_iterator(list.end()) };
return true;
}
bool from_json(const nlohmann::json &json, bool) override
{
if (!json.is_array())
{
return false;
}
auto array = json.get<nlohmann::json::array_t>();
std::vector<std::string> string_array;
string_array.reserve(array.size());
for (auto &elem : array)
{
if (!elem.is_string())
{
return false;
}
string_array.push_back(elem.get<nlohmann::json::string_t>());
}
return from_list(std::move(string_array));
}
};
template<typename T>
@ -628,6 +818,31 @@ namespace cfg
return m_map;
}
nlohmann::json to_json() const override
{
return
{
{"type", "map"},
{"value", m_map},
};
}
bool from_json(const nlohmann::json &json, bool) override
{
if (!json.is_object())
{
return false;
}
for (auto &elem : json.get<nlohmann::json::object_t>())
{
set_value(elem.first, elem.second);
}
return true;
}
std::string get_value(std::string_view key);
void set_value(std::string key, std::string value);
@ -662,6 +877,57 @@ namespace cfg
return m_map;
}
nlohmann::json to_json() const override
{
auto levels = try_to_enum_list(&fmt_class_string<logs::level>::format);
auto values = nlohmann::json::object();
for (auto [key, level] : m_map)
{
std::string level_string;
fmt_class_string<logs::level>::format(level_string, fmt_unveil<logs::level>::get(level));
values[key] = level_string;
}
return
{
{"type", "log_map"},
{"values", values},
{"levels", levels},
};
}
bool from_json(const nlohmann::json &json, bool) override
{
if (!json.is_object())
{
return false;
}
for (auto [key, valueString] : json.get<nlohmann::json::object_t>())
{
if (!valueString.is_string())
{
continue;
}
logs::level value;
if (u64 int_value;
try_to_enum_value(&int_value, &fmt_class_string<logs::level>::format, valueString.get<std::string>()))
{
value = static_cast<logs::level>(static_cast<std::underlying_type_t<logs::level>>(int_value));
}
else
{
continue;
}
m_map[key] = value;
}
return true;
}
void set_map(map_of_type<logs::level>&& map);
void from_default() override;
@ -674,6 +940,61 @@ namespace cfg
std::string vid;
std::string pid;
std::pair<u16, u16> get_usb_ids() const;
nlohmann::json to_json() const
{
return {
{"path", path},
{"serial", serial},
{"vid", vid},
{"pid", pid},
};
}
bool from_json(const nlohmann::json &json)
{
if (json.contains("path"))
{
if (!json["path"].is_string())
{
return false;
}
path = json["path"];
}
if (json.contains("serial"))
{
if (!json["serial"].is_string())
{
return false;
}
path = json["serial"];
}
if (json.contains("vid"))
{
if (!json["vid"].is_string())
{
return false;
}
path = json["vid"];
}
if (json.contains("pid"))
{
if (!json["pid"].is_string())
{
return false;
}
path = json["pid"];
}
return true;
}
};
class device_entry final : public _base
@ -689,6 +1010,16 @@ namespace cfg
m_default = m_map;
}
nlohmann::json to_json() const override
{
return {};
}
bool from_json(const nlohmann::json &, bool) override
{
return false;
}
const map_of_type<device_info>& get_map() const
{
return m_map;

View file

@ -173,19 +173,12 @@ endif()
target_link_libraries(rpcs3_emu
PUBLIC
3rdparty::openal)
target_link_libraries(rpcs3_emu
PUBLIC
3rdparty::cubeb)
target_link_libraries(rpcs3_emu
PUBLIC
3rdparty::soundtouch)
target_link_libraries(rpcs3_emu
PUBLIC
3rdparty::miniupnpc)
3rdparty::openal
3rdparty::cubeb
3rdparty::soundtouch
3rdparty::miniupnpc
3rdparty::json
)
# Cell
target_sources(rpcs3_emu PRIVATE