An open API service indexing awesome lists of open source software.

https://github.com/junkdog/pupene

A non-invasive, multi-format serialization library for C++17.
https://github.com/junkdog/pupene

introspection serialization

Last synced: about 1 year ago
JSON representation

A non-invasive, multi-format serialization library for C++17.

Awesome Lists containing this project

README

          

## pupene

A non-invasive, multi-format serialization library for C++17.

### Features or Caveats

This library was primarily conceived as a foundation for assisting with building
tooling for gamedev projects. The approach and naming conventions are borrowed
from Daniel Randle's [Pupping - a method for serializing data][article].

- Works with default constructible types.
- `pupene` relies on direct field access to read/write.
- Concise and simple:
- `pup()` - one serializer-agnostic read/write function per type.
- `Pupper` - serializer, binary and optional JSON support included.
- Serialization format can not be customized, this makes it non-ideal for
dealing with third-party formats.
- Zero dependencies, unless built with JSON support.
- Not limited to performing only pure serialization.
- Example using [imgui and pupene][pupene_imgui] to auto-generate editor UI:s at runtime.

[pupene_imgui]: https://github.com/junkdog/pupene_imgui
[article]: https://www.gamedev.net/articles/programming/general-and-gameplay-programming/pupping-a-method-for-serializing-data-r4485/

### Getting started

Add [this conan remote](https://bintray.com/junkdog/conan):

```bash
conan remote add junkdog https://api.bintray.com/conan/junkdog/conan
```

In your project's conanfile.txt/py:

```
[requires]
pupene/0.2.0@junkdog/stable
```

### Links

- Full API documentation, including this README: https://junkdog.github.io/pupene/index.html
- Github repository: https://github.com/junkdog/pupene
- Issues: https://github.com/junkdog/pupene/issues

### A brief introduction

At the core, `pupene` is built around serializers called _puppers_, and `pup`
functions - a combined read/write function per serializable type.

Include `` and/or `` (requires `-DPUPENE_BUILD_JSON=true`) to
access the appropriate puppers.

Refer to the [API docs](https://junkdog.github.io/pupene) for more detailed
documentation. The [tests][tests] may be of some interest too.

Namespace `pupene` is omitted from example code, in the interest of brevity.

[tests]: https://github.com/junkdog/pupene/tree/master/test

#### Pupper

`Pupper` is on the receiving end of `pup`; they only deal directly with values once
`pup` has flattened the object into a sequence of integer, decimal and string types.

Included Puppers, and related convenience functions:
- JsonReader: `from_json()`
- JsonWriter: `to_json()`
- BinaryReader: `from_binary()`
- BinaryWriter: `to_binary()`
- DebugPupper: `to_debug()`

A `pup` function must exist for each serializable type.

#### pup

An object is serializable when there's a matching `pup` function; these describe
the structure of the type by enumerating its fields. All `pup` functions must
be defined in the `pupene::fns` namespace.

A limited number of fundamental types are built-in:
- Integer and decimal types
- `std::string`
- STL containers, such as `std::vector` and `std::map`

`pup()` for a type `FooBar` has the following signature:

```cpp
template
void pup(Pupper

& p, // Pupper-agnostic - works with all
FooBar& value, // must be reference
const Meta& meta); // name and Meta::Type
```

**N.B.** For function resolution to work, `pup` functions must be declared in
a file which does not `#include` any puppers, implicitly or explicitly.

#### Example

You have some models:

```cpp
struct Color {
float r, g, b, a;
};

struct FontReference {
std::string path;
Color inner;
Color outer;
};
```

To make the types eligible, each requires its own pup function in the namespace `pupene:fns`.

```cpp
#include

namespace pupene::fns { // required namespace

template
void pup(Pupper

& p, // the serializer in use
Color& color, // always as non-const references
const Meta& meta) { // metadata for color

// idiomatic boilerplate
pup_object(p, color, meta, [&color](auto&& fpup) {
fpup(color.r, "r"); // enumerate each field
fpup(color.g, "g");
fpup(color.b, "b");
fpup(color.a, "a");
});
}

template
void pup(Pupper

& p,
FontReference& ref,
const Meta& meta) {

pup_object(p, ref, meta, [&ref](auto&& fpup) {
fpup(ref.path, "path");
fpup(ref.inner, "inner"); // dispatches to pup for Color
fpup(ref.outer, "outer");
});
}
}
```

Once the necessary pup:s are implemented, serialization between different
format becomes possible e.g.:

```cpp
// load binary from input stream
std::istream& in = ...;
Color color = from_binary(in);

// save to json (assumes built with PUPENE_BUILD_JSON=true)
std::string raw_json = to_json(color);
```

`Color` and `FontReference` can now also be combined with some STL containers:

```cpp
std::unordered_map colored_fonts = {
{colorA, small}, {colorB, medium}, {colorC, large}
};

// complex keys - such as Color - are ok
std::string raw_json = to_json(colored_fonts);

// (this doesn't require any user-supplied pup:s)
std::vector numbers = {0, 1, 6, -2, 4, 5, 7};
to_binary(numbers, std::cout);
```

### Building

Unless already added, The `conan-community` remote has to be added for
the `Boost` test dependency to work:

```bash
conan remote add conan-community https://api.bintray.com/conan/conan-community/conan
```

#### Using Conan

First-time setup:

```bash
conan install . --build missing --install-folder _builds
```

Build project:

```bash
conan build . --build-folder _builds
```

#### Using CMake:

Once conan has built the project for the first time, CMake should work as
expected.

Build project:

```bash
cmake --build _builds --target install -- -j 8
```

Tests are run with:

```bash
cmake --build _build --target test
```
... or run the tests with valgrind/memcheck:

```bash
cmake --build _build --target valgrind
```

#### CLion/CMake

To play nice with CLion, manually specify the compiler using *CMake Options*
under `Settings > Build, Execution, Deployment > CMake`, e.g.:

```bash
-DCMAKE_CXX_COMPILER=/usr/bin/clang++-5.0
```

### Overarching TODO
- Types currently require a default constructor to be eligble for `pup`.
- Benchmarking and profiling remain.

### Alternative libraries:
- [MetaStuff](https://github.com/eliasdaler/MetaStuff): C++14, similar but expanded features compared to `pupene`
- [cereal](https://github.com/USCiLab/cereal): C++11, only binary serialization(?)