Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/linux.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
strategy:
fail-fast: false
matrix:
format: ["JSON", "AVRO", "CAPNPROTO", "CBOR", "CEREAL", "FLEXBUFFERS", "MSGPACK", "PARQUET", "TOML", "UBJSON", "XML", "YAML", "benchmarks", "headers"]
format: ["JSON", "AVRO", "BOOST_SERIALIZATION", "CAPNPROTO", "CBOR", "CEREAL", "FLEXBUFFERS", "MSGPACK", "PARQUET", "TOML", "UBJSON", "XML", "YAML", "benchmarks", "headers"]
compiler: [llvm, gcc]
compiler-version: [11, 12, 13, 14, 16, 17, 18]
cxx: [20, 23]
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/windows.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
strategy:
fail-fast: false
matrix:
format: ["JSON", "AVRO", "CAPNPROTO", "CBOR", "CEREAL", "FLEXBUFFERS", "MSGPACK", "PARQUET", "TOML", "UBJSON", "XML", "YAML", "benchmarks"]
format: ["JSON", "AVRO", "BOOST_SERIALIZATION", "CAPNPROTO", "CBOR", "CEREAL", "FLEXBUFFERS", "MSGPACK", "PARQUET", "TOML", "UBJSON", "XML", "YAML", "benchmarks"]
name: "windows-msvc (${{ matrix.format }})"
concurrency:
group: "windows-${{ github.ref }}-${{ github.job }}-${{ matrix.format }}"
Expand Down Expand Up @@ -77,7 +77,7 @@ jobs:
strategy:
fail-fast: false
matrix:
format: ["JSON", "AVRO", "CAPNPROTO", "CBOR", "FLEXBUFFERS", "MSGPACK", "PARQUET", "TOML", "UBJSON", "XML", "YAML"]
format: ["JSON", "AVRO", "BOOST_SERIALIZATION", "CAPNPROTO", "CBOR", "FLEXBUFFERS", "MSGPACK", "PARQUET", "TOML", "UBJSON", "XML", "YAML"]
name: "windows-msvc-shared (${{ matrix.format }})"
runs-on: windows-latest
steps:
Expand Down
14 changes: 14 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ option(REFLECTCPP_XML "Enable XML support" ${REFLECTCPP_ALL_FORMATS})
option(REFLECTCPP_TOML "Enable TOML support" ${REFLECTCPP_ALL_FORMATS})
option(REFLECTCPP_UBJSON "Enable UBJSON support" ${REFLECTCPP_ALL_FORMATS})
option(REFLECTCPP_YAML "Enable YAML support" ${REFLECTCPP_ALL_FORMATS})
option(REFLECTCPP_BOOST_SERIALIZATION "Enable Boost.Serialization support" ${REFLECTCPP_ALL_FORMATS})

option(REFLECTCPP_BUILD_BENCHMARKS "Build benchmarks" OFF)
option(REFLECTCPP_BUILD_TESTS "Build tests" OFF)
Expand Down Expand Up @@ -57,6 +58,7 @@ if(REFLECTCPP_BUILD_BENCHMARKS)
set(REFLECTCPP_TOML ON CACHE BOOL "" FORCE)
set(REFLECTCPP_UBJSON ON CACHE BOOL "" FORCE)
set(REFLECTCPP_YAML ON CACHE BOOL "" FORCE)
set(REFLECTCPP_BOOST_SERIALIZATION ON CACHE BOOL "" FORCE)
endif()

