is a C++ 23 serialization library. It provides a simple to use interfaces, supports containers, trivial types and aggregates[1] out of the box and provides a simple interface to create custom serialization methods.
[1] Aggregate types are supported via fox::reflexpr reflections library.
Library uses operator|
to chain together objects to serialize and deserialize.
Builtin supported types are:
- Trivailly copyable types
- range-to compatible types
- tuple-like types
std::optional
#include <fox/serialize.hpp>
namespace sr = fox::serialize;
std::string a = "Capybara";
int b = 123;
sr::bit_writer writer;
writer | a | b;
sr::bit_reader reader(std::from_range, writer.data());
std::string a_out;
int b_out;
reader | a_out | b_out;
Aggregate types are supported through fox::reflexpr reflections library if available. Library can be disabled by setting FOX_SERIALIZE_INCLUDE_REFLEXPR
CMAKE flag to OFF.
#include <fox/serialize.hpp>
namespace sr = fox::serialize;
struct aggregate
{
std::string a;
int b;
};
aggregate a{ "Fox, 123 };
sr::bit_writer writer;
writer | a;
sr::bit_reader reader(std::from_range, writer.data());
aggregate a_out;
reader | a_out;
It's possible to provide custom serialization method for a given type.
#include <fox/serialize.hpp>
template<>
struct fox::serialize::serialize_traits<std::unique_ptr<int>>
{
static void serialize(fox::serialize::bit_writer& writer, const std::unique_ptr<int>& ptr)
{
writer | (static_cast<bool>(ptr));
if (ptr)
writer | (*ptr);
}
static void deserialize(fox::serialize::bit_reader& reader, std::unique_ptr<int>& ptr)
{
bool b = fox::serialize::deserialize<bool>(reader);
if(b)
{
ptr = std::make_unique<int>(fox::serialize::deserialize<int>(reader));
}
else
{
ptr.reset();
}
}
};
void sample_custom_0()
{
fox::serialize::bit_writer writer;
auto a = std::make_unique<int>(2);
writer | a;
fox::serialize::bit_reader reader(std::from_range, writer.data());
std::unique_ptr<int> b;
reader | b;
}
#include <fox/serialize.hpp>
class custom_type_1
{
friend void sample_custom_1();
std::string v0_;
int v1_;
public:
custom_type_1() = default;
custom_type_1(const std::string& v0, int v1)
: v0_(v0), v1_(v1) {}
void serialize(fox::serialize::bit_writer& writer) const
{
writer | v0_ | v1_;
}
void deserialize(fox::serialize::bit_reader& reader)
{
reader | v0_ | v1_;
}
};
void sample_custom_1()
{
fox::serialize::bit_writer writer;
custom_type_1 a = custom_type_1("Fox", 1);
writer | a;
fox::serialize::bit_reader reader(std::from_range, writer.data());
custom_type_1 b;
reader | b;
}
#include <fox/serialize.hpp>
class custom_type_2
{
friend void sample_custom_2();
std::string v0_;
int v1_;
public:
custom_type_2() = default;
custom_type_2(const std::string& v0, int v1)
: v0_(v0), v1_(v1) {}
static void serialize(fox::serialize::bit_writer& writer, const custom_type_2& obj)
{
writer | obj.v0_ | obj.v1_;
}
static void deserialize(fox::serialize::bit_reader& reader, custom_type_2& obj)
{
reader | obj.v0_ | obj.v1_;
}
};
void sample_custom_2()
{
fox::serialize::bit_writer writer;
custom_type_2 a = custom_type_2("Fox", 1);
writer | a;
fox::serialize::bit_reader reader(std::from_range, writer.data());
custom_type_2 b;
reader | b;
}
#include <fox/serialize.hpp>
#include <iostream>
#include <format>
#include <string>
class custom_type_3
{
friend void sample_custom_3();
std::string v0_;
int v1_;
public:
custom_type_3() = default;
custom_type_3(fox::serialize::from_bit_reader_t, fox::serialize::bit_reader& reader)
{
reader | v0_ | v1_;
}
custom_type_3(const std::string& v0, int v1)
: v0_(v0), v1_(v1) {}
static void serialize(fox::serialize::bit_writer& writer, const custom_type_3& obj)
{
writer | obj.v0_ | obj.v1_;
}
};
void sample_custom_3()
{
fox::serialize::bit_writer writer;
custom_type_3 a = custom_type_3("Fox", 1);
writer | a;
fox::serialize::bit_reader reader(std::from_range, writer.data());
custom_type_3 b;
reader | b;
}
#include <fox/serialize.hpp>
class custom_type_4
{
friend void sample_custom_4();
std::string v0_;
int v1_;
public:
custom_type_4() = default;
custom_type_4(const std::string& v0, int v1)
: v0_(v0), v1_(v1) {}
// This can be a hand written trait like in a sample samples/sample_custom_0.cpp
using serialize_trait = fox::serialize::serialize_from_members<custom_type_4, &custom_type_4::v0_, &custom_type_4::v1_>;
};
void sample_custom_4()
{
fox::serialize::bit_writer writer;
custom_type_4 a = custom_type_4("Fox", 1);
writer | a;
fox::serialize::bit_reader reader(std::from_range, writer.data());
custom_type_4 b;
reader | b;
}
struct custom_struct
{
std::string a;
int b;
};
template<>
struct fox::serialize::serialize_traits<custom_struct> :
fox::serialize::serialize_from_members<custom_struct, &custom_struct::a, &custom_struct::b>
{
};
This is a C++ 23 library. All compilers that support std::ranges::to
and std::format
should support this library. Following compilers are known to work:
- Microsoft Visual C++ 2022 (msvc) / Build Tools 19.38.33134 (and possibly later)
- Microsoft Visual C++ 2022 (clang) 16.0.5 (and possibly later)
serialize.hpp
is single header library. It requires C++ 23. If you want to enable aggreage serialization, install (single header library) fox::reflexpr
and define FOX_SERIALIZE_HAS_REFLEXPR
macro before including fox/serialize.hpp
.
include(FetchContent)
# One could disable fox::reflexpr by setting FOX_SERIALIZE_INCLUDE_REFLEXPR to OFF
# set(FOX_SERIALIZE_INCLUDE_REFLEXPR OFF)
FetchContent_Declare(fox_serialize GIT_REPOSITORY https://github.com/RedSkittleFox/serialize.git)
FetchContent_MakeAvailable(fox_serialize)
target_link_libraries(foo PRIVATE fox::serialize)
This library is licensed under the MIT License.