Gaia-ECS v1.0.0
A simple and powerful entity component system
Loading...
Searching...
No Matches
ser_rt.h
1#pragma once
2#include "gaia/config/config.h"
3
4#include <type_traits>
5#include <utility>
6
7#include "gaia/core/utility.h"
8#include "gaia/ser/impl/ser_dispatch.h"
9#include "gaia/ser/ser_common.h"
10
11namespace gaia {
12 namespace ser {
14 using save_raw_fn = void (*)(void*, const void*, uint32_t, serialization_type_id);
16 using load_raw_fn = void (*)(void*, void*, uint32_t, serialization_type_id);
18 using data_fn = const char* (*)(const void*);
20 using reset_fn = void (*)(void*);
22 using tell_fn = uint32_t (*)(const void*);
24 using bytes_fn = uint32_t (*)(const void*);
26 using seek_fn = void (*)(void*, uint32_t);
27
31 void* user = nullptr;
33 save_raw_fn save_raw = nullptr;
35 load_raw_fn load_raw = nullptr;
37 data_fn data = nullptr;
39 reset_fn reset = nullptr;
41 tell_fn tell = nullptr;
43 bytes_fn bytes = nullptr;
45 seek_fn seek = nullptr;
46 };
47
48 namespace detail {
49 template <typename T, typename = void>
50 struct has_save_raw_ptr: std::false_type {};
51 template <typename T>
53 T, std::void_t<decltype(std::declval<T&>().save_raw(
54 (const void*)nullptr, uint32_t{}, ser::serialization_type_id{}))>>: std::true_type {};
55
56 template <typename T, typename = void>
57 struct has_load_raw_ptr: std::false_type {};
58 template <typename T>
60 T,
61 std::void_t<decltype(std::declval<T&>().load_raw((void*)nullptr, uint32_t{}, ser::serialization_type_id{}))>>:
62 std::true_type {};
63
64 template <typename T, typename = void>
65 struct has_data_ptr: std::false_type {};
66 template <typename T>
67 struct has_data_ptr<T, std::void_t<decltype(std::declval<const T&>().data())>>: std::true_type {};
68
69 template <typename T, typename = void>
70 struct has_reset_fn: std::false_type {};
71 template <typename T>
72 struct has_reset_fn<T, std::void_t<decltype(std::declval<T&>().reset())>>: std::true_type {};
73
74 template <typename T, typename = void>
75 struct has_tell_fn: std::false_type {};
76 template <typename T>
77 struct has_tell_fn<T, std::void_t<decltype(std::declval<const T&>().tell())>>: std::true_type {};
78
79 template <typename T, typename = void>
80 struct has_bytes_fn: std::false_type {};
81 template <typename T>
82 struct has_bytes_fn<T, std::void_t<decltype(std::declval<const T&>().bytes())>>: std::true_type {};
83
84 template <typename T, typename = void>
85 struct has_seek_fn: std::false_type {};
86 template <typename T>
87 struct has_seek_fn<T, std::void_t<decltype(std::declval<T&>().seek(uint32_t{}))>>: std::true_type {};
88 } // namespace detail
89
94 struct serializer {
97
98 serializer() = default;
99
102 explicit serializer(const serializer_ctx& ctx): m_ctx(ctx) {}
103
106 GAIA_NODISCARD bool valid() const {
107 return m_ctx.user != nullptr && m_ctx.save_raw != nullptr && m_ctx.load_raw != nullptr &&
108 m_ctx.tell != nullptr && m_ctx.seek != nullptr;
109 }
110
114 template <typename T>
115 void save(const T& arg) {
116 auto saveTrivial = [](auto& serializer, const auto& value) {
117 serializer.save_raw(value);
118 };
119 detail::save_dispatch(*this, arg, saveTrivial);
120 }
121
125 template <typename T>
126 void load(T& arg) {
127 auto loadTrivial = [](auto& serializer, auto& value) {
128 serializer.load_raw(value);
129 };
130 detail::load_dispatch(*this, arg, loadTrivial);
131 }
132
133#if GAIA_ASSERT_ENABLED
134 template <typename T>
135 void check(const T& arg) {
136 T tmp{};
137
138 // Make sure that we write just as many bytes as we read.
139 // If positions are the same there is a good chance that save and load match.
140 const auto pos0 = tell();
141 save(arg);
142 const auto pos1 = tell();
143 seek(pos0);
144 load(tmp);
145 const auto pos2 = tell();
146 GAIA_ASSERT(pos2 == pos1);
147
148 // Return back to the original position in the buffer.
149 seek(pos0);
150 }
151#endif
152
156 template <typename T>
157 void save_raw(const T& value) {
158 save_raw(&value, sizeof(value), ser::type_id<T>());
159 }
160
164 template <typename T>
165 void load_raw(T& value) {
166 load_raw(&value, sizeof(value), ser::type_id<T>());
167 }
168
173 void save_raw(const void* src, uint32_t size, serialization_type_id id) {
174 GAIA_ASSERT(m_ctx.save_raw != nullptr);
175 m_ctx.save_raw(m_ctx.user, src, size, id);
176 }
177
182 void load_raw(void* src, uint32_t size, serialization_type_id id) {
183 GAIA_ASSERT(m_ctx.load_raw != nullptr);
184 m_ctx.load_raw(m_ctx.user, src, size, id);
185 }
186
189 GAIA_NODISCARD const char* data() const {
190 if (m_ctx.data == nullptr)
191 return nullptr;
192 return m_ctx.data(m_ctx.user);
193 }
194
196 void reset() {
197 if (m_ctx.reset == nullptr)
198 return;
200 }
201
204 GAIA_NODISCARD uint32_t tell() const {
205 GAIA_ASSERT(m_ctx.tell != nullptr);
206 return m_ctx.tell(m_ctx.user);
207 }
208
211 GAIA_NODISCARD uint32_t bytes() const {
212 if (m_ctx.bytes == nullptr)
213 return 0;
214 return m_ctx.bytes(m_ctx.user);
215 }
216
219 void seek(uint32_t pos) {
220 GAIA_ASSERT(m_ctx.seek != nullptr);
221 m_ctx.seek(m_ctx.user, pos);
222 }
223
228 template <typename TSerializer>
229 static serializer_ctx bind_ctx(TSerializer& obj) {
230 static_assert(detail::has_save_raw_ptr<TSerializer>::value, "Serializer must expose save_raw(ptr,size,id)");
231 static_assert(detail::has_load_raw_ptr<TSerializer>::value, "Serializer must expose load_raw(ptr,size,id)");
232 static_assert(detail::has_tell_fn<TSerializer>::value, "Serializer must expose tell()");
233 static_assert(detail::has_seek_fn<TSerializer>::value, "Serializer must expose seek(pos)");
234
235 serializer_ctx ctx;
236 ctx.user = &obj;
237 ctx.save_raw = [](void* ctx, const void* src, uint32_t size, serialization_type_id id) {
238 auto& s = *reinterpret_cast<TSerializer*>(ctx);
239 s.save_raw(src, size, id);
240 };
241 ctx.load_raw = [](void* ctx, void* src, uint32_t size, serialization_type_id id) {
242 auto& s = *reinterpret_cast<TSerializer*>(ctx);
243 s.load_raw(src, size, id);
244 };
245
247 ctx.data = [](const void* ctx) {
248 const auto& s = *reinterpret_cast<const TSerializer*>(ctx);
249 return (const char*)s.data();
250 };
251 }
252
254 ctx.reset = [](void* ctx) {
255 auto& s = *reinterpret_cast<TSerializer*>(ctx);
256 s.reset();
257 };
258 }
259
260 ctx.tell = [](const void* ctx) {
261 const auto& s = *reinterpret_cast<const TSerializer*>(ctx);
262 return (uint32_t)s.tell();
263 };
264
266 ctx.bytes = [](const void* ctx) {
267 const auto& s = *reinterpret_cast<const TSerializer*>(ctx);
268 return (uint32_t)s.bytes();
269 };
270 }
271
272 ctx.seek = [](void* ctx, uint32_t pos) {
273 auto& s = *reinterpret_cast<TSerializer*>(ctx);
274 s.seek(pos);
275 };
276
277 return ctx;
278 }
279
284 template <typename TSerializer>
285 static serializer bind(TSerializer& obj) {
286 return serializer(bind_ctx(obj));
287 }
288 };
289
293 inline serializer make_serializer(serializer s) {
294 return s;
295 }
296
301 template <typename TSerializer>
302 inline serializer make_serializer(TSerializer& s) {
303 return serializer::bind(s);
304 }
305 } // namespace ser
306} // namespace gaia
Definition ser_rt.h:80
Definition ser_rt.h:65
Definition ser_rt.h:70
Definition ser_rt.h:85
Definition ser_rt.h:75
Opaque runtime serializer context passed around as a single object.
Definition ser_rt.h:29
tell_fn tell
Cursor-query callback.
Definition ser_rt.h:41
bytes_fn bytes
Optional byte-count callback.
Definition ser_rt.h:43
load_raw_fn load_raw
Raw-read callback.
Definition ser_rt.h:35
data_fn data
Optional backing-data callback.
Definition ser_rt.h:37
void * user
Opaque backend instance.
Definition ser_rt.h:31
seek_fn seek
Cursor-movement callback.
Definition ser_rt.h:45
save_raw_fn save_raw
Raw-write callback.
Definition ser_rt.h:33
reset_fn reset
Optional reset callback.
Definition ser_rt.h:39
Runtime serializer type-erased handle. Traversal logic is shared with compile-time serialization,...
Definition ser_rt.h:94
GAIA_NODISCARD uint32_t bytes() const
Returns the backend byte count when exposed.
Definition ser_rt.h:211
serializer_ctx m_ctx
Bound backend context and callback table.
Definition ser_rt.h:96
void save_raw(const void *src, uint32_t size, serialization_type_id id)
Writes raw bytes through the bound backend.
Definition ser_rt.h:173
void load_raw(void *src, uint32_t size, serialization_type_id id)
Reads raw bytes through the bound backend.
Definition ser_rt.h:182
static serializer_ctx bind_ctx(TSerializer &obj)
Creates a callback context bound to a concrete backend.
Definition ser_rt.h:229
void save_raw(const T &value)
Writes the object representation of a typed value.
Definition ser_rt.h:157
void load(T &arg)
Deserializes a value through generic traversal.
Definition ser_rt.h:126
GAIA_NODISCARD uint32_t tell() const
Returns the current backend cursor.
Definition ser_rt.h:204
void reset()
Resets the backend when supported.
Definition ser_rt.h:196
void save(const T &arg)
Serializes a value through generic traversal.
Definition ser_rt.h:115
void seek(uint32_t pos)
Moves the backend cursor.
Definition ser_rt.h:219
GAIA_NODISCARD bool valid() const
Checks whether mandatory backend callbacks are bound.
Definition ser_rt.h:106
GAIA_NODISCARD const char * data() const
Returns the backend data pointer when exposed.
Definition ser_rt.h:189
void load_raw(T &value)
Reads an object representation into a typed value.
Definition ser_rt.h:165
serializer(const serializer_ctx &ctx)
Creates a serializer from an existing callback context.
Definition ser_rt.h:102
static serializer bind(TSerializer &obj)
Creates a runtime serializer bound to a concrete backend.
Definition ser_rt.h:285