if (
Expand All @@ -65,6 +67,7 @@ if (
REFLECTCPP_CHECK_HEADERS OR
(REFLECTCPP_JSON AND NOT REFLECTCPP_USE_BUNDLED_DEPENDENCIES) OR
REFLECTCPP_AVRO OR
REFLECTCPP_BOOST_SERIALIZATION OR
REFLECTCPP_BSON OR
REFLECTCPP_CAPNPROTO OR
REFLECTCPP_CBOR OR
Expand Down Expand Up @@ -95,6 +98,10 @@ if (REFLECTCPP_USE_VCPKG)
list(APPEND VCPKG_MANIFEST_FEATURES "avro")
endif()

if (REFLECTCPP_BOOST_SERIALIZATION OR REFLECTCPP_CHECK_HEADERS)
list(APPEND VCPKG_MANIFEST_FEATURES "boost-serialization")
endif()

if (REFLECTCPP_BSON OR REFLECTCPP_CHECK_HEADERS)
list(APPEND VCPKG_MANIFEST_FEATURES "bson")
endif()
Expand Down Expand Up @@ -424,6 +431,13 @@ if (REFLECTCPP_YAML OR REFLECTCPP_CHECK_HEADERS)
target_link_libraries(reflectcpp PUBLIC yaml-cpp::yaml-cpp)
endif ()

if (REFLECTCPP_BOOST_SERIALIZATION OR REFLECTCPP_CHECK_HEADERS)
if (NOT TARGET Boost::serialization)
find_package(Boost REQUIRED COMPONENTS serialization)
endif ()
target_link_libraries(reflectcpp PUBLIC Boost::serialization)
endif ()

set_target_properties(reflectcpp PROPERTIES LINKER_LANGUAGE CXX)
target_sources(reflectcpp PRIVATE ${REFLECT_CPP_SOURCES})
target_precompile_headers(reflectcpp PRIVATE [["rfl.hpp"]] <iostream> <string> <functional>)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ The following table lists the serialization formats currently supported by refle
|--------------|------------------------------------------------------|--------------|------------| -----------------------------------------------------|
| JSON | [yyjson](https://github.com/ibireme/yyjson) | >= 0.8.0 | MIT | out-of-the-box support, included in this repository |
| Avro | [avro-c](https://avro.apache.org/docs/1.11.1/api/c/) | >= 1.11.3 | Apache 2.0 | Schemaful binary format |
| Boost.Serialization | [Boost.Serialization](https://www.boost.org/doc/libs/release/libs/serialization/) | >= 1.74.0 | BSL 1.0 | Streaming binary format with archive interop |
| BSON | [libbson](https://github.com/mongodb/mongo-c-driver) | >= 1.25.1 | Apache 2.0 | JSON-like binary format |
| Cap'n Proto | [capnproto](https://capnproto.org) | >= 1.0.2 | MIT | Schemaful binary format |
| CBOR | [jsoncons](https://github.com/danielaparker/jsoncons)| >= 0.176.0 | BSL 1.0 | JSON-like binary format |
Expand Down
14 changes: 13 additions & 1 deletion benchmarks/all/canada_read.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <benchmark/benchmark.h>

#include <rfl/avro.hpp>
#include <rfl/boost_serialization.hpp>
#include <rfl/bson.hpp>
#include <rfl/capnproto.hpp>
#include <rfl/cbor.hpp>
Expand Down Expand Up @@ -69,6 +70,18 @@ static void BM_canada_read_reflect_cpp_bson(benchmark::State &state) {
}
BENCHMARK(BM_canada_read_reflect_cpp_bson);

static void BM_canada_read_reflect_cpp_boost_serialization(
benchmark::State &state) {
const auto data = rfl::boost_serialization::write(load_data());
for (auto _ : state) {
const auto res = rfl::boost_serialization::read<FeatureCollection>(data);
if (!res) {
std::cout << res.error().what() << std::endl;
}
}
}
BENCHMARK(BM_canada_read_reflect_cpp_boost_serialization);

static void BM_canada_read_reflect_cpp_capnproto(benchmark::State &state) {
const auto schema = rfl::capnproto::to_schema<FeatureCollection>();
const auto data = rfl::capnproto::write(load_data(), schema);
Expand Down Expand Up @@ -237,4 +250,3 @@ BENCHMARK(BM_canada_read_reflect_cpp_yaml);
// ----------------------------------------------------------------------------

} // namespace canada_read

14 changes: 13 additions & 1 deletion benchmarks/all/canada_write.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <benchmark/benchmark.h>

#include <rfl/avro.hpp>
#include <rfl/boost_serialization.hpp>
#include <rfl/bson.hpp>
#include <rfl/capnproto.hpp>
#include <rfl/cbor.hpp>
Expand Down Expand Up @@ -69,6 +70,18 @@ static void BM_canada_write_reflect_cpp_bson(benchmark::State &state) {
}
BENCHMARK(BM_canada_write_reflect_cpp_bson);

static void BM_canada_write_reflect_cpp_boost_serialization(
benchmark::State &state) {
const auto data = load_data();
for (auto _ : state) {
const auto output = rfl::boost_serialization::write(data);
if (output.size() == 0) {
std::cout << "No output" << std::endl;
}
}
}
BENCHMARK(BM_canada_write_reflect_cpp_boost_serialization);

static void BM_canada_write_reflect_cpp_capnproto(benchmark::State &state) {
const auto schema = rfl::capnproto::to_schema<FeatureCollection>();
const auto data = load_data();
Expand Down Expand Up @@ -221,4 +234,3 @@ BENCHMARK(BM_canada_write_reflect_cpp_yaml);
// ----------------------------------------------------------------------------

} // namespace canada_write

14 changes: 13 additions & 1 deletion benchmarks/all/licenses_read.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <optional>
#include <rfl/avro.hpp>
#include <rfl/boost_serialization.hpp>
#include <rfl/bson.hpp>
#include <rfl/capnproto.hpp>
#include <rfl/cbor.hpp>
Expand Down Expand Up @@ -86,6 +87,18 @@ static void BM_licenses_read_reflect_cpp_bson(benchmark::State &state) {
}
BENCHMARK(BM_licenses_read_reflect_cpp_bson);

static void BM_licenses_read_reflect_cpp_boost_serialization(
benchmark::State &state) {
const auto data = rfl::boost_serialization::write(load_data());
for (auto _ : state) {
const auto res = rfl::boost_serialization::read<Licenses>(data);
if (!res) {
std::cout << res.error().what() << std::endl;
}
}
}
BENCHMARK(BM_licenses_read_reflect_cpp_boost_serialization);

static void BM_licenses_read_reflect_cpp_capnproto(benchmark::State &state) {
const auto schema = rfl::capnproto::to_schema<Licenses>();
const auto data = rfl::capnproto::write(load_data(), schema);
Expand Down Expand Up @@ -260,4 +273,3 @@ BENCHMARK(BM_licenses_read_reflect_cpp_yaml);
// ----------------------------------------------------------------------------

} // namespace licenses_read

14 changes: 13 additions & 1 deletion benchmarks/all/licenses_write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <optional>
#include <rfl/avro.hpp>
#include <rfl/boost_serialization.hpp>
#include <rfl/bson.hpp>
#include <rfl/capnproto.hpp>
#include <rfl/cbor.hpp>
Expand Down Expand Up @@ -86,6 +87,18 @@ static void BM_licenses_write_reflect_cpp_bson(benchmark::State &state) {
}
BENCHMARK(BM_licenses_write_reflect_cpp_bson);

static void BM_licenses_write_reflect_cpp_boost_serialization(
benchmark::State &state) {
const auto data = load_data();
for (auto _ : state) {
const auto output = rfl::boost_serialization::write(data);
if (output.size() == 0) {
std::cout << "No output" << std::endl;
}
}
}
BENCHMARK(BM_licenses_write_reflect_cpp_boost_serialization);

static void BM_licenses_write_reflect_cpp_capnproto(benchmark::State &state) {
const auto schema = rfl::capnproto::to_schema<Licenses>();
const auto data = load_data();
Expand Down Expand Up @@ -260,4 +273,3 @@ BENCHMARK(BM_licenses_write_reflect_cpp_yaml);
// ----------------------------------------------------------------------------

} // namespace licenses_write

14 changes: 13 additions & 1 deletion benchmarks/all/person_read.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <benchmark/benchmark.h>

#include <rfl/avro.hpp>
#include <rfl/boost_serialization.hpp>
#include <rfl/bson.hpp>
#include <rfl/capnproto.hpp>
#include <rfl/cbor.hpp>
Expand Down Expand Up @@ -64,6 +65,18 @@ static void BM_person_read_reflect_cpp_bson(benchmark::State &state) {
}
BENCHMARK(BM_person_read_reflect_cpp_bson);

static void BM_person_read_reflect_cpp_boost_serialization(
benchmark::State &state) {
const auto data = rfl::boost_serialization::write(load_data());
for (auto _ : state) {
const auto res = rfl::boost_serialization::read<Person>(data);
if (!res) {
std::cout << res.error().what() << std::endl;
}
}
}
BENCHMARK(BM_person_read_reflect_cpp_boost_serialization);

static void BM_person_read_reflect_cpp_capnproto(benchmark::State &state) {
const auto schema = rfl::capnproto::to_schema<Person>();
const auto data = rfl::capnproto::write(load_data(), schema);
Expand Down Expand Up @@ -238,4 +251,3 @@ BENCHMARK(BM_person_read_reflect_cpp_yaml);
// ----------------------------------------------------------------------------

} // namespace person_read

14 changes: 13 additions & 1 deletion benchmarks/all/person_write.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <benchmark/benchmark.h>

#include <rfl/avro.hpp>
#include <rfl/boost_serialization.hpp>
#include <rfl/bson.hpp>
#include <rfl/capnproto.hpp>
#include <rfl/cbor.hpp>
Expand Down Expand Up @@ -65,6 +66,18 @@ static void BM_person_write_reflect_cpp_bson(benchmark::State &state) {
}
BENCHMARK(BM_person_write_reflect_cpp_bson);

static void BM_person_write_reflect_cpp_boost_serialization(
benchmark::State &state) {
const auto data = load_data();
for (auto _ : state) {
const auto output = rfl::boost_serialization::write(data);
if (output.size() == 0) {
std::cout << "No output" << std::endl;
}
}
}
BENCHMARK(BM_person_write_reflect_cpp_boost_serialization);

static void BM_person_write_reflect_cpp_capnproto(benchmark::State &state) {
const auto schema = rfl::capnproto::to_schema<Person>();
const auto data = load_data();
Expand Down Expand Up @@ -239,4 +252,3 @@ BENCHMARK(BM_person_write_reflect_cpp_yaml);
// ----------------------------------------------------------------------------

} // namespace person_write

90 changes: 90 additions & 0 deletions docs/supported_formats/boost_serialization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Boost.Serialization

For Boost.Serialization support, you must also include the header `<rfl/boost_serialization.hpp>` and link to the [Boost.Serialization](https://www.boost.org/doc/libs/release/libs/serialization/) library.
Furthermore, when compiling reflect-cpp, you need to pass `-DREFLECTCPP_BOOST_SERIALIZATION=ON` to cmake. If you are using vcpkg, there
should be an appropriate feature that will abstract this away for you.

Unlike most other formats supported by reflect-cpp, which use document-tree based libraries, Boost.Serialization streams data sequentially through archive objects. reflect-cpp implements this as a schemaful binary format, similar to Avro and Cap'n Proto.

## Reading and writing

Suppose you have a struct like this:

```cpp
struct Person {
std::string first_name;
std::string last_name;
rfl::Timestamp<"%Y-%m-%d"> birthday;
std::vector<Person> children;
};
```

A `Person` can be serialized like this:

```cpp
const auto person = Person{...};
const std::vector<char> bytes = rfl::boost_serialization::write(person);
```

You can parse bytes like this:

```cpp
const rfl::Result<Person> result = rfl::boost_serialization::read<Person>(bytes);
```

## Loading and saving

You can also load and save to disc using a very similar syntax:

```cpp
const rfl::Result<Person> result = rfl::boost_serialization::load<Person>("/path/to/file.bin");

const auto person = Person{...};
rfl::boost_serialization::save("/path/to/file.bin", person);
```

## Reading from and writing into streams

You can also read from and write into any `std::istream` and `std::ostream` respectively.

```cpp
const rfl::Result<Person> result = rfl::boost_serialization::read<Person>(my_istream);

const auto person = Person{...};
rfl::boost_serialization::write(person, my_ostream);
```

## Archive interop

One of the key features of the Boost.Serialization backend is that you can use it with existing Boost archives directly. This allows reflect-cpp types to participate in larger Boost serialization workflows.

```cpp
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <rfl/boost_serialization.hpp>

// Writing into an existing Boost archive
boost::archive::binary_oarchive oa(my_ostream);
rfl::boost_serialization::write(oa, person);

// Reading from an existing Boost archive
boost::archive::binary_iarchive ia(my_istream);
const auto result = rfl::boost_serialization::read_from_archive<
Person, boost::archive::binary_iarchive,
boost::archive::binary_oarchive>(ia);
```

This also works with text archives:

```cpp
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

boost::archive::text_oarchive oa(my_ostream);
rfl::boost_serialization::write(oa, person);

boost::archive::text_iarchive ia(my_istream);
const auto result = rfl::boost_serialization::read_from_archive<
Person, boost::archive::text_iarchive,
boost::archive::text_oarchive>(ia);
```
13 changes: 13 additions & 0 deletions include/rfl/boost_serialization.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef RFL_BOOST_SERIALIZATION_HPP_
#define RFL_BOOST_SERIALIZATION_HPP_

#include "../rfl.hpp"
#include "boost_serialization/Parser.hpp"
#include "boost_serialization/Reader.hpp"
#include "boost_serialization/Writer.hpp"
#include "boost_serialization/load.hpp"
#include "boost_serialization/read.hpp"
#include "boost_serialization/save.hpp"
#include "boost_serialization/write.hpp"

#endif
Loading
Loading