diff --git a/.gitmodules b/.gitmodules index 80fb5f6c91..7039c7b1f7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -23,10 +23,6 @@ path = 3rdparty/SPIRV/SPIRV-Headers url = ../../KhronosGroup/SPIRV-Headers.git ignore = dirty -[submodule "3rdparty/cereal"] - path = 3rdparty/cereal - url = ../../RPCS3/cereal.git - ignore = dirty [submodule "3rdparty/zlib"] path = 3rdparty/zlib/zlib url = ../../madler/zlib diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index 338d756b0b..ac213bb7d3 100644 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -103,12 +103,6 @@ else() target_include_directories(xxhash INTERFACE xxHash) endif() - -# cereal -add_library(3rdparty_cereal INTERFACE) -target_include_directories(3rdparty_cereal INTERFACE cereal/include) - - # OpenGL # Prefer GLVND for OpenGL rather than legacy, unless it's been defined elsewhere, in the case of AppImage builds @@ -351,7 +345,6 @@ add_library(3rdparty::yaml-cpp ALIAS yaml-cpp) add_library(3rdparty::xxhash ALIAS xxhash) add_library(3rdparty::hidapi ALIAS 3rdparty_hidapi) add_library(3rdparty::libpng ALIAS ${LIBPNG_TARGET}) -add_library(3rdparty::cereal ALIAS 3rdparty_cereal) add_library(3rdparty::opengl ALIAS 3rdparty_opengl) add_library(3rdparty::stblib ALIAS 3rdparty_stblib) add_library(3rdparty::discordRPC ALIAS 3rdparty_discordRPC) diff --git a/3rdparty/cereal b/3rdparty/cereal deleted file mode 160000 index 60c69df968..0000000000 --- a/3rdparty/cereal +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 60c69df968d1c72c998cd5f23ba34e2e3718a84b diff --git a/buildfiles/msvc/rpcs3_default.props b/buildfiles/msvc/rpcs3_default.props index 90a88c1b55..2ad27957d5 100644 --- a/buildfiles/msvc/rpcs3_default.props +++ b/buildfiles/msvc/rpcs3_default.props @@ -3,7 +3,7 @@ - .\;..\;..\3rdparty\asmjit\asmjit\src;..\3rdparty\yaml-cpp\include;..\3rdparty\ffmpeg\include;..\3rdparty\cereal\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);..\3rdparty\libpng\libpng;..\3rdparty\GL;..\3rdparty\stblib\include;..\3rdparty\OpenAL\include;..\3rdparty\pugixml\src;..\3rdparty\hidapi\hidapi;..\3rdparty\Optional;..\3rdparty\xxhash + .\;..\;..\3rdparty\asmjit\asmjit\src;..\3rdparty\yaml-cpp\include;..\3rdparty\ffmpeg\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);..\3rdparty\libpng\libpng;..\3rdparty\GL;..\3rdparty\stblib\include;..\3rdparty\OpenAL\include;..\3rdparty\pugixml\src;..\3rdparty\hidapi\hidapi;..\3rdparty\Optional;..\3rdparty\xxhash $(SolutionDir)lib\$(Configuration)-$(Platform)\ $(SolutionDir)lib\$(Configuration)-$(Platform)\;$(UniversalCRT_LibraryPath_x64);$(LibraryPath) $(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)\ diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index 5ff512f455..139f403c48 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -38,7 +38,6 @@ target_sources(rpcs3_emu PRIVATE ../util/atomic.cpp ../util/logs.cpp ../util/yaml.cpp - ../util/cereal.cpp ../util/vm_native.cpp ../util/dyn_lib.cpp ../util/sysinfo.cpp @@ -76,12 +75,6 @@ else() set_source_files_properties("../util/yaml.cpp" PROPERTIES COMPILE_FLAGS -fexceptions) endif() -if(MSVC) - set_source_files_properties("../util/cereal.cpp" PROPERTIES COMPILE_FLAGS /GR) -else() - set_source_files_properties("../util/cereal.cpp" PROPERTIES COMPILE_FLAGS -frtti) -endif() - # Crypto target_sources(rpcs3_emu PRIVATE ../Crypto/aes.cpp @@ -499,7 +492,7 @@ endif() target_link_libraries(rpcs3_emu PUBLIC - 3rdparty::ffmpeg 3rdparty::cereal + 3rdparty::ffmpeg 3rdparty::opengl 3rdparty::stblib 3rdparty::vulkan 3rdparty::glew 3rdparty::libusb 3rdparty::wolfssl diff --git a/rpcs3/Emu/RSX/Capture/rsx_replay.h b/rpcs3/Emu/RSX/Capture/rsx_replay.h index 6e0a9d14aa..8049f5b6df 100644 --- a/rpcs3/Emu/RSX/Capture/rsx_replay.h +++ b/rpcs3/Emu/RSX/Capture/rsx_replay.h @@ -8,35 +8,27 @@ namespace rsx { - constexpr u32 FRAME_CAPTURE_MAGIC = 0x52524300; // ascii 'RRC/0' - constexpr u32 FRAME_CAPTURE_VERSION = 0x4; + enum : u32 + { + c_fc_magic = "RRC"_u32, + c_fc_version = 0x5, + }; + struct frame_capture_data { struct memory_block_data { std::vector data{}; - - template - void serialize(Archive& ar) - { - ar(data); - } }; // simple block to hold ps3 address and data struct memory_block { + static constexpr bool enable_bitcopy = true; + u32 offset; // Offset in rsx address space u32 location; // rsx memory location of the block u64 data_state; - - template - void serialize(Archive & ar) - { - ar(offset); - ar(location); - ar(data_state); - } }; struct replay_command @@ -45,101 +37,61 @@ namespace rsx std::unordered_set memory_state{}; // index into memory_map for the various memory blocks that need applying before this command can run u64 tile_state{0}; // tile state for this command u64 display_buffer_state{0}; - - template - void serialize(Archive & ar) - { - ar(rsx_command); - ar(memory_state); - ar(tile_state); - ar(display_buffer_state); - } }; struct tile_info { + static constexpr bool enable_bitcopy = true; + u32 tile; u32 limit; u32 pitch; u32 format; - - template - void serialize(Archive & ar) - { - ar(tile); - ar(limit); - ar(pitch); - ar(format); - } }; struct zcull_info { + static constexpr bool enable_bitcopy = true; + u32 region; u32 size; u32 start; u32 offset; u32 status0; u32 status1; - - template - void serialize(Archive & ar) - { - ar(region); - ar(size); - ar(start); - ar(offset); - ar(status0); - ar(status1); - } }; // bleh, may need to break these out, might be unnecessary to do both always struct tile_state { + static constexpr bool enable_bitcopy = true; + tile_info tiles[15]{}; zcull_info zculls[8]{}; - - template - void serialize(Archive & ar) - { - ar(tiles); - ar(zculls); - } }; struct buffer_state { + static constexpr bool enable_bitcopy = true; + u32 width{0}; u32 height{0}; u32 pitch{0}; u32 offset{0}; - - template - void serialize(Archive & ar) - { - ar(width); - ar(height); - ar(pitch); - ar(offset); - } }; struct display_buffers_state { + static constexpr bool enable_bitcopy = true; + std::array buffers{}; u32 count{0}; - - template - void serialize(Archive & ar) - { - ar(buffers); - ar(count); - } }; - u32 magic; - u32 version; + u32 magic = c_fc_magic; + u32 version = c_fc_version; + u32 LE_format = std::endian::little == std::endian::native; + // hashmap of holding various states for tile std::unordered_map tile_map; // hashmap of various memory 'changes' that can be applied to ps3 memory @@ -153,23 +105,10 @@ namespace rsx // Initial registers state at the beginning of the capture rsx::rsx_state reg_state; - template - void serialize(Archive & ar) - { - ar(magic); - ar(version); - ar(tile_map); - ar(memory_map); - ar(memory_data_map); - ar(display_buffers_map); - ar(replay_commands); - ar(reg_state); - } - void reset() { - magic = FRAME_CAPTURE_MAGIC; - version = FRAME_CAPTURE_VERSION; + magic = c_fc_magic; + version = c_fc_version; tile_map.clear(); memory_map.clear(); replay_commands.clear(); diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index c0ad5a04c5..3521944d29 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -19,7 +19,7 @@ #include "Utilities/date_time.h" #include "Utilities/StrUtil.h" -#include "util/cereal.hpp" +#include "util/serialization.hpp" #include "util/asm.hpp" #include @@ -39,6 +39,37 @@ rsx::frame_capture_data frame_capture; extern CellGcmOffsetTable offsetTable; extern thread_local std::string(*g_tls_log_prefix)(); +template <> +bool serialize(utils::serial& ar, rsx::rsx_state& o) +{ + return ar(o.transform_program, /*o.transform_constants,*/ o.registers); +} + +template <> +bool serialize(utils::serial& ar, rsx::frame_capture_data& o) +{ + ar(o.magic, o.version, o.LE_format); + + if (o.magic != rsx::c_fc_magic || o.version != rsx::c_fc_version || o.LE_format != (std::endian::little == std::endian::native)) + { + return false; + } + + return ar(o.tile_map, o.memory_map, o.memory_data_map, o.display_buffers_map, o.replay_commands, o.reg_state); +} + +template <> +bool serialize(utils::serial& ar, rsx::frame_capture_data::memory_block_data& o) +{ + return ar(o.data); +} + +template <> +bool serialize(utils::serial& ar, rsx::frame_capture_data::replay_command& o) +{ + return ar(o.rsx_command, o.memory_state, o.tile_state, o.display_buffer_state); +} + namespace rsx { std::function g_access_violation_handler; @@ -2861,11 +2892,14 @@ namespace rsx const std::string file_path = fs::get_config_dir() + "captures/" + Emu.GetTitleID() + "_" + date_time::current_time_narrow() + "_capture.rrc"; // todo: may want to compress this data? - const std::string file_data = cereal_serialize(frame_capture); + utils::serial save_manager; + save_manager.reserve(0x800'0000); // 128MB + + save_manager(frame_capture); fs::pending_file temp(file_path); - if (temp.file && (temp.file.write(file_data), temp.commit(false))) + if (temp.file && (temp.file.write(save_manager.data), temp.commit(false))) { rsx_log.success("Capture successful: %s", file_path); } diff --git a/rpcs3/Emu/RSX/rsx_methods.h b/rpcs3/Emu/RSX/rsx_methods.h index 2278d8ec60..a9845c79e5 100644 --- a/rpcs3/Emu/RSX/rsx_methods.h +++ b/rpcs3/Emu/RSX/rsx_methods.h @@ -554,15 +554,6 @@ namespace rsx void init(); - template - void serialize(Archive & ar) - { - ar(transform_program, -// transform_constants, - registers - ); - } - u16 viewport_width() const { return decode().width(); diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 963ff0508e..b9b74328aa 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -30,7 +30,7 @@ #include "../Crypto/unself.h" #include "util/yaml.hpp" #include "util/logs.hpp" -#include "util/cereal.hpp" +#include "util/serialization.hpp" #include #include @@ -380,18 +380,31 @@ bool Emulator::BootRsxCapture(const std::string& path) } std::unique_ptr frame = std::make_unique(); - cereal_deserialize(*frame, in_file.to_string()); + utils::serial load_manager; + load_manager.set_reading_state(in_file.to_vector()); + + load_manager(*frame); in_file.close(); - if (frame->magic != rsx::FRAME_CAPTURE_MAGIC) + if (frame->magic != rsx::c_fc_magic) { sys_log.error("Invalid rsx capture file!"); return false; } - if (frame->version != rsx::FRAME_CAPTURE_VERSION) + if (frame->version != rsx::c_fc_version) { - sys_log.error("Rsx capture file version not supported! Expected %d, found %d", rsx::FRAME_CAPTURE_VERSION, frame->version); + sys_log.error("Rsx capture file version not supported! Expected %d, found %d", +rsx::c_fc_version, frame->version); + return false; + } + + if (frame->LE_format != (std::endian::little == std::endian::native)) + { + static constexpr std::string_view machines[2]{"Big-Endian", "Little-Endian"}; + + sys_log.error("Rsx capture byte endianness not supported! Expected %s format, found %s format" + , machines[frame->LE_format ^ 1], machines[frame->LE_format]); + return false; } diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 51727b08ff..402bcdce38 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -100,10 +100,6 @@ NotUsing Sync - - NotUsing - true - NotUsing @@ -490,6 +486,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 8c76ee1cec..2c6076d531 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -843,9 +843,6 @@ Utilities - - Utilities - Utilities @@ -1962,6 +1959,9 @@ Emu\GPU\RSX\Overlays + + Utilities + diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 994b61322f..b591b510d3 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -62,12 +62,12 @@ true - ..\3rdparty\7z\src;..\3rdparty\hidapi\hidapi\hidapi;.\;..\;..\3rdparty\asmjit\asmjit\src;..\3rdparty\yaml-cpp\include;..\3rdparty\ffmpeg\include;..\3rdparty\cereal\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);..\3rdparty\XAudio2Redist\include;..\3rdparty\libpng\libpng;..\3rdparty\GL;..\3rdparty\stblib\include;..\3rdparty\OpenAL\include;..\3rdparty\pugixml\src;..\3rdparty\Optional;..\3rdparty\discord-rpc\include;..\3rdparty\zlib\zlib + ..\3rdparty\7z\src;..\3rdparty\hidapi\hidapi\hidapi;.\;..\;..\3rdparty\asmjit\asmjit\src;..\3rdparty\yaml-cpp\include;..\3rdparty\ffmpeg\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);..\3rdparty\XAudio2Redist\include;..\3rdparty\libpng\libpng;..\3rdparty\GL;..\3rdparty\stblib\include;..\3rdparty\OpenAL\include;..\3rdparty\pugixml\src;..\3rdparty\Optional;..\3rdparty\discord-rpc\include;..\3rdparty\zlib\zlib $(SolutionDir)lib\$(Configuration)-$(Platform)\;$(UniversalCRT_LibraryPath_x64);$(LibraryPath) $(SolutionDir)lib\$(Configuration)-$(Platform)\;$(UniversalCRT_LibraryPath_x64);$(LibraryPath) - ..\3rdparty\7z\src;..\3rdparty\hidapi\hidapi\hidapi;.\;..\;..\3rdparty\asmjit\asmjit\src;..\3rdparty\yaml-cpp\include;..\3rdparty\ffmpeg\include;..\3rdparty\cereal\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);..\3rdparty\XAudio2Redist\include;..\3rdparty\libpng\libpng;..\3rdparty\GL;..\3rdparty\stblib\include;..\3rdparty\OpenAL\include;..\3rdparty\pugixml\src;..\3rdparty\Optional;..\3rdparty\discord-rpc\include;..\3rdparty\zlib\zlib + ..\3rdparty\7z\src;..\3rdparty\hidapi\hidapi\hidapi;.\;..\;..\3rdparty\asmjit\asmjit\src;..\3rdparty\yaml-cpp\include;..\3rdparty\ffmpeg\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);..\3rdparty\XAudio2Redist\include;..\3rdparty\libpng\libpng;..\3rdparty\GL;..\3rdparty\stblib\include;..\3rdparty\OpenAL\include;..\3rdparty\pugixml\src;..\3rdparty\Optional;..\3rdparty\discord-rpc\include;..\3rdparty\zlib\zlib diff --git a/rpcs3/util/cereal.cpp b/rpcs3/util/cereal.cpp deleted file mode 100644 index 221f8db4f9..0000000000 --- a/rpcs3/util/cereal.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "util/cereal.hpp" -#include -#include "Utilities/StrFmt.h" -#include "Emu/RSX/RSXThread.h" -#include "Emu/RSX/Capture/rsx_capture.h" - -#ifndef _MSC_VER -#pragma GCC diagnostic ignored "-Weffc++" -#endif - -#include "cereal/archives/binary.hpp" -#include -#include -#include -#include -#include -#include - -#include - -namespace cereal -{ - [[noreturn]] void throw_exception(const std::string& err) - { - fmt::throw_exception("%s", err); - } - - [[noreturn]] void throw_exception(const char* err) - { - fmt::throw_exception("%s", err); - } -} - -template <> -std::string cereal_serialize(const rsx::frame_capture_data& data) -{ - std::ostringstream os; - cereal::BinaryOutputArchive archive(os); - archive(data); - return os.str(); -} - -template <> -void cereal_deserialize(rsx::frame_capture_data& data, const std::string& src) -{ - std::istringstream is(src); - cereal::BinaryInputArchive archive(is); - archive(data); -} diff --git a/rpcs3/util/cereal.hpp b/rpcs3/util/cereal.hpp deleted file mode 100644 index 378a119150..0000000000 --- a/rpcs3/util/cereal.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include - -template -std::string cereal_serialize(const T&); - -template -void cereal_deserialize(T& data, const std::string& src); diff --git a/rpcs3/util/serialization.hpp b/rpcs3/util/serialization.hpp new file mode 100644 index 0000000000..8446dc8d66 --- /dev/null +++ b/rpcs3/util/serialization.hpp @@ -0,0 +1,346 @@ +#pragma once + +#include "util/types.hpp" +#include + +namespace stx +{ + template + struct exact_t + { + T obj; + + exact_t(T&& _obj) : obj(std::forward(_obj)) {} + + // TODO: More conversions + template requires (std::is_same_v) + operator U&() const { return obj; }; + }; +} + +namespace utils +{ + template + concept FastRandomAccess = requires (T& obj) + { + std::data(obj)[0]; + }; + + template + concept Reservable = requires (T& obj) + { + obj.reserve(0); + }; + + template + concept Bitcopy = (std::is_arithmetic_v) || (std::is_enum_v) || requires (T& obj) + { + std::enable_if_t(std::remove_cv_t::enable_bitcopy)>(); + }; + + template + concept TupleAlike = requires () + { + std::tuple_size>::value; + }; + + template + concept ListAlike = requires (T& obj) { obj.insert(obj.end(), std::declval()); }; + + struct serial + { + std::vector data; + usz pos = umax; + + // Checks if this strcuture is currently used for serialization + bool is_writing() const + { + return pos == umax; + } + + // Reserve memory for serialization + void reserve(usz size) + { + // Is a NO-OP for deserialization in order to allow usage from serialization specializations regardless + if (is_writing()) + { + data.reserve(data.size() + size); + } + } + + bool raw_serialize(const void* ptr, usz size) + { + if (is_writing()) + { + data.insert(data.end(), static_cast(ptr), static_cast(ptr) + size); + return true; + } + + ensure(data.size() - pos >= size); + std::memcpy(const_cast(ptr), data.data() + pos, size); + pos += size; + return true; + } + + // (De)serialization function + template + bool serialize(T& obj) + { + // Fallback to global overload + return ::serialize(*this, obj); + } + + // Enabled for fundamental types, enumerations and if specfied explicitly that type can be saved in pure bitwise manner + template requires Bitcopy + bool serialize(T& obj) + { + return raw_serialize(std::addressof(obj), sizeof(obj)); + } + + // std::vector, std::basic_string + template requires FastRandomAccess && ListAlike + bool serialize(T& obj) + { + if (is_writing()) + { + for (usz i = obj.size();;) + { + const usz i_old = std::exchange(i, i >> 7); + operator()(static_cast(i_old % 0x80) | (u8{!!i} << 7)); + if (!i) + break; + } + + if constexpr (std::is_trivially_copyable_v::value_type>) + { + raw_serialize(obj.data(), sizeof(obj[0]) * obj.size()); + } + else + { + for (auto&& value : obj) + { + if (!serialize(value)) + { + return false; + } + } + } + + return true; + } + + obj.clear(); + + usz size = 0; + + for (u32 i = 0;; i += 7) + { + u8 byte_data = 0; + + if (!raw_serialize(&byte_data, 1)) + { + return false; + } + + size |= static_cast(byte_data % 0x80) << i; + + if (!(byte_data >> 7)) + { + break; + } + } + + obj.resize(size); + + if constexpr (std::is_trivially_copyable_v) + { + if (!raw_serialize(obj.data(), sizeof(obj[0]) * size)) + { + obj.clear(); + return false; + } + } + else + { + for (auto&& value : obj) + { + if (!serialize(value)) + { + obj.clear(); + return false; + } + } + } + + return true; + } + + // C-array, std::array, std::span + template requires FastRandomAccess && (!ListAlike) && (!Bitcopy) + bool serialize(T& obj) + { + if constexpr (std::is_trivially_copyable_v()[0])>>) + { + return raw_serialize(std::data(obj), sizeof(obj[0]) * std::size(obj)); + } + else + { + for (auto&& value : obj) + { + if (!serialize(value)) + { + return false; + } + } + + return true; + } + } + + // std::deque, std::list, std::(unordered_)set, std::(unordered_)map, std::(unordered_)multiset, std::(unordered_)multimap + template requires (!FastRandomAccess) && ListAlike + bool serialize(T& obj) + { + if (is_writing()) + { + for (usz i = obj.size();;) + { + const usz i_old = std::exchange(i, i >> 7); + operator()(static_cast(i_old % 0x80) | (u8{!!i} << 7)); + if (!i) + break; + } + + for (auto&& value : obj) + { + if (!serialize(value)) + { + return false; + } + } + + return true; + } + + obj.clear(); + + usz size = 0; + + for (u32 i = 0;; i += 7) + { + u8 byte_data = 0; + + if (!raw_serialize(&byte_data, 1)) + { + return false; + } + + size |= static_cast(byte_data % 0x80) << i; + + if (!(byte_data >> 7)) + { + break; + } + } + + if constexpr (Reservable) + { + obj.reserve(size); + } + + for (usz i = 0; i < size; i++) + { + obj.insert(obj.end(), static_cast(*this)); + + if (!is_valid()) + { + obj.clear(); + return false; + } + } + + return true; + } + + template + bool serialize_tuple(T& obj) + { + const bool res = serialize(std::get(obj)); + constexpr usz next_i = std::min(i + 1, std::tuple_size_v - 1); + + if constexpr (next_i == i) + { + return res; + } + else + { + return res && serialize_tuple(obj); + } + } + + // std::pair, std::tuple + template requires TupleAlike && (!FastRandomAccess) + bool serialize(T& obj) + { + return serialize_tuple(obj); + } + + // Wrapper for serialize(T&), allows to pass multiple objects at once + template + bool operator()(Args&&... args) + { + return ((AUDIT(!std::is_const_v> || is_writing()) + , serialize(const_cast(static_cast(args)))), ...); + } + + // Convert serialization manager to deserializion manager (can't go the other way) + // If no arg provided reuse saved buffer + void set_reading_state(std::vector&& _data = std::vector{}) + { + if (!_data.empty()) + { + data = std::move(_data); + } + + pos = 0; + } + + template requires (std::is_constructible_v> || Bitcopy> || + std::is_constructible_v, stx::exact_t> || TupleAlike>) + operator T() + { + AUDIT(!is_writing()); + + using type = std::remove_const_t; + + if constexpr (Bitcopy) + { + u8 buf[sizeof(type)]{}; + ensure(raw_serialize(buf, sizeof(buf))); + return std::bit_cast(buf); + } + else if constexpr (std::is_constructible_v>) + { + return type(stx::exact_t(*this)); + } + else if constexpr (std::is_constructible_v) + { + type value{}; + ensure(serialize(value)); + return value; + } + else if constexpr (TupleAlike) + { + static_assert(std::tuple_size_v == 2, "Unimplemented tuple serialization!"); + return type{ operator std::remove_cvref_t(std::declval()))> + , operator std::remove_cvref_t(std::declval()))> }; + } + } + + // Returns true if writable or readable and valid + bool is_valid() const + { + return is_writing() || pos < data.size(); + } + }; +} diff --git a/rpcs3/util/types.hpp b/rpcs3/util/types.hpp index 24639e0208..b7f698cac6 100644 --- a/rpcs3/util/types.hpp +++ b/rpcs3/util/types.hpp @@ -1070,3 +1070,11 @@ constexpr bool is_same_ptr(const volatile Y* ptr) template concept PtrSame = (is_same_ptr()); + +namespace utils +{ + struct serial; +} + +template +extern bool serialize(utils::serial& ar, T& obj);