Gaia-ECS v0.9.3
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 {
13 using save_raw_fn = void (*)(void*, const void*, uint32_t, serialization_type_id);
14 using load_raw_fn = void (*)(void*, void*, uint32_t, serialization_type_id);
15 using data_fn = const char* (*)(const void*);
16 using reset_fn = void (*)(void*);
17 using tell_fn = uint32_t (*)(const void*);
18 using bytes_fn = uint32_t (*)(const void*);
19 using seek_fn = void (*)(void*, uint32_t);
20
23 void* user = nullptr;
24 save_raw_fn save_raw = nullptr;
25 load_raw_fn load_raw = nullptr;
26 data_fn data = nullptr;
27 reset_fn reset = nullptr;
28 tell_fn tell = nullptr;
29 bytes_fn bytes = nullptr;
30 seek_fn seek = nullptr;
31 };
32
33 namespace detail {
34 template <typename T, typename = void>
35 struct has_save_raw_ptr: std::false_type {};
36 template <typename T>
38 T, std::void_t<decltype(std::declval<T&>().save_raw(
39 (const void*)nullptr, uint32_t{}, ser::serialization_type_id{}))>>: std::true_type {};
40
41 template <typename T, typename = void>
42 struct has_load_raw_ptr: std::false_type {};
43 template <typename T>
45 T,
46 std::void_t<decltype(std::declval<T&>().load_raw((void*)nullptr, uint32_t{}, ser::serialization_type_id{}))>>:
47 std::true_type {};
48
49 template <typename T, typename = void>
50 struct has_data_ptr: std::false_type {};
51 template <typename T>
52 struct has_data_ptr<T, std::void_t<decltype(std::declval<const T&>().data())>>: std::true_type {};
53
54 template <typename T, typename = void>
55 struct has_reset_fn: std::false_type {};
56 template <typename T>
57 struct has_reset_fn<T, std::void_t<decltype(std::declval<T&>().reset())>>: std::true_type {};
58
59 template <typename T, typename = void>
60 struct has_tell_fn: std::false_type {};
61 template <typename T>
62 struct has_tell_fn<T, std::void_t<decltype(std::declval<const T&>().tell())>>: std::true_type {};
63
64 template <typename T, typename = void>
65 struct has_bytes_fn: std::false_type {};
66 template <typename T>
67 struct has_bytes_fn<T, std::void_t<decltype(std::declval<const T&>().bytes())>>: std::true_type {};
68
69 template <typename T, typename = void>
70 struct has_seek_fn: std::false_type {};
71 template <typename T>
72 struct has_seek_fn<T, std::void_t<decltype(std::declval<T&>().seek(uint32_t{}))>>: std::true_type {};
73 } // namespace detail
74
79 struct serializer {
80 serializer_ctx m_ctx{};
81
82 serializer() = default;
83
84 explicit serializer(const serializer_ctx& ctx): m_ctx(ctx) {}
85
86 GAIA_NODISCARD bool valid() const {
87 return m_ctx.user != nullptr && m_ctx.save_raw != nullptr && m_ctx.load_raw != nullptr &&
88 m_ctx.tell != nullptr && m_ctx.seek != nullptr;
89 }
90
91 template <typename T>
92 void save(const T& arg) {
93 auto saveTrivial = [](auto& serializer, const auto& value) {
94 serializer.save_raw(value);
95 };
96 detail::save_dispatch(*this, arg, saveTrivial);
97 }
98
99 template <typename T>
100 void load(T& arg) {
101 auto loadTrivial = [](auto& serializer, auto& value) {
102 serializer.load_raw(value);
103 };
104 detail::load_dispatch(*this, arg, loadTrivial);
105 }
106
107#if GAIA_ASSERT_ENABLED
108 template <typename T>
109 void check(const T& arg) {
110 T tmp{};
111
112 // Make sure that we write just as many bytes as we read.
113 // If positions are the same there is a good chance that save and load match.
114 const auto pos0 = tell();
115 save(arg);
116 const auto pos1 = tell();
117 seek(pos0);
118 load(tmp);
119 const auto pos2 = tell();
120 GAIA_ASSERT(pos2 == pos1);
121
122 // Return back to the original position in the buffer.
123 seek(pos0);
124 }
125#endif
126
127 template <typename T>
128 void save_raw(const T& value) {
129 save_raw(&value, sizeof(value), ser::type_id<T>());
130 }
131
132 template <typename T>
133 void load_raw(T& value) {
134 load_raw(&value, sizeof(value), ser::type_id<T>());
135 }
136
137 void save_raw(const void* src, uint32_t size, serialization_type_id id) {
138 GAIA_ASSERT(m_ctx.save_raw != nullptr);
139 m_ctx.save_raw(m_ctx.user, src, size, id);
140 }
141
142 void load_raw(void* src, uint32_t size, serialization_type_id id) {
143 GAIA_ASSERT(m_ctx.load_raw != nullptr);
144 m_ctx.load_raw(m_ctx.user, src, size, id);
145 }
146
147 GAIA_NODISCARD const char* data() const {
148 if (m_ctx.data == nullptr)
149 return nullptr;
150 return m_ctx.data(m_ctx.user);
151 }
152
153 void reset() {
154 if (m_ctx.reset == nullptr)
155 return;
156 m_ctx.reset(m_ctx.user);
157 }
158
159 GAIA_NODISCARD uint32_t tell() const {
160 GAIA_ASSERT(m_ctx.tell != nullptr);
161 return m_ctx.tell(m_ctx.user);
162 }
163
164 GAIA_NODISCARD uint32_t bytes() const {
165 if (m_ctx.bytes == nullptr)
166 return 0;
167 return m_ctx.bytes(m_ctx.user);
168 }
169
170 void seek(uint32_t pos) {
171 GAIA_ASSERT(m_ctx.seek != nullptr);
172 m_ctx.seek(m_ctx.user, pos);
173 }
174
175 template <typename TSerializer>
176 static serializer_ctx bind_ctx(TSerializer& obj) {
177 static_assert(detail::has_save_raw_ptr<TSerializer>::value, "Serializer must expose save_raw(ptr,size,id)");
178 static_assert(detail::has_load_raw_ptr<TSerializer>::value, "Serializer must expose load_raw(ptr,size,id)");
179 static_assert(detail::has_tell_fn<TSerializer>::value, "Serializer must expose tell()");
180 static_assert(detail::has_seek_fn<TSerializer>::value, "Serializer must expose seek(pos)");
181
182 serializer_ctx ctx;
183 ctx.user = &obj;
184 ctx.save_raw = [](void* ctx, const void* src, uint32_t size, serialization_type_id id) {
185 auto& s = *reinterpret_cast<TSerializer*>(ctx);
186 s.save_raw(src, size, id);
187 };
188 ctx.load_raw = [](void* ctx, void* src, uint32_t size, serialization_type_id id) {
189 auto& s = *reinterpret_cast<TSerializer*>(ctx);
190 s.load_raw(src, size, id);
191 };
192
194 ctx.data = [](const void* ctx) {
195 const auto& s = *reinterpret_cast<const TSerializer*>(ctx);
196 return (const char*)s.data();
197 };
198 }
199
201 ctx.reset = [](void* ctx) {
202 auto& s = *reinterpret_cast<TSerializer*>(ctx);
203 s.reset();
204 };
205 }
206
207 ctx.tell = [](const void* ctx) {
208 const auto& s = *reinterpret_cast<const TSerializer*>(ctx);
209 return (uint32_t)s.tell();
210 };
211
213 ctx.bytes = [](const void* ctx) {
214 const auto& s = *reinterpret_cast<const TSerializer*>(ctx);
215 return (uint32_t)s.bytes();
216 };
217 }
218
219 ctx.seek = [](void* ctx, uint32_t pos) {
220 auto& s = *reinterpret_cast<TSerializer*>(ctx);
221 s.seek(pos);
222 };
223
224 return ctx;
225 }
226
227 template <typename TSerializer>
228 static serializer bind(TSerializer& obj) {
229 return serializer(bind_ctx(obj));
230 }
231 };
232
234 inline serializer make_serializer(serializer s) {
235 return s;
236 }
237
239 template <typename TSerializer>
240 inline serializer make_serializer(TSerializer& s) {
241 return serializer::bind(s);
242 }
243 } // namespace ser
244} // namespace gaia
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9
Definition ser_rt.h:65
Definition ser_rt.h:50
Definition ser_rt.h:55
Definition ser_rt.h:70
Definition ser_rt.h:60
Opaque runtime serializer context passed around as a single object.
Definition ser_rt.h:22
Runtime serializer type-erased handle. Traversal logic is shared with compile-time serialization,...
Definition ser_rt.h:79