15namespace pixie::detail {
17inline constexpr std::uint8_t kLittleEndianMarker = 1;
19template <std::
size_t Size>
20void write_magic(BinaryWriter& stream,
21 const std::array<std::uint8_t, Size>& magic) {
22 for (
const std::uint8_t
byte : magic) {
23 stream.write_u8(
byte);
27template <std::
size_t Size>
28void require_magic(BinaryReader& reader,
29 const std::array<std::uint8_t, Size>& expected) {
30 for (
const std::uint8_t
byte : expected) {
31 const std::size_t offset = reader.byte_offset();
32 if (reader.read_u8() !=
byte) {
33 throw SerializationError(
"Serialized artifact has the wrong magic",
39template <std::
integral T>
40void write_integral(BinaryWriter& stream, T value) {
41 if constexpr (std::same_as<T, bool>) {
42 stream.write_u8(
static_cast<std::uint8_t
>(value));
43 }
else if constexpr (std::same_as<T, std::size_t>) {
44 stream.write_size(value);
45 }
else if constexpr (std::is_unsigned_v<T> &&
sizeof(T) == 1) {
46 stream.write_u8(
static_cast<std::uint8_t
>(value));
47 }
else if constexpr (std::is_unsigned_v<T> &&
sizeof(T) == 2) {
48 stream.write_u16(
static_cast<std::uint16_t
>(value));
49 }
else if constexpr (std::is_unsigned_v<T> &&
sizeof(T) == 4) {
50 stream.write_u32(
static_cast<std::uint32_t
>(value));
51 }
else if constexpr (std::is_unsigned_v<T> &&
sizeof(T) == 8) {
52 stream.write_u64(
static_cast<std::uint64_t
>(value));
53 }
else if constexpr (std::is_signed_v<T> &&
sizeof(T) == 1) {
54 stream.write_i8(
static_cast<std::int8_t
>(value));
55 }
else if constexpr (std::is_signed_v<T> &&
sizeof(T) == 2) {
56 stream.write_i16(
static_cast<std::int16_t
>(value));
57 }
else if constexpr (std::is_signed_v<T> &&
sizeof(T) == 4) {
58 stream.write_i32(
static_cast<std::int32_t
>(value));
59 }
else if constexpr (std::is_signed_v<T> &&
sizeof(T) == 8) {
60 stream.write_i64(
static_cast<std::int64_t
>(value));
62 static_assert(
sizeof(T) == 0,
"Unsupported serialized integer type");
66template <std::
integral T>
67T read_integral(BinaryReader& reader) {
68 if constexpr (std::same_as<T, bool>) {
69 const std::uint8_t value = reader.read_u8();
71 throw SerializationError(
"Invalid serialized boolean value",
72 reader.byte_offset() - 1);
75 }
else if constexpr (std::same_as<T, std::size_t>) {
76 return reader.read_size();
77 }
else if constexpr (std::is_unsigned_v<T> &&
sizeof(T) == 1) {
78 return static_cast<T
>(reader.read_u8());
79 }
else if constexpr (std::is_unsigned_v<T> &&
sizeof(T) == 2) {
80 return static_cast<T
>(reader.read_u16());
81 }
else if constexpr (std::is_unsigned_v<T> &&
sizeof(T) == 4) {
82 return static_cast<T
>(reader.read_u32());
83 }
else if constexpr (std::is_unsigned_v<T> &&
sizeof(T) == 8) {
84 return static_cast<T
>(reader.read_u64());
85 }
else if constexpr (std::is_signed_v<T> &&
sizeof(T) == 1) {
86 return static_cast<T
>(reader.read_i8());
87 }
else if constexpr (std::is_signed_v<T> &&
sizeof(T) == 2) {
88 return static_cast<T
>(reader.read_i16());
89 }
else if constexpr (std::is_signed_v<T> &&
sizeof(T) == 4) {
90 return static_cast<T
>(reader.read_i32());
91 }
else if constexpr (std::is_signed_v<T> &&
sizeof(T) == 8) {
92 return static_cast<T
>(reader.read_i64());
94 static_assert(
sizeof(T) == 0,
"Unsupported serialized integer type");
98template <std::
integral T>
99inline constexpr std::size_t kSerializedIntegralBytes =
100 std::same_as<T, std::size_t> ?
sizeof(std::uint64_t) : sizeof(T);
102template <std::
integral T>
103void write_vector(BinaryWriter& stream, std::span<const T> values) {
104 stream.write_size(values.size());
105 for (
const T value : values) {
106 write_integral(stream, value);
110template <std::
integral T>
111std::vector<T> read_vector(BinaryReader& reader) {
112 const std::size_t count = reader.read_size();
113 const std::vector<T> empty;
114 if (count > empty.max_size()) {
115 throw std::length_error(
"Serialized vector is too large");
117 if (count > reader.remaining() / kSerializedIntegralBytes<T>) {
118 throw SerializationError(
"Truncated serialized vector",
119 reader.byte_offset());
121 std::vector<T> result;
122 result.reserve(count);
123 for (std::size_t i = 0; i < count; ++i) {
124 result.push_back(read_integral<T>(reader));
129inline std::size_t checked_artifact_size(std::uint64_t encoded_size,
130 std::size_t header_size,
131 std::size_t available_size) {
132 if (encoded_size > std::numeric_limits<std::size_t>::max()) {
133 throw std::length_error(
"Serialized artifact size does not fit in size_t");
135 const std::size_t size =
static_cast<std::size_t
>(encoded_size);
136 if (size < header_size || size > available_size) {
137 throw std::invalid_argument(
"Truncated serialized artifact");
139 if (size %
sizeof(std::uint64_t) != 0) {
140 throw std::invalid_argument(
"Serialized artifact is not word padded");
Checked byte-oriented binary serialization primitives.