From bf1b9a20ec1a8e4d39b997a983a14cb78ceb66e8 Mon Sep 17 00:00:00 2001 From: Lukas Senionis Date: Sun, 21 Jan 2024 00:05:35 +0200 Subject: [PATCH] Add a dedicated library for working with JSON (#2047) --- .gitmodules | 4 + cmake/compile_definitions/common.cmake | 3 +- cmake/dependencies/common.cmake | 3 + cmake/dependencies/windows.cmake | 4 +- .../windows/nvprefs/driver_settings.cpp | 15 +- .../windows/nvprefs/driver_settings.h | 9 ++ .../nvprefs/nvapi_opensource_wrapper.cpp | 6 + .../windows/nvprefs/nvprefs_common.cpp | 2 + src/platform/windows/nvprefs/nvprefs_common.h | 26 +--- .../windows/nvprefs/nvprefs_interface.cpp | 6 +- .../windows/nvprefs/nvprefs_interface.h | 3 + src/platform/windows/nvprefs/undo_data.cpp | 131 ++++++++++++------ src/platform/windows/nvprefs/undo_data.h | 25 ++-- src/platform/windows/nvprefs/undo_file.cpp | 3 +- src/platform/windows/nvprefs/undo_file.h | 5 + third-party/nlohmann_json | 1 + 16 files changed, 154 insertions(+), 92 deletions(-) create mode 160000 third-party/nlohmann_json diff --git a/.gitmodules b/.gitmodules index faccb0d5..798235eb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -42,3 +42,7 @@ path = third-party/build-deps url = https://github.com/LizardByte/build-deps.git branch = dist +[submodule "third-party/nlohmann_json"] + path = third-party/nlohmann_json + url = https://github.com/nlohmann/json + branch = master diff --git a/cmake/compile_definitions/common.cmake b/cmake/compile_definitions/common.cmake index c096920a..a2ae3948 100644 --- a/cmake/compile_definitions/common.cmake +++ b/cmake/compile_definitions/common.cmake @@ -126,4 +126,5 @@ list(APPEND SUNSHINE_EXTERNAL_LIBRARIES ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${CURL_LIBRARIES} - ${PLATFORM_LIBRARIES}) + ${PLATFORM_LIBRARIES} + nlohmann_json::nlohmann_json) diff --git a/cmake/dependencies/common.cmake b/cmake/dependencies/common.cmake index 8aeb92a8..699028a2 100644 --- a/cmake/dependencies/common.cmake +++ b/cmake/dependencies/common.cmake @@ -19,6 +19,9 @@ pkg_check_modules(CURL REQUIRED libcurl) pkg_check_modules(MINIUPNP miniupnpc REQUIRED) include_directories(SYSTEM ${MINIUPNP_INCLUDE_DIRS}) +# nlohmann_json +add_subdirectory(third-party/nlohmann_json) + # ffmpeg pre-compiled binaries if(WIN32) if(NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64") diff --git a/cmake/dependencies/windows.cmake b/cmake/dependencies/windows.cmake index 3ce9a9da..376c44da 100644 --- a/cmake/dependencies/windows.cmake +++ b/cmake/dependencies/windows.cmake @@ -1,6 +1,4 @@ # windows specific dependencies set(Boost_USE_STATIC_LIBS ON) # cmake-lint: disable=C0103 -# Boost >= 1.82.0 is required for boost::json::value::set_at_pointer() support -# todo - are we actually using json? I think this was attempted to be used in a PR, but we ended up not using json -find_package(Boost 1.82.0 COMPONENTS locale log filesystem program_options json REQUIRED) +find_package(Boost 1.71.0 COMPONENTS locale log filesystem program_options REQUIRED) diff --git a/src/platform/windows/nvprefs/driver_settings.cpp b/src/platform/windows/nvprefs/driver_settings.cpp index 54529fd5..3b66e7a5 100644 --- a/src/platform/windows/nvprefs/driver_settings.cpp +++ b/src/platform/windows/nvprefs/driver_settings.cpp @@ -1,6 +1,6 @@ -#include "nvprefs_common.h" - +// local includes #include "driver_settings.h" +#include "nvprefs_common.h" namespace { @@ -94,9 +94,8 @@ namespace nvprefs { driver_settings_t::restore_global_profile_to_undo(const undo_data_t &undo_data) { if (!session_handle) return false; - auto [opengl_swapchain_saved, opengl_swapchain_our_value, opengl_swapchain_undo_value] = undo_data.get_opengl_swapchain(); - - if (opengl_swapchain_saved) { + const auto &swapchain_data = undo_data.get_opengl_swapchain(); + if (swapchain_data) { NvAPI_Status status; NvDRSProfileHandle profile_handle = 0; @@ -111,14 +110,14 @@ namespace nvprefs { setting.version = NVDRS_SETTING_VER; status = NvAPI_DRS_GetSetting(session_handle, profile_handle, OGL_CPL_PREFER_DXPRESENT_ID, &setting); - if (status == NVAPI_OK && setting.settingLocation == NVDRS_CURRENT_PROFILE_LOCATION && setting.u32CurrentValue == opengl_swapchain_our_value) { - if (opengl_swapchain_undo_value) { + if (status == NVAPI_OK && setting.settingLocation == NVDRS_CURRENT_PROFILE_LOCATION && setting.u32CurrentValue == swapchain_data->our_value) { + if (swapchain_data->undo_value) { setting = {}; setting.version = NVDRS_SETTING_VER1; setting.settingId = OGL_CPL_PREFER_DXPRESENT_ID; setting.settingType = NVDRS_DWORD_TYPE; setting.settingLocation = NVDRS_CURRENT_PROFILE_LOCATION; - setting.u32CurrentValue = *opengl_swapchain_undo_value; + setting.u32CurrentValue = *swapchain_data->undo_value; status = NvAPI_DRS_SetSetting(session_handle, profile_handle, &setting); diff --git a/src/platform/windows/nvprefs/driver_settings.h b/src/platform/windows/nvprefs/driver_settings.h index fbbc9aa1..8e10098b 100644 --- a/src/platform/windows/nvprefs/driver_settings.h +++ b/src/platform/windows/nvprefs/driver_settings.h @@ -1,5 +1,14 @@ #pragma once +// nvapi headers +// disable clang-format header reordering +// as needs types from +// clang-format off +#include +#include +// clang-format on + +// local includes #include "undo_data.h" namespace nvprefs { diff --git a/src/platform/windows/nvprefs/nvapi_opensource_wrapper.cpp b/src/platform/windows/nvprefs/nvapi_opensource_wrapper.cpp index e1010737..34657548 100644 --- a/src/platform/windows/nvprefs/nvapi_opensource_wrapper.cpp +++ b/src/platform/windows/nvprefs/nvapi_opensource_wrapper.cpp @@ -1,5 +1,11 @@ +// standard library headers +#include + +// local includes +#include "driver_settings.h" #include "nvprefs_common.h" +// special nvapi header that should be the last include #include namespace { diff --git a/src/platform/windows/nvprefs/nvprefs_common.cpp b/src/platform/windows/nvprefs/nvprefs_common.cpp index ba15dfe3..cda867df 100644 --- a/src/platform/windows/nvprefs/nvprefs_common.cpp +++ b/src/platform/windows/nvprefs/nvprefs_common.cpp @@ -1,4 +1,6 @@ +// local includes #include "nvprefs_common.h" +#include "src/main.h" // sunshine boost::log severity levels namespace nvprefs { diff --git a/src/platform/windows/nvprefs/nvprefs_common.h b/src/platform/windows/nvprefs/nvprefs_common.h index 7d4a6619..5dc8ba40 100644 --- a/src/platform/windows/nvprefs/nvprefs_common.h +++ b/src/platform/windows/nvprefs/nvprefs_common.h @@ -3,19 +3,6 @@ // sunshine utility header for generic smart pointers #include "src/utility.h" -// sunshine boost::log severity levels -#include "src/main.h" - -// standard library headers -#include -#include -#include -#include -#include -#include -#include -#include - // winapi headers // disable clang-format header reordering // clang-format off @@ -23,21 +10,12 @@ #include // clang-format on -// nvapi headers -// disable clang-format header reordering -// clang-format off -#include -#include -// clang-format on - -// boost headers -#include - namespace nvprefs { struct safe_handle: public util::safe_ptr_v2 { using util::safe_ptr_v2::safe_ptr_v2; - explicit operator bool() const { + explicit + operator bool() const { auto handle = get(); return handle != NULL && handle != INVALID_HANDLE_VALUE; } diff --git a/src/platform/windows/nvprefs/nvprefs_interface.cpp b/src/platform/windows/nvprefs/nvprefs_interface.cpp index 961788ae..ea8fa6c5 100644 --- a/src/platform/windows/nvprefs/nvprefs_interface.cpp +++ b/src/platform/windows/nvprefs/nvprefs_interface.cpp @@ -1,9 +1,7 @@ -#include "nvprefs_common.h" - +// local includes #include "nvprefs_interface.h" - #include "driver_settings.h" -#include "undo_data.h" +#include "src/main.h" // main include for assert #include "undo_file.h" namespace { diff --git a/src/platform/windows/nvprefs/nvprefs_interface.h b/src/platform/windows/nvprefs/nvprefs_interface.h index 43d588c3..583e72c5 100644 --- a/src/platform/windows/nvprefs/nvprefs_interface.h +++ b/src/platform/windows/nvprefs/nvprefs_interface.h @@ -1,5 +1,8 @@ #pragma once +// standard library headers +#include + namespace nvprefs { class nvprefs_interface { diff --git a/src/platform/windows/nvprefs/undo_data.cpp b/src/platform/windows/nvprefs/undo_data.cpp index 7abd81f7..388b02cf 100644 --- a/src/platform/windows/nvprefs/undo_data.cpp +++ b/src/platform/windows/nvprefs/undo_data.cpp @@ -1,70 +1,117 @@ -#include "nvprefs_common.h" +// external includes +#include +// local includes +#include "nvprefs_common.h" #include "undo_data.h" -namespace { +using json = nlohmann::json; - const auto opengl_swapchain_our_value_key = "/opengl_swapchain/our_value"; - const auto opengl_swapchain_undo_value_key = "/opengl_swapchain/undo_value"; +// Separate namespace for ADL, otherwise we need to define json +// functions in the same namespace as our types +namespace nlohmann { + using data_t = nvprefs::undo_data_t::data_t; + using opengl_swapchain_t = data_t::opengl_swapchain_t; -} // namespace + template + struct adl_serializer> { + static void + to_json(json &j, const std::optional &opt) { + if (opt == std::nullopt) { + j = nullptr; + } + else { + j = *opt; + } + } + + static void + from_json(const json &j, std::optional &opt) { + if (j.is_null()) { + opt = std::nullopt; + } + else { + opt = j.template get(); + } + } + }; + + template <> + struct adl_serializer { + static void + to_json(json &j, const data_t &data) { + j = json { { "opengl_swapchain", data.opengl_swapchain } }; + } + + static void + from_json(const json &j, data_t &data) { + j.at("opengl_swapchain").get_to(data.opengl_swapchain); + } + }; + + template <> + struct adl_serializer { + static void + to_json(json &j, const opengl_swapchain_t &opengl_swapchain) { + j = json { + { "our_value", opengl_swapchain.our_value }, + { "undo_value", opengl_swapchain.undo_value } + }; + } + + static void + from_json(const json &j, opengl_swapchain_t &opengl_swapchain) { + j.at("our_value").get_to(opengl_swapchain.our_value); + j.at("undo_value").get_to(opengl_swapchain.undo_value); + } + }; +} // namespace nlohmann namespace nvprefs { void undo_data_t::set_opengl_swapchain(uint32_t our_value, std::optional undo_value) { - data.set_at_pointer(opengl_swapchain_our_value_key, our_value); - if (undo_value) { - data.set_at_pointer(opengl_swapchain_undo_value_key, *undo_value); - } - else { - data.set_at_pointer(opengl_swapchain_undo_value_key, nullptr); - } + data.opengl_swapchain = data_t::opengl_swapchain_t { + our_value, + undo_value + }; } - std::tuple> + std::optional undo_data_t::get_opengl_swapchain() const { - auto get_value = [this](const auto &key) -> std::tuple> { - try { - auto value = data.at_pointer(key); - if (value.is_null()) { - return { true, std::nullopt }; - } - else if (value.is_number()) { - return { true, value.template to_number() }; - } - } - catch (...) { - } - error_message(std::string("Couldn't find ") + key + " element"); - return { false, std::nullopt }; - }; - - auto [our_value_present, our_value] = get_value(opengl_swapchain_our_value_key); - auto [undo_value_present, undo_value] = get_value(opengl_swapchain_undo_value_key); - - if (!our_value_present || !undo_value_present || !our_value) { - return { false, 0, std::nullopt }; - } - - return { true, *our_value, undo_value }; + return data.opengl_swapchain; } std::string undo_data_t::write() const { - return boost::json::serialize(data); + try { + // Keep this assignment otherwise data will be treated as an array due to + // initializer list shenanigangs. + const json json_data = data; + return json_data.dump(); + } + catch (const std::exception &err) { + error_message(std::string { "failed to serialize json data" }); + return {}; + } } void undo_data_t::read(const std::vector &buffer) { - data = boost::json::parse(std::string_view(buffer.data(), buffer.size())); + try { + data = json::parse(std::begin(buffer), std::end(buffer)); + } + catch (const std::exception &err) { + error_message(std::string { "failed to parse json data: " } + err.what()); + data = {}; + } } void undo_data_t::merge(const undo_data_t &newer_data) { - auto [opengl_swapchain_saved, opengl_swapchain_our_value, opengl_swapchain_undo_value] = newer_data.get_opengl_swapchain(); - if (opengl_swapchain_saved) { - set_opengl_swapchain(opengl_swapchain_our_value, opengl_swapchain_undo_value); + const auto &swapchain_data = newer_data.get_opengl_swapchain(); + if (swapchain_data) { + set_opengl_swapchain(swapchain_data->our_value, swapchain_data->undo_value); } } diff --git a/src/platform/windows/nvprefs/undo_data.h b/src/platform/windows/nvprefs/undo_data.h index 999483e1..d5f30251 100644 --- a/src/platform/windows/nvprefs/undo_data.h +++ b/src/platform/windows/nvprefs/undo_data.h @@ -1,24 +1,33 @@ #pragma once +// standard library headers +#include +#include +#include +#include + namespace nvprefs { class undo_data_t { public: + struct data_t { + struct opengl_swapchain_t { + uint32_t our_value; + std::optional undo_value; + }; + + std::optional opengl_swapchain; + }; + void set_opengl_swapchain(uint32_t our_value, std::optional undo_value); - std::tuple> + std::optional get_opengl_swapchain() const; - void - write(std::ostream &stream) const; - std::string write() const; - void - read(std::istream &stream); - void read(const std::vector &buffer); @@ -26,7 +35,7 @@ namespace nvprefs { merge(const undo_data_t &newer_data); private: - boost::json::value data; + data_t data; }; } // namespace nvprefs diff --git a/src/platform/windows/nvprefs/undo_file.cpp b/src/platform/windows/nvprefs/undo_file.cpp index 8a459550..9f2648ab 100644 --- a/src/platform/windows/nvprefs/undo_file.cpp +++ b/src/platform/windows/nvprefs/undo_file.cpp @@ -1,5 +1,4 @@ -#include "nvprefs_common.h" - +// local includes #include "undo_file.h" namespace { diff --git a/src/platform/windows/nvprefs/undo_file.h b/src/platform/windows/nvprefs/undo_file.h index 46dcba61..acbfbae2 100644 --- a/src/platform/windows/nvprefs/undo_file.h +++ b/src/platform/windows/nvprefs/undo_file.h @@ -1,5 +1,10 @@ #pragma once +// standard library headers +#include + +// local includes +#include "nvprefs_common.h" #include "undo_data.h" namespace nvprefs { diff --git a/third-party/nlohmann_json b/third-party/nlohmann_json new file mode 160000 index 00000000..9cca280a --- /dev/null +++ b/third-party/nlohmann_json @@ -0,0 +1 @@ +Subproject commit 9cca280a4d0ccf0c08f47a99aa71d1b0e52f8d03