Tutorial#
This is the AddressBook sample from tests/addressbook.capnp, the same
schema as Cap’n C++. The runnable form is
tests/example-test.cpp (Examples.RoundTripPerson).
Generate C#
From a source checkout, after meson compile -C build:
$ capnp compile -Icompiler -o./build/capnpc-c tests/addressbook.capnp
That writes addressbook.capnp.c / .h next to the schema. Generated
headers #include "c.capnp.h". Link lib/capn.c, lib/capn-malloc.c,
lib/capn-stream.c.
Schema#
using C = import "/c.capnp";
$C.fieldgetset;
struct Person {
id @0 :UInt32;
name @1 :Text;
email @2 :Text;
phones @3 :List(PhoneNumber);
employment :union {
unemployed @4 :Void;
employer @5 :Text;
school @6 :Text;
selfEmployed @7 :Void;
}
}
struct AddressBook {
people @0 :List(Person);
}
Write#
Zero-init optional pointer fields. Call capn_set_root after
write_* or the framed bytes are a legal empty message.
static capn_text txt(const char *s) {
return (capn_text){.len = (int)strlen(s), .str = s, .seg = NULL};
}
struct capn c;
capn_init_malloc(&c);
struct capn_segment *cs = capn_root(&c).seg;
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");
p.phones = new_Person_PhoneNumber_list(cs, 2);
struct Person_PhoneNumber pn0 = {
.number = txt("123"), .type = Person_PhoneNumber_Type_work,
};
set_Person_PhoneNumber(&pn0, p.phones, 0);
Person_ptr pp = new_Person(cs);
write_Person(&p, pp);
capn_set_root(&c, pp.p);
uint8_t buf[4096];
ssize_t sz = capn_write_mem(&c, buf, sizeof buf, 0); /* unpacked */
capn_free(&c);
Packed: pass 1 as the last argument of capn_write_mem. Those bytes
memcmp official capnp convert binary:packed when the object order
matches schema order.
Read#
struct capn rc;
capn_init_mem(&rc, buf, sz, 0);
Person_ptr rroot;
rroot.p = capn_getp(capn_root(&rc), 0, 1);
struct Person rp;
read_Person(&rp, rroot);
/* rp.id == 17 */
/* rp.name.str / rp.name.len is "Firstname Lastname" */
/* Person_has_name(rroot) is 1; a wire-null Text has has_=0 and get_ "" */
struct Person_PhoneNumber rpn0;
get_Person_PhoneNumber(&rpn0, rp.phones, 0);
capn_free(&rc);
Canonical form#
struct capn canon;
capn_init_malloc(&canon);
if (capn_canonicalize(&c, &canon) == 0) {
/* one segment, no far pointers; empty struct B = -1 */
}
capn_free(&canon);
capn_canonicalize memcmp=s =capnp convert binary:canonical on the
AddressBook fixture. See wire for the layout rules.