- C++ 99%
- CMake 1%
|
|
||
|---|---|---|
| LibCBOR | ||
| Tests | ||
| .gitignore | ||
| CMakeLists.txt | ||
| LICENSE | ||
| README.md | ||
LibCBOR
A basic two-way CBOR implementation for C++. Mostly compatible with RFC 8949, apart from
float16_t.
Usage
The preferred way of using this library is pulling it in via CMake's FetchContent.
include(FetchContent)
FetchContent_Declare(
libcbor
GIT_REPOSITORY https://code.3011.io/TennesseeTrash/LibCBOR.git
GIT_TAG v0.2.6
)
FetchContent_MakeAvailable(
libcbor
)
Afterwards, you can just link against the LibCBOR target, and include the library in your code.
target_link_libraries(${YOUR_PROJECT}
PRIVATE # Or PUBLIC if you want to expose the functionality to downstream targets
LibCBOR
)
If you'd rather not use CMake, the path is a bit more difficult, but it shouldn't be too problematic.
The library is written such that you just need to add the TUs in the Source directory to your
build, and add Include to your include paths. Note that this may change in the future.
Make sure to use a relatively recent toolchain, the library depends on some C++23 features. Clang 19 and GCC 14 are known to work.
Documentation
For encoding data to CBOR, include <CBOR/Encoder.hpp>, and prepare a buffer.
Encoding is as simple as instantiating an instance of an Encoder on top of a fixed or dynamic
buffer. Most standard containers should work out of the box, but for some less common types, please
include <CBOR/EncoderHooks.hpp> (currently only std::tuple).
#include <CBOR/Encoder.hpp>
int main()
{
std::array<std::uint8_t, 1024> buffer;
CBOR::Encoder enc(buffer);
enc.Encode("Hello!");
}
The encoder can be extended to consume custom types via ADL-provided EncodeHook functions.
#include <CBOR/Encoder.hpp>
struct Person
{
std::string Name;
std::uint64_t PhoneNumber;
std::vector<std::string> Hobbies;
double Height;
};
void EncodeHook(CBOR::Encoder &enc, const Person &person)
{
enc.EncodeMap(
"name", person.Name,
"phone_number", person.PhoneNumber,
"hobbies", person.Hobbies,
"height", person.Height
);
}
Once the EncodeHook is provided, the type can be encoded identically to default supported types.
std::vector<std::uint8_t> buffer;
CBOR::Encoder enc(buffer);
Person john {
.Name = "John Doe",
.PhoneNumber = 123'456'789,
.Hobbies = { "Fishing", "Skiing", "Diving", },
.Height = 1.91,
};
enc.Encode(john);
After Encode is called, the buffer is filled with the appropriate value. The encoder itself keeps
minimal state, so it's possible to call Encode multiple times on the same buffer. Note, however,
that this produces a CBOR Sequence instead of a single CBOR item.
Decoding is different from encoding by default. The decoder (implemented in <CBOR/Decoder.hpp>)
uses custom decoding types to handle maps and arrays. This requires manually calling the decoder
API in a pull-parser fashion to extract the data from the encoded CBOR buffer.
This allows the library to stay allocation free, while handling all the possible CBOR types
(including indefinite strings). However, for basic tasks this API is cumbersome,
so the decoder also provides a unified Decode<T>() function, which behaves
very similarly to its Encode counterpart. By default, Decode<T>() cannot handle standard
containers. To enable their support, include <CBOR/DecoderHooks.hpp>. This header includes
support for std::string, std::vector, std::tuple, std::map, and std::unordered_map.
Support for custom types can be added via an ADL-provided
DecodeHook, similar to its encoder variant. To make writing the decoder a bit more pleasant
(including decoding maps with shuffled map items), the library provides a StructHelper.
#include <CBOR/Decoder.hpp>
#include <CBOR/DecoderHooks.hpp>
#include <CBOR/Utility.hpp>
void DecodeHook(CBOR::Decoder &dec, Person &person)
{
constexpr CBOR::StructHelper helper {
CBOR::StructMember { "name", &Person::Name },
CBOR::StructMember { "phone_number", &Person::PhoneNumber },
CBOR::StructMember { "hobbies", &Person::Hobbies },
CBOR::StructMember { "height", &Person::Height },
};
helper.Decode(dec.AsItem(), person);
}
With this hook, the Person struct can now be decoded. Note that the decoded type must be default
initializable. Similar to the encoder, the decoder can be used for CBOR Sequences by simply calling
the Decode<T>() function multiple times.
std::array<std::uint8_t, 1024> buffer; // Assume we have filled this buffer with an encoded Person.
CBOR::Decoder dec(buffer);
auto person = dec.Decode<Person>();
The library supports some more niche functionality, such as nested CBOR encoding via CBOR::Binary,
tagged items, and printing a formatted view of an encoded buffer via CBOR::Print.
For examples of this, take a look at the tests.