Project Awesome project awesome

libfyaml

A fancy 1.2 YAML and JSON parser/writer. [MIT]

Package 329 stars GitHub

libfyaml 1.0-alpha5

Autotools CI CMake CI License: MIT Language: C

libfyaml is a high-performance YAML 1.2 and JSON parser/emitter with zero-copy operation, full document and event APIs, and the two major 1.0 alpha features:

  • generics: a schema-light, sum-type value model for YAML/JSON data in C
  • reflection/meta-type: typed YAML <-> C serdes driven by C type metadata

The alpha release adds a clear progression:

  • use the core API when you need parser, emitter, event, or document-tree control
  • use generics when your problem is "work with values"
  • use reflection when your problem is "populate native C data structures"

Why 1.0-alpha5 matters

1.0.0-alpha5 is the build-and-correctness follow-up to the earlier 1.0.0-alpha releases.

It keeps the same overall 1.0 direction, but expands build/test coverage and hardens the new subsystems in the places that matter for early adopters:

  • new pcons build system support and CI coverage
  • address-sanitized CI builds via ENABLE_ASAN=1
  • generic and threading fixes around preduce seeding and steal-mode worker shutdown/join behavior
  • parser and emitter bug fixes with expanded regression coverage
  • reflection cleanup fixes and safer no-libclang stub handling

Generic runtime

The center of the generic API is fy_generic.

fy_generic is the sum-type value used to represent YAML and JSON data in C. It carries one runtime value of one type: null, bool, int, float, string, sequence, mapping, or YAML-specific wrappers.

It is a single pointer-sized word with inline storage for common small values, including 61-bit signed integers on 64-bit builds, short strings, and inline 32-bit floats.

The rest of the generic API is about working with fy_generic values:

  • creating fy_generic values from C literals or parsed input
  • reading typed values back out
  • transforming one fy_generic into another
  • controlling lifetime through stack-local values and builders

That gives C a Python-like data model:

  • scalars, sequences, and mappings as immutable tagged fy_generic values
  • construction via fy_value(), fy_sequence(), and fy_mapping()
  • parse/emit helpers for YAML and JSON
  • functional collection operations such as map, filter, and reduce

If you know Python dict / list workflows, serde_json::Value, tagged unions, or other sum-type/value-tree APIs, generics are the direct fit.

Reflection / meta-type

The reflection subsystem provides schema-driven typed serdes:

  • extract type metadata from annotated C headers
  • deserialize YAML directly into native C structs
  • emit native C structs back to YAML
  • inspect type and field metadata through the public reflection API
  • choose between direct libclang authoring or packed metadata blobs

Reflection is the typed layer for stable C data models.

Python binding

The Python binding in python-libfyaml/ is built on the generic runtime. It is a direct bridge into the C generics API:

  • Python FyGeneric lazy wrappers mirror C fy_generic values
  • the binding demonstrates dict/list/scalar usage over the same data model
  • users can move from Python prototypes to C without changing how they think about the data

See the binding reference at python-libfyaml/docs/API.md.

Which layer should I use?

Core API

Choose the core library when you need:

  • event-streaming parsing
  • YAML document tree access and mutation
  • path queries and document-building helpers
  • full control over emission details and original YAML structure

Generic API

Choose generics when you need:

  • Python-like data handling in C
  • a schema-less or schema-light value layer
  • transformations over YAML/JSON values
  • a common model shared with the Python binding

Reflection API

Choose reflection when you need:

  • direct YAML <-> C struct serdes
  • stable typed configuration objects
  • metadata-aware array/mapping handling
  • deployable packed schemas without runtime libclang dependency

Quick look

Generic literals in C

#include <libfyaml/libfyaml-generic.h>

fy_generic config = fy_mapping(
    "server", fy_mapping(
        "host", "localhost",
        "port", 8080,
        "tls",  true),
    "features", fy_sequence("http", "metrics", "admin"));

Generic parse and transform

fy_generic doc = fy_parse(
    "values: [1, 2, 3, 4]",
    FYOPPF_DISABLE_DIRECTORY | FYOPPF_INPUT_TYPE_STRING,
    NULL);

fy_generic values = fy_get(doc, "values", fy_invalid);
fy_generic first = fy_first(values);

Reflection-based typed parse

#include <libfyaml/libfyaml-reflection.h>

struct fy_reflection *rfl = fy_reflection_from_c_file_with_cflags(
    "schema.h", "", false, true, NULL);

struct fy_type_context_cfg cfg = {
    .rfl = rfl,
    .entry_type = "struct app_config",
};
struct fy_type_context *ctx = fy_type_context_create(&cfg);

Documentation roadmap

Start with these pages:

Reference pages:

Examples

The refreshed examples directory now covers the new alpha workflows:

  • generic literals and Python-like object construction
  • generic parse/transform/reduce flows
  • generic lambda examples with captured local variables
  • generic serial and parallel lambda-based filter/map/reduce flows with an explicit thread pool and configurable workload size
  • schema-sensitive generic round-trips
  • a Python-binding-to-C adoption bridge
  • reflection from libclang-processed headers
  • reflection export to packed blobs and runtime load from packed metadata

See examples/README.md for the full list.

Existing strengths still apply

libfyaml also remains:

  • a full YAML 1.2 and JSON parser/emitter
  • zero-copy in core parsing paths
  • free of artificial key/document size limits
  • strong on diagnostics and document manipulation
  • fully MIT licensed

Installation

Using CMake

find_package(libfyaml 1.0 REQUIRED)
target_link_libraries(your_app PRIVATE libfyaml::libfyaml)

If the installed package was built with libclang support, the CMake package also exports libfyaml_HAS_LIBCLANG.

Using pkg-config

pkg-config --cflags libfyaml
pkg-config --libs libfyaml

Building from source

Using CMake:

mkdir build && cd build
cmake ..
cmake --build .
ctest --progress -j"$(nproc)"

Using Autotools:

./bootstrap.sh
./configure
make
make check

Optional dependencies

  • llvm-dev libclang-dev: author reflection metadata directly from C headers
  • no runtime libclang is required when using packed reflection blobs

Documentation builds

Sphinx documentation targets require the Python documentation toolchain:

  • sphinx
  • sphinx_rtd_theme
  • sphinx-markdown-builder
  • linuxdoc

PDF documentation also requires a LaTeX toolchain with:

  • latexmk
  • pdflatex
  • xcolor.sty
  • wrapfig.sty

On Debian/Ubuntu, the practical package set is:

python3 -m pip install sphinx sphinx_rtd_theme sphinx-markdown-builder linuxdoc
sudo apt-get install latexmk tex-gyre texlive-fonts-recommended texlive-latex-base texlive-latex-recommended texlive-latex-extra

Then build the docs with:

cmake --build build --target doc-html
cmake --build build --target doc-latexpdf

Python binding

The binding lives in python-libfyaml/. Run its tests with:

cd python-libfyaml
python3 -m pytest tests/

The binding is part of the alpha release story and shows the generic runtime's data model in regular use. v1.0.0-alpha3 improved the Windows story for the binding, v1.0.0-alpha4 repaired the wheel and sdist packaging flow, and v1.0.0-alpha5 broadens build and CI coverage around the project as a whole.

License

libfyaml is fully MIT licensed.

Back to C/C++