2 * Copyright (C) 2024-2026 David C. Manuelda (StormBytePP)
4 * This file is part of StormByte.
6 * StormByte is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License version 3
8 * or later, as published by the Free Software Foundation.
10 * StormByte is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with StormByte. If not, see
17 * <https://www.gnu.org/licenses/lgpl-3.0.html>.
22// Out-of-line implementation of StormByte::Serializable, included by serializable.hxx.
23// See serializable.hxx for documentation of each member.
27 std::vector<std::byte> Serializable<T>::Serialize() const noexcept {
28 if constexpr (Type::Optional<T>) {
29 return SerializeOptional();
30 } else if constexpr (Type::Pair<T>) {
31 return SerializePair();
32 } else if constexpr (Type::Container<T>) {
33 return SerializeContainer();
34 } else if constexpr (Type::TriviallyCopyable<T>) {
35 return SerializeTrivial();
37 return Detail::Codec<DecayedT>::Write(m_data);
42 Expected<T, DeserializeError> Serializable<T>::Deserialize(std::span<const std::byte> data) noexcept {
43 if constexpr (Type::Optional<T>) {
44 return DeserializeOptional(data);
45 } else if constexpr (Type::Pair<T>) {
46 return DeserializePair(data);
47 } else if constexpr (Type::Container<T>) {
48 return DeserializeContainer(data);
49 } else if constexpr (Type::TriviallyCopyable<T>) {
50 return DeserializeTrivial(data);
52 return Detail::Codec<DecayedT>::Read(data);
57 Expected<T, DeserializeError> Serializable<T>::Deserialize(const std::vector<std::byte>& data) noexcept {
58 return Deserialize(std::span<const std::byte>(data.data(), data.size()));
62 std::size_t Serializable<T>::Size(const DecayedT& data) noexcept {
63 if constexpr (Type::Optional<T>) {
64 return SizeOptional(data);
65 } else if constexpr (Type::Pair<T>) {
66 return SizePair(data);
67 } else if constexpr (Type::Container<T>) {
68 return SizeContainer(data);
69 } else if constexpr (Type::TriviallyCopyable<T>) {
72 return Detail::Codec<DecayedT>::Size(data);
78 std::vector<std::byte> Serializable<T>::SerializeTrivial() const noexcept
79 requires Type::TriviallyCopyable<U> {
80 DecayedT value = m_data;
82 if constexpr (!std::is_same_v<DecayedT, bool> &&
83 std::endian::native != std::endian::little) {
84 value = Type::Detail::swap_endian(value);
88 reinterpret_cast<const std::byte*>(&value),
89 reinterpret_cast<const std::byte*>(&value) + sizeof(value)
95 std::vector<std::byte> Serializable<T>::SerializeContainer() const noexcept
96 requires Type::Container<U> {
97 const std::uint64_t size = static_cast<std::uint64_t>(m_data.size());
98 std::vector<std::byte> buffer = Serializable<std::uint64_t>(size).Serialize();
99 buffer.reserve(buffer.size() + SizeContainer(m_data));
100 for (const auto& element : m_data) {
101 Serializable<std::decay_t<decltype(element)>> element_serial(element);
102 append_vector(buffer, element_serial.Serialize());
109 std::vector<std::byte> Serializable<T>::SerializePair() const noexcept
110 requires Type::Pair<U> {
111 Serializable<std::decay_t<typename T::first_type>> first_serial(m_data.first);
112 Serializable<std::decay_t<typename T::second_type>> second_serial(m_data.second);
113 std::vector<std::byte> buffer;
114 buffer.reserve(SizePair(m_data));
115 append_vector(buffer, first_serial.Serialize());
116 append_vector(buffer, second_serial.Serialize());
122 std::vector<std::byte> Serializable<T>::SerializeOptional() const noexcept
123 requires Type::Optional<U> {
124 const bool has_value = m_data.has_value();
125 std::vector<std::byte> buffer;
126 buffer.reserve(SizeOptional(m_data));
127 append_vector(buffer, Serializable<bool>(has_value).Serialize());
128 if (m_data.has_value()) {
129 Serializable<std::decay_t<decltype(m_data.value())>> value_serial(m_data.value());
130 append_vector(buffer, value_serial.Serialize());
137 std::size_t Serializable<T>::SizeContainer(const DecayedT& data) noexcept
138 requires Type::Container<U> {
139 std::size_t size = sizeof(std::uint64_t);
140 for (const auto& element : data) {
141 size += Serializable<std::decay_t<decltype(element)>>::Size(element);
148 std::size_t Serializable<T>::SizePair(const DecayedT& data) noexcept
149 requires Type::Pair<U> {
151 Serializable<std::decay_t<typename T::first_type>>::Size(data.first) +
152 Serializable<std::decay_t<typename T::second_type>>::Size(data.second);
157 std::size_t Serializable<T>::SizeOptional(const DecayedT& data) noexcept
158 requires Type::Optional<U> {
159 std::size_t size = sizeof(bool);
160 if (data.has_value()) {
161 size += Serializable<std::decay_t<decltype(data.value())>>::Size(data.value());
168 Expected<T, DeserializeError> Serializable<T>::DeserializeTrivial(std::span<const std::byte> data) noexcept
169 requires Type::TriviallyCopyable<U> {
170 if constexpr (std::is_same_v<T, bool>) {
172 return Unexpected<DeserializeError>("Insufficient data for bool");
174 const auto raw = static_cast<unsigned char>(data[0]);
175 if (raw != 0 && raw != 1)
176 return Unexpected<DeserializeError>("Invalid bool value in stream");
180 if (data.size() < sizeof(T))
181 return Unexpected<DeserializeError>("Insufficient data for deserialization");
184 std::memcpy(&result, data.data(), sizeof(T));
186 if constexpr (std::endian::native != std::endian::little) {
187 result = Type::Detail::swap_endian(result);
196 Expected<T, DeserializeError> Serializable<T>::DeserializeContainer(std::span<const std::byte> data) noexcept
197 requires Type::Container<U> {
198 std::size_t offset = 0;
200 if (offset + sizeof(std::uint64_t) > data.size())
201 return Unexpected<DeserializeError>("Insufficient data for container size");
203 auto expected_container_size = Serializable<std::uint64_t>::Deserialize(
204 data.subspan(offset, sizeof(std::uint64_t)));
205 if (!expected_container_size)
206 return Unexpected(expected_container_size.error());
208 const std::uint64_t size = expected_container_size.value();
209 offset += sizeof(std::uint64_t);
211 if (size > static_cast<std::uint64_t>(data.size() - offset))
212 return Unexpected<DeserializeError>("Claimed container size exceeds remaining buffer");
213 if constexpr (Detail::is_std_array_v<T>) {
214 if (size != static_cast<std::uint64_t>(std::tuple_size_v<T>))
215 return Unexpected<DeserializeError>("Array size does not match serialized element count");
219 for (std::uint64_t i = 0; i < size; ++i) {
220 using ElementT = std::decay_t<typename T::value_type>;
222 if (offset >= data.size())
223 return Unexpected<DeserializeError>("Insufficient data for container element");
225 auto expected_element = Serializable<ElementT>::Deserialize(data.subspan(offset));
226 if (!expected_element)
227 return Unexpected(expected_element.error());
229 const std::size_t element_size = Serializable<ElementT>::Size(expected_element.value());
230 if constexpr (Detail::is_std_array_v<T>) {
231 container[static_cast<std::size_t>(i)] = std::move(expected_element.value());
233 container.insert(container.end(), std::move(expected_element.value()));
235 offset += element_size;
242 Expected<T, DeserializeError> Serializable<T>::DeserializePair(std::span<const std::byte> data) noexcept
243 requires Type::Pair<U> {
244 using FirstT = std::decay_t<typename T::first_type>;
245 using SecondT = std::decay_t<typename T::second_type>;
247 auto expected_first = Serializable<FirstT>::Deserialize(data);
249 return Unexpected(expected_first.error());
251 const std::size_t first_size = Serializable<FirstT>::Size(expected_first.value());
252 if (first_size > data.size())
253 return Unexpected<DeserializeError>("Insufficient data for pair second");
255 auto expected_second = Serializable<SecondT>::Deserialize(data.subspan(first_size));
256 if (!expected_second)
257 return Unexpected(expected_second.error());
259 return T{ std::move(expected_first.value()), std::move(expected_second.value()) };
264 Expected<T, DeserializeError> Serializable<T>::DeserializeOptional(std::span<const std::byte> data) noexcept
265 requires Type::Optional<U> {
266 auto expected_has = Serializable<bool>::Deserialize(data);
268 return Unexpected(expected_has.error());
270 if (!expected_has.value())
273 const std::size_t flag_size = Serializable<bool>::Size(true);
274 if (flag_size > data.size())
275 return Unexpected<DeserializeError>("Insufficient data for optional value");
277 using ValueT = std::decay_t<typename T::value_type>;
278 auto expected_value = Serializable<ValueT>::Deserialize(data.subspan(flag_size));
280 return Unexpected(expected_value.error());
282 return T{ std::move(expected_value.value()) };