3#include "pixelbullet/filesystem/native_path.h"
11#include <system_error>
15namespace pixelbullet::serialization_internal
17inline void set_binary_io_error(std::string* error_message, std::string message)
19 if (error_message !=
nullptr)
21 *error_message = std::move(message);
25[[nodiscard]]
inline bool streamsize_fits(
const std::size_t byte_count)
noexcept
27 return byte_count <= static_cast<std::size_t>(std::numeric_limits<std::streamsize>::max());
30[[nodiscard]]
inline std::ifstream open_binary_input_file(
const std::filesystem::path& path,
const std::string_view label,
31 std::string* error_message =
nullptr)
35 set_binary_io_error(error_message,
"Failed to open " + std::string(label) +
" for reading: path is empty.");
39 std::ifstream stream(filesystem::to_native_file_io_path(path), std::ios::binary);
42 set_binary_io_error(error_message,
"Failed to open " + std::string(label) +
" for reading: " + path.string());
47[[nodiscard]]
inline std::ofstream open_binary_output_file(
const std::filesystem::path& path,
const std::string_view label,
48 std::string* error_message =
nullptr)
52 set_binary_io_error(error_message,
"Failed to open " + std::string(label) +
" for writing: path is empty.");
56 const std::filesystem::path native_path = filesystem::to_native_file_io_path(path);
57 const std::filesystem::path parent = native_path.parent_path();
60 std::error_code error_code;
61 std::filesystem::create_directories(parent, error_code);
64 set_binary_io_error(error_message,
"Failed to create " + std::string(label) +
" output directory '" + parent.string() +
65 "': " + error_code.message());
70 std::ofstream stream(native_path, std::ios::binary | std::ios::trunc);
73 set_binary_io_error(error_message,
"Failed to open " + std::string(label) +
" for writing: " + path.string());
78[[nodiscard]]
inline bool finish_binary_output_file(std::ofstream& stream,
const std::filesystem::path& path,
const std::string_view label,
79 std::string* error_message =
nullptr)
84 set_binary_io_error(error_message,
"Failed to flush " + std::string(label) +
": " + path.string());
91 set_binary_io_error(error_message,
"Failed to close " + std::string(label) +
": " + path.string());
97[[nodiscard]]
inline bool read_bytes(std::istream& stream,
void* bytes,
const std::size_t byte_count)
103 if (bytes ==
nullptr || !streamsize_fits(byte_count))
107 return static_cast<bool>(stream.read(
static_cast<char*
>(bytes),
static_cast<std::streamsize
>(byte_count)));
110[[nodiscard]]
inline bool write_bytes(std::ostream& stream,
const void* bytes,
const std::size_t byte_count)
112 if (byte_count == 0u)
116 if (bytes ==
nullptr || !streamsize_fits(byte_count))
120 return static_cast<bool>(stream.write(
static_cast<const char*
>(bytes),
static_cast<std::streamsize
>(byte_count)));
124[[nodiscard]]
bool read_trivial(std::istream& stream, T& value)
126 static_assert(std::is_trivially_copyable_v<T>);
127 return read_bytes(stream, &value,
sizeof(T));
131[[nodiscard]]
bool write_trivial(std::ostream& stream,
const T& value)
133 static_assert(std::is_trivially_copyable_v<T>);
134 return write_bytes(stream, &value,
sizeof(T));
138[[nodiscard]]
bool read_trivial_span(std::istream& stream,
const std::span<T> values)
140 static_assert(std::is_trivially_copyable_v<T>);
141 return read_bytes(stream, values.data(), values.size_bytes());
145[[nodiscard]]
bool write_trivial_span(std::ostream& stream,
const std::span<const T> values)
147 static_assert(std::is_trivially_copyable_v<T>);
148 return write_bytes(stream, values.data(), values.size_bytes());