-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs(serialization): add custom serializer sample
- Loading branch information
Showing
6 changed files
with
174 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Data {#examples-core-data} | ||
|
||
@brief Using the @ref core-data module. | ||
|
||
- @subpage examples-core-data-ser - @copybrief examples-core-data-ser |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
#include <cubos/core/log.hpp> | ||
#include <cubos/core/memory/stream.hpp> | ||
|
||
using cubos::core::memory::Stream; | ||
|
||
/// [Include] | ||
#include <cubos/core/data/ser/serializer.hpp> | ||
|
||
using cubos::core::data::Serializer; | ||
using cubos::core::reflection::Type; | ||
/// [Include] | ||
|
||
/// [Your own serializer] | ||
class MySerializer : public Serializer | ||
{ | ||
public: | ||
MySerializer(); | ||
|
||
protected: | ||
virtual bool decompose(const Type& type, const void* value) override; | ||
}; | ||
/// [Your own serializer] | ||
|
||
/// [Setting up hooks] | ||
#include <cubos/core/reflection/external/primitives.hpp> | ||
|
||
using cubos::core::reflection::reflect; | ||
|
||
MySerializer::MySerializer() | ||
{ | ||
this->hook<int32_t>([](Serializer&, const Type&, const void* value) { | ||
Stream::stdOut.print(*static_cast<const int32_t*>(value)); | ||
return true; | ||
}); | ||
} | ||
/// [Setting up hooks] | ||
|
||
/// [Decomposing types] | ||
#include <cubos/core/reflection/traits/array.hpp> | ||
#include <cubos/core/reflection/traits/fields.hpp> | ||
#include <cubos/core/reflection/type.hpp> | ||
|
||
using cubos::core::reflection::ArrayTrait; | ||
using cubos::core::reflection::FieldsTrait; | ||
|
||
bool MySerializer::decompose(const Type& type, const void* value) | ||
{ | ||
if (type.has<ArrayTrait>()) | ||
{ | ||
const auto& arrayTrait = type.get<ArrayTrait>(); | ||
|
||
Stream::stdOut.put('['); | ||
for (auto element : arrayTrait.view(value)) | ||
{ | ||
if (!this->write(arrayTrait.elementType(), element)) | ||
{ | ||
return false; | ||
} | ||
Stream::stdOut.print(", "); | ||
} | ||
Stream::stdOut.put(']'); | ||
|
||
return true; | ||
} | ||
/// [Decomposing types] | ||
|
||
/// [Decomposing types with fields] | ||
if (type.has<FieldsTrait>()) | ||
{ | ||
Stream::stdOut.put('{'); | ||
for (const auto& [field, fieldValue] : type.get<FieldsTrait>().view(value)) | ||
{ | ||
Stream::stdOut.printf("{}: ", field->name()); | ||
if (!this->write(field->type(), fieldValue)) | ||
{ | ||
return false; | ||
} | ||
Stream::stdOut.print(", "); | ||
} | ||
Stream::stdOut.put('}'); | ||
|
||
return true; | ||
} | ||
|
||
CUBOS_WARN("Cannot decompose '{}'", type.name()); | ||
return false; | ||
} | ||
/// [Decomposing types with fields] | ||
|
||
/// [Usage] | ||
#include <glm/vec3.hpp> | ||
|
||
#include <cubos/core/reflection/external/glm.hpp> | ||
#include <cubos/core/reflection/external/vector.hpp> | ||
|
||
int main() | ||
{ | ||
std::vector<glm::ivec3> vec{{1, 2, 3}, {4, 5, 6}}; | ||
|
||
MySerializer ser{}; | ||
ser.write(vec); | ||
} | ||
/// [Usage] | ||
|
||
/// [Output] | ||
// [{x: 1, y: 2, z: 3, }, {x: 4, y: 5, z: 6, }, ] | ||
/// [Output] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# Custom Serializer {#examples-core-data-ser-custom} | ||
|
||
@brief Implementing your own @ref cubos::core::data::Serializer "Serializer". | ||
|
||
To define your own serializer type, you'll need to include | ||
@ref core/data/ser/serializer.hpp. For simplicity, in this sample we'll use | ||
the following aliases: | ||
|
||
@snippet data/ser/custom/main.cpp Include | ||
|
||
We'll define a serializer that will print the data to the standard output. | ||
|
||
@snippet data/ser/custom/main.cpp Your own serializer | ||
|
||
In the constructor, we should set hooks to be called for serializing primitive | ||
types or any other type we want to handle specifically. | ||
|
||
In this example, we'll only handle `int32_t`, but usually you should at least | ||
cover all primitive types. | ||
|
||
@snippet data/ser/custom/main.cpp Setting up hooks | ||
|
||
The only other thing you need to do is implement the @ref | ||
cubos::core::data::Serializer::decompose "Serializer::decompose" method, which | ||
acts as a catch-all for any type without a specific hook. | ||
|
||
Here, we can use traits such as @ref cubos::core::reflection::FieldsTrait | ||
"FieldsTrait" to get the fields of a type and print them. | ||
|
||
In this sample, we'll only be handling fields and arrays, but you should try to | ||
cover as many kinds of data as possible. | ||
|
||
@snippet data/ser/custom/main.cpp Decomposing types | ||
|
||
We start by checking if the type can be viewed as an array. If it can, we | ||
recurse into its elements. | ||
Otherwise, we'll fallback to the fields of the type. | ||
|
||
@snippet data/ser/custom/main.cpp Decomposing types with fields | ||
|
||
If the type has fields, we'll iterate over them and print them. | ||
Otherwise, we'll fail by returning `false`. | ||
|
||
Using our serializer is as simple as constructing it and calling @ref | ||
cubos::core::data::Serializer::write "Serializer::write" on the data we want to | ||
serialize. | ||
|
||
In this case, we'll be serializing a `std::vector<glm::ivec3>`, which is | ||
an array of objects with three `int32_t` fields. | ||
|
||
@snippet data/ser/custom/main.cpp Usage | ||
|
||
This should output: | ||
|
||
@snippet data/ser/custom/main.cpp Output |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Serialization {#examples-core-data-ser} | ||
|
||
@brief Using the @ref core-data-ser module. | ||
|
||
- @subpage examples-core-data-ser-custom - @copybrief examples-core-data-ser-custom |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters