A small library for dealing with JSON.
  • C++ 98.7%
  • CMake 1.3%
Find a file
TennesseeTrash aa979ac9a9
All checks were successful
laminator
Typo and version bump
2026-07-08 07:45:26 +02:00
LibJSON Typo and version bump 2026-07-08 07:45:26 +02:00
Tests Bughunting 2026-07-08 07:36:22 +02:00
.gitignore Initial lexer impl 2026-06-12 18:25:16 +02:00
CMakeLists.txt Typo and version bump 2026-07-08 07:45:26 +02:00
LICENSE Add LICENSE and README.md 2026-06-21 22:16:44 +02:00
README.md Typo and version bump 2026-07-08 07:45:26 +02:00

LibJSON

A basic two-way JSON implementation for C++. Mostly compatible with RFC 8259.

Usage

The preferred way of using this library is pulling it in via CMake's FetchContent.

include(FetchContent)

FetchContent_Declare(
    libjson
    GIT_REPOSITORY https://code.3011.io/TennesseeTrash/LibJSON.git
    GIT_TAG        v0.0.2
)

FetchContent_MakeAvailable(
    libjson
)

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 is known to work.

Documentation

For encoding your data to JSON, include <JSON/Printer.hpp>, and prepare a std::string. Encoding is as simple as creating an instance of a Printer on top of a string. Most standard containers should work out of the box, but keep in mind the library intentionally supports only double as a numeric type.

#include <JSON/Printer.hpp>

int main()
{
    std::string buffer;

    JSON::Printer printer(buffer);

    printer.Print("Hello!");
}

The printer can be extended to consume custom types via ADL-provided PrintHook functions.

#include <JSON/Printer.hpp>

struct Person
{
    std::string              Name;
    double                   Height;
    std::vector<std::string> Hobbies;
};

void PrintHook(JSON::Printer &printer, const Person &person)
{
    printer.PrintObject(
        "name",    person.Name,
        "height",  person.Height,
        "hobbies", person.Hobbies
    );
}

Once the PrintHook is provided, the type can be printed identically to the default supported types.

std::string buffer;
JSON::Printer printer(buffer);
Person john {
    .Name    = "John Doe",
    .Height  = 1.91,
    .Hobbies = { "Fishing", "Skiing", "Diving" },
};
printer.Print(john);

After Print is called, the buffer is filled with the appropriate value. The printer itself keeps minimal state, so it's possible to call Print multiple times on the same buffer. This can be useful when serializing something like JSONL, but keep in mind this produces malformed JSON by default.

Parsing is different from printing by default. The parser (implemented in <JSON/Parser.hpp>) uses custom parsing types to handle objects and arrays. This requires manually calling the decoder API in a pull-parser fashion to extract the data from raw JSON. This allows the library to stay allocation free (with caveats), while handling all the supported JSON types. However, for basic tasks this API is cumbersome, so the parser provides a unified Parse<T>() function, which behaves very similarly to its Print counterpart. By default, Parse<T>() cannot handle standard containers. To enable their support, include <JSON/ParserHooks.hpp>. This header includes support for std::string, std::vector, std::unordered_map, and std::tuple. Support for custom types can be added via an ADL-provided ParseHook, similar to its printer variant. To make writing the parser a bit more pleasant (including parsing objects with shuffled map items), the library provides a StructHelper.

The Parser does not check that it's at the end of the buffer once it's done parsing the current item. This done intentionally to enable symmetrical handling of JSONL and similar without changing the parser. To check whether the parser has consumed the whole input explicitly, use Done() after extracting the value.

#include <JSON/Parser.hpp>
#include <JSON/ParserHooks.hpp>
#include <JSON/Utility.hpp>

void ParseHook(JSON::Parser &parser, Person &person)
{
    constexpr JSON::StructHelper helper {
        JSON::StructMember { "name",    &Person::Name    },
        JSON::StructMember { "height",  &Person::Height  },
        JSON::StructMember { "hobbies", &Person::Hobbies },
    };
    helper.Parse(parser.AsValue(), person);
}

With this hook, the Person struct can now be parsed. Note that the parsed type must be default initializable. Similar to the printer, the parser can be used for parsing sequences of JSON values by calling the Parse<T>() function several times.

std::string buffer; // Assume we have filled this buffer with an encoded Person.
JSON::Parser parser(buffer);
auto person = parser.Parse<Person>();

Strings

When printing, the library escapes unsafe values (mostly control characters), but it does not escape UTF-8, that passes through the library without changes.

When parsing, the String parser helper lets you choose to either get the raw string value, with out unescaping by calling .Raw(). This returns a std::string_view, so it costs no allocations, or extra scans. Alternatively, the type also exposes an .Unescaped() member function, that unescapes everything into UTF-8, but returns a std::string. This costs an allocation, and an extra pass over the buffer. Note, however that it does not validate UTF-8.