ECSTASY
All in the name
Loading...
Searching...
No Matches
Serializer.hpp
Go to the documentation of this file.
1
11
12#ifndef ECSTASY_SERIALIZATION_SERIALIZER_HPP_
13#define ECSTASY_SERIALIZATION_SERIALIZER_HPP_
14
15#include <fstream>
16#include <sstream>
17#include <unordered_map>
18
28
30
31#define __CONCATENATE_DETAIL(x, y) x##y
32#define __CONCATENATE(x, y) __CONCATENATE_DETAIL(x, y)
33#define _REGISTER_SERIALIZABLES_AGAIN() _REGISTER_SERIALIZABLES_HELPER
34#define _REGISTER_SERIALIZABLES_HELPER(COMPONENT, a1, ...) \
35 REGISTER_SERIALIZABLE(COMPONENT, a1) \
36 __VA_OPT__(_REGISTER_SERIALIZABLES_AGAIN PARENS(COMPONENT, __VA_ARGS__))
37
44#define REGISTER_SERIALIZABLE(COMPONENT, SERIALIZER) \
45 static bool __CONCATENATE(registered_component_, __COUNTER__) = \
46 reinterpret_cast<bool &>(SERIALIZER::registerComponent<COMPONENT>(#COMPONENT));
47
54#define REGISTER_SERIALIZABLES(COMPONENT, a1, ...) EXPAND(_REGISTER_SERIALIZABLES_HELPER(COMPONENT, a1, __VA_ARGS__))
55
57{
58
68 template <typename S>
69 class Serializer : public ISerializer {
70 protected:
73
74 public:
85 template <typename U>
86 static constexpr bool is_constructible = std::is_constructible_v<U, std::add_lvalue_reference_t<S>>;
87
94 Serializer() = default;
95
102 ~Serializer() override = default;
103
112 constexpr S &inner()
113 {
114 return reinterpret_cast<S &>(*this);
115 }
116
118 void importFile(const std::filesystem::path &filename) override
119 {
120 std::ifstream fstream(filename);
121
122 importStream(fstream);
123 }
124
126 void importBytes(const std::string &content) override
127 {
128 std::stringstream stream(content);
129
130 importStream(stream);
131 }
132
134 void exportFile(const std::filesystem::path &filename) const override
135 {
136 std::ofstream fstream(filename);
137
138 exportStream(fstream);
139 }
140
142 [[nodiscard]] std::string exportBytes() const override
143 {
144 std::stringstream stream;
145
146 exportStream(stream);
147 return stream.str();
148 }
149
162 template <typename U>
163 requires concepts::has_extraction_operator<S, U> || traits::has_save_impl_for_type_v<S, U>
164 S &save(const U &object)
165 {
166 if constexpr (traits::has_save_impl_for_type_v<S, U>)
167 return inner().saveImpl(object);
168 else
169 return object >> inner();
170 }
171
185 template <typename C>
186 S &saveEntityComponent(const C &component)
187 {
188 return inner() << typeid(C) << component;
189 }
190
205 template <typename... Cs>
206 S &saveEntity(const RegistryEntity &entity)
207 {
208 S &s = inner();
209 (saveEntityComponent(entity.get<Cs>()), ...);
210 return s;
211 }
212
226 {
227 beforeSaveEntity(entity);
228 auto storages = entity.getRegistry().getEntityStorages(entity);
229
230 for (IStorage &storage : storages) {
231 auto optional_type = ecstasy::rtti::TypeRegistry::getInstance().find(storage.getComponentTypeInfos());
232
233 if (optional_type.has_value()) {
234 auto serializer = optional_type->get().tryGetSerializer<S>();
235
236 if (serializer.has_value())
237 serializer->get().save(*this, storage, entity);
238 }
239 }
240 afterSaveEntity(entity);
241 return inner();
242 }
243
256 template <typename U>
257 requires is_constructible<U> || (std::is_default_constructible_v<U> && traits::can_update_type_v<S, U>)
258 || traits::has_load_impl_for_type_v<S, U>
259 [[nodiscard]] U load()
260 {
261 if constexpr (traits::has_load_impl_for_type_v<S, U>)
262 return inner().template loadImpl<U>();
263 else if constexpr (is_constructible<U>) {
264 return U(inner());
265 } else {
266 U object;
267 inner().update(object);
268 return object;
269 }
270 }
271
283 {
284 RegistryEntity entity(registry.entityBuilder().build(), registry);
285
286 updateEntity(entity);
287 return entity;
288 }
289
305 template <typename U>
306 requires traits::has_update_impl_for_type_v<S, U> || std::is_fundamental_v<U>
308 S &update(U &object)
309 {
310 if constexpr (traits::has_update_impl_for_type_v<S, U>)
311 return inner().updateImpl(object);
312 else {
313 if constexpr (std::is_fundamental_v<U>)
314 object = inner().template load<U>();
315 else
316 object << inner();
317 return inner();
318 }
319 }
320
336 {
337 beforeUpdateEntity(entity);
339
340 while (component.has_value()) {
341 rtti::AType &type = rtti::TypeRegistry::getInstance().get(component->get().getType());
342 IStorage &storage = entity.getRegistry().getStorages().get(std::type_index(type.getStorageTypeInfo()));
343
344 component->get().load(*this, storage, entity);
345
346 component = loadComponentSerializer();
347 }
348 afterUpdateEntity(entity);
349 return inner();
350 }
351
364 template <typename U>
365 S &operator<<(const U &object)
366 {
367 return inner().save(object);
368 }
369
382 template <typename U>
383 S &operator>>(U &object)
384 {
385 return inner().update(object);
386 }
387
402 template <typename C>
404 {
406
407 return dynamic_cast<rtti::Type<C> &>(type).template registerSerializer<S>();
408 }
409
420 template <typename T>
421 [[nodiscard]] static bool hasEntityComponentSerializer()
422 {
423 auto atype = rtti::TypeRegistry::getInstance().find<T>();
424
425 if (atype.has_value())
426 return atype->get().template hasSerializer<S>();
427 return false;
428 }
429
430 protected:
432
444
453 virtual void beforeSaveEntity([[maybe_unused]] RegistryEntity &entity)
454 {
455 }
456
465 virtual void afterSaveEntity([[maybe_unused]] RegistryEntity &entity)
466 {
467 }
468
477 virtual void beforeUpdateEntity([[maybe_unused]] RegistryEntity &entity)
478 {
479 }
480
489 virtual void afterUpdateEntity([[maybe_unused]] RegistryEntity &entity)
490 {
491 }
492 };
493
494} // namespace ecstasy::serialization
495
496#endif /* !ECSTASY_SERIALIZATION_SERIALIZER_HPP_ */
Entity component serializer class bound to a specific component and a serializer type.
Interface for all serializer classes.
Entity containing a reference to the registry. Allows to find storage implicitly.
Concept to check if a type can be loaded with a serializer using the extraction operator.
Concept to check if a type can be saved with a serializer.
Concept to check if a type can be updated with a serializer.
Base class of all components storage.
Definition IStorage.hpp:44
Entity build()
Finalize the entity, making it alive.
Definition Registry.cpp:22
Entity containing a reference to the registry.
constexpr Registry & getRegistry() noexcept
Get the entity owning registry.
const C & get() const
Try to fetch the instance of component C associated to the current entity.
Base of an ECS architecture.
Definition Registry.hpp:82
constexpr const Instances< IStorage > & getStorages() const noexcept
Get a const reference to the storages instances.
EntityBuilder entityBuilder() noexcept
Create a new entity builder.
Definition Registry.cpp:33
std::vector< std::reference_wrapper< IStorage > > getEntityStorages(Entity entity)
Get the Entity Storages.
Definition Registry.cpp:43
Type erased interface for cross-platform type information.
Definition AType.hpp:46
virtual const std::type_info & getStorageTypeInfo() const noexcept=0
Get the type info of T storage type, as find by getStorageType<T>().
Type erased interface for cross-platform type information.
Definition Type.hpp:35
static TypeRegistry & getInstance() noexcept
Get the Instance object.
OptionalATypeReference find(const T &target) const noexcept
Search for a registered type.
AType & get(const T &target) const
Get a reference to the AType instance matching the target.
AType & registerType(std::string_view name)
Register a type in the registry.
Type erased interface for serializing entity components.
Interface for all serializer classes.
virtual void importStream(std::istream &stream)=0
Import data from a stream into the serializer.
virtual void exportStream(std::ostream &stream) const =0
Export the serializer content to a stream.
virtual void beforeUpdateEntity(RegistryEntity &entity)
Optional method triggered at the start of updateEntity.
virtual void beforeSaveEntity(RegistryEntity &entity)
Optional method triggered at the start of saveEntity.
void importFile(const std::filesystem::path &filename) override
Import data from a file into the serializer.
S & update(U &object)
Update an existing object from the serializer.
S & save(const U &object)
Save an object to the serializer.
constexpr S & inner()
Get a reference to the inner serializer.
std::string exportBytes() const override
Export the serializer content to a string.
virtual OptionalEntityComponentSerializer loadComponentSerializer()=0
Load the next component serializer from the stream.
S & saveEntity(const RegistryEntity &entity)
Save an entity to the serializer with explicit components.
S & updateEntity(RegistryEntity &entity)
Update all registered components of an entity from the serializer.
RegistryEntity loadEntity(Registry &registry)
Load an entity component from the serializer.
S & saveEntityComponent(const C &component)
Save an entity component to the serializer.
S & saveEntity(RegistryEntity &entity)
Save all registered components of an entity to the serializer.
U load()
Load an object from the serializer.
static IEntityComponentSerializer & registerComponent(std::string_view name)
Register a component to this serializer type.
static bool hasEntityComponentSerializer()
Get the registered components of the serializer.
S & operator>>(U &object)
Operator overload to simplify the update method.
virtual void afterSaveEntity(RegistryEntity &entity)
Optional method triggered at the end of saveEntity.
~Serializer() override=default
Destroy the Serializer.
S & operator<<(const U &object)
Operator overload to simplify the save method.
virtual void afterUpdateEntity(RegistryEntity &entity)
Optional method triggered at the end of updateEntity.
Serializer()=default
Construct a new Serializer.
static constexpr bool is_constructible
Check if a type is constructible from the serializer.
void exportFile(const std::filesystem::path &filename) const override
Export the serializer content to a file.
void importBytes(const std::string &content) override
Import data from a string into the serializer.
Concept to check if a type can be saved with a serializer using the extraction operator.
Concept to check if a type can be updated with a serializer using the insertion operator.
Concept to check if a type can be saved with a serializer using the extraction operator.
Concept to check if a type can be updated with a serializer using the insertion operator.
Namespace regrouping the serialization ecstasy classes.
Definition AType.hpp:26
T has_value(T... args)
T str(T... args)