c-capnproto#

Pure C runtime and capnpc-c for Cap’n Proto. Wire encode is byte-equivalent with official capnp 1.0.2 when objects are allocated in schema order.

Sibling runtimes: capnp-fortran and capnp-janet.

Warning

Failed pointer hops are still CAPN_NULL; check capn_ok. This is not C++ MessageReader throw-parity. See SECURITY.md.

Install (shortest path)#

$ git clone --recurse-submodules https://github.com/HaoZeke/c-capnproto.git
$ cd c-capnproto
$ meson setup build && meson compile -C build
$ meson test -C build

First message#

Schema is tests/addressbook.capnp (same shape as the C++ sample). Generate accessors, then write and read a Person:

$ capnp compile -Icompiler -oc:build tests/addressbook.capnp
#include "capnp_c.h"
#include "addressbook.capnp.h"

static capn_text txt(const char *s) {
  return (capn_text){.len = (int)strlen(s), .str = s, .seg = NULL};
}

uint8_t buf[4096];
struct capn c;
capn_init_malloc(&c);

struct Person p = {
  .id = 17,
  .name = txt("Firstname Lastname"),
  .email = txt("username@domain.com"),
};
p.employment_which = Person_employment_school;
p.employment.school = txt("of life");

Person_ptr pp = new_Person(capn_root(&c).seg);
write_Person(&p, pp);
capn_set_root(&c, pp.p);   /* required; otherwise the message is empty */
ssize_t sz = capn_write_mem(&c, buf, sizeof buf, 0);
capn_free(&c);

struct capn rc;
capn_init_mem(&rc, buf, sz, 0);
struct Person rp;
Person_ptr rp_ptr = {.p = capn_getp(capn_root(&rc), 0, 1)};
read_Person(&rp, rp_ptr);
/* rp.id == 17, rp.name.str == "Firstname Lastname" */
capn_free(&rc);

The full walk-through (phones list, union, packed, canonical) is the tutorial.

Documentation map#

Install

Meson (recommended), CMake, autotools, optional kernel module.

Install
Tutorial

AddressBook: generate, write, read, packed, canonicalize.

Tutorial
Usage

capnpc-c, capn_set_root, $C.fieldgetset, has_.

Usage
Wire

Schema-order encode, empty struct B=-1, packed 0xFF heuristic.

Wire format
Interop

Official capnp CLI memcmp, fortran goldens, Janet peer.

Interop