---
title: "Rcereal: cereal headers for R and C++ serialization"
output: rmarkdown::html_vignette
author: Wush Wu
vignette: >
%\VignetteIndexEntry{introduction-to-rcereal}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
This package provides R with access to [__cereal__][cereal_gh] header files.
__cereal__ is a header-only C++11 serialization library. __cereal__ takes
arbitrary data types and reversibly turns them into different representations,
such as compact binary encodings, XML, or JSON.
For more information, please visit the official website of the __cereal__
project: .
[cereal_gh]: https://uscilab.github.io/cereal/
The headers in this package can be used via:
- the `LinkingTo:` field in the DESCRIPTION of an R package;
- the `[[cpp11::linking_to("Rcereal")]]` attribute and `cpp11::source` from
the [cpp11][cpp11_url] package, or;
- the `[[Rcpp::depends(Rcereal)]]` [Rcpp attribute][rcpp_attributes_vignette].
[cpp11_url]: https://cpp11.r-lib.org
[rcpp_attributes_vignette]: https://cran.r-project.org/package=Rcpp/vignettes/Rcpp-attributes.pdf
See the official __cereal__ [Quick Start][cereal_quick_start_doc] guide for
further details about using __cereal__ in C++11.
[cereal_quick_start_doc]: https://uscilab.github.io/cereal/quickstart.html
## Usage
### Using cpp11
The following example shows how to use __Rcereal__ alongside [cpp11][cpp11_url]
to serialize and deserialize a user-defined `struct` using raw vectors:
```cpp
// path/to/example.cpp
#include
#include
#include
struct MyClass
{
int x, y, z;
// This method lets cereal know which data members to serialize
template
void serialize(Archive & archive)
{
archive( x, y, z ); // serialize things by passing them to the archive
}
};
[[cpp11::linking_to("Rcereal")]]
[[cpp11::register]]
cpp11::raws serialize_myclass(int x = 1, int y = 2, int z = 3) {
MyClass my_instance { x, y, z };
std::stringstream ss;
{
cereal::BinaryOutputArchive oarchive(ss); // Create an output archive
oarchive(my_instance);
}
ss.seekg(0, ss.end);
cpp11::writable::raws result(ss.tellg());
ss.seekg(0, ss.beg);
std::copy(std::istreambuf_iterator{ss},
std::istreambuf_iterator(),
result.begin());
return result;
}
[[cpp11::register]]
void deserialize_myclass(cpp11::raws src) {
std::stringstream ss;
std::copy(src.cbegin(), src.cend(), std::ostream_iterator(ss));
MyClass my_instance;
{
cereal::BinaryInputArchive iarchive(ss); // Read from input archive
iarchive(my_instance);
}
Rprintf("%i,%i,%i\n", my_instance.x, my_instance.y, my_instance.z);
}
```
Then, provided C++11 is enabled by default (see [this tidyverse
post 03/2023][tidyverse_post_03_2023]), in R:
```r
cpp11::cpp_source(file='path/to/example.cpp')
raw_vector <- serialize_myclass(1, 2, 4)
deserialize_myclass(raw_vector)
```
[tidyverse_post_03_2023]: https://www.tidyverse.org/blog/2023/03/cran-checks-compiled-code/
### Using Rcpp
The following example shows how to use __Rcereal__ alongside [Rcpp][rcpp_cran]
to serialize and deserialize a user-defined `struct` using raw vectors:
```cpp
// path/to/example.cpp
//[[Rcpp::depends(Rcereal)]]
#include
#include
#include
struct MyClass
{
/* same as cpp11 example above */
};
using namespace Rcpp;
//[[Rcpp::export]]
RawVector serialize_myclass(int x = 1, int y = 2, int z = 3) {
MyClass my_instance { x, y, z};
std::stringstream ss;
{
cereal::BinaryOutputArchive oarchive(ss); // Create an output archive
oarchive(my_instance);
}
ss.seekg(0, ss.end);
RawVector result(ss.tellg());
ss.seekg(0, ss.beg);
ss.read(reinterpret_cast(&retval[0]), result.size());
return result;
}
//[[Rcpp::export]]
void deserialize_myclass(RawVector src) {
std::stringstream ss;
ss.write(reinterpret_cast(&src[0]), src.size());
ss.seekg(0, ss.beg);
MyClass my_instance;
{
cereal::BinaryInputArchive iarchive(ss);
iarchive(my_instance);
}
Rcout << my_instance.x << "," << my_instance.y << "," << my_instance.z << std::endl;
}
```
Then in R (provided C++11 is enabled):
```r
Rcpp::sourceCpp("path/to/example.cpp")
raw_vector <- serialize_myclass(1, 2, 4)
deserialize_myclass(raw_vector)
```
[rcpp_cran]: https://cran.r-project.org/package=Rcpp
## Troubleshooting
C++11 may not be enabled by default for some compilers, if not; ensure that
`PKG_CXXFLAGS` contains `-std=c++11`, e.g. if you use `pkgbuild::compile_dll()`
to build a package (similarly for `devtools::build`):
```r
withr::with_makevars(c("PKG_CXXFLAGS"="std=c++11"),
pkgbuild::compile_dll(),
assignment="+=")
```
If the compiler reports missing header files, try `Rcereal::update_version()` to
update the content of __cereal__ from GitHub. Check that a directory named
`cereal` is in the folder `system.file("include", package = "Rcereal")`.