Skip to content

Commit

Permalink
docs(serialization): add custom serializer sample
Browse files Browse the repository at this point in the history
  • Loading branch information
RiscadoA committed Oct 2, 2023
1 parent 594f935 commit 1d995ee
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 0 deletions.
1 change: 1 addition & 0 deletions core/samples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ make_sample(DIR "reflection/traits/array")
make_sample(DIR "reflection/traits/dictionary")
make_sample(DIR "data/fs/embedded_archive" SOURCES "embed.cpp")
make_sample(DIR "data/fs/standard_archive")
make_sample(DIR "data/ser/custom")
make_sample(DIR "data/serialization")
make_sample(DIR "ecs/events")
make_sample(DIR "ecs/general")
Expand Down
5 changes: 5 additions & 0 deletions core/samples/data/page.md
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
107 changes: 107 additions & 0 deletions core/samples/data/ser/custom/main.cpp
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:
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 (const 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]
55 changes: 55 additions & 0 deletions core/samples/data/ser/custom/page.md
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
5 changes: 5 additions & 0 deletions core/samples/data/ser/page.md
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
1 change: 1 addition & 0 deletions docs/pages/3_examples/1_core/main.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ The following examples have fully documented tutorials:

- @subpage examples-core-logging - @copybrief examples-core-logging
- @subpage examples-core-reflection - @copybrief examples-core-reflection
- @subpage examples-core-data - @copybrief examples-core-data

0 comments on commit 1d995ee

Please sign in to comment.