diff --git a/.gitignore b/.gitignore index 76d9560..c3a9d9d 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,8 @@ test-driver *.log *.trs +tests/*.out + *.o *.a *.so diff --git a/Makefile.am b/Makefile.am index 8622c90..6fa4b95 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,8 +17,9 @@ pkgconfig_DATA = c-capnproto.pc EXTRA_DIST += compiler/c.capnp capnp_DATA = compiler/c.capnp - -AM_CPPFLAGS = -I${srcdir}/lib +AM_CPPFLAGS = \ + -I${srcdir}/compiler \ + -I${srcdir}/lib lib_LTLIBRARIES += libcapnp_c.la libcapnp_c_la_LDFLAGS = -version-info 0:0:0 @@ -42,25 +43,52 @@ noinst_HEADERS += \ lib/capnp_priv.h \ compiler/str.h \ compiler/schema.capnp.h \ - compiler/c++.capnp.h \ - compiler/test.capnp.h + compiler/c.capnp.h \ + compiler/c++.capnp.h +# Don't try to generate any *.capnp files. Otherwise make wants to compile them +# from *.capnp.c and fails. +%.capnp: ; + +# googletest GTEST_LDADD = gtest/googletest/lib/libgtest.la gtest/googletest/lib/libgtest.la: make -C gtest/googletest lib/libgtest.la GTEST_CPPFLAGS = -I${srcdir}/gtest/googletest/include DIST_SUBDIRS = gtest/googletest +# Tests check_PROGRAMS += \ capn-test capn_test_SOURCES = \ tests/capn-test.cpp \ tests/capn-stream-test.cpp \ + tests/example-test.cpp \ + tests/addressbook.capnp.c \ compiler/test.capnp.c \ compiler/schema-test.cpp \ compiler/schema.capnp.c +noinst_HEADERS += \ + compiler/test.capnp.h \ + tests/addressbook.capnp.h +EXTRA_DIST += \ + compiler/c.capnp \ + compiler/c++.capnp \ + compiler/schema.capnp \ + compiler/test.capnp \ + tests/addressbook.capnp capn_test_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_CPPFLAGS) capn_test_CXXFLAGS = -std=gnu++11 -pthread capn_test_LDADD = libcapnp_c.la $(GTEST_LDADD) capn_test_LDFLAGS = -pthread TESTS = capn-test + +CAPNP_SCHEMA_FILES := $(shell find . -type f -name \*.capnp) + +CAPNP ?= capnp +.PHONY: capnp-compile +capnp-compile: + $(CAPNP) compile \ + --output=./capnpc-c \ + -Icompiler \ + $(CAPNP_SCHEMA_FILES) diff --git a/README.md b/README.md index a9d9fa8..8b46dd2 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,87 @@ capnpc-c This is a C plugin for [Cap'n Proto](http://kentonv.github.io/capnproto), an efficient protocol for sharing data and capabilities. -This is only the plugin, to properly make use of it you need to download, build -and install capnpc and then build and install this project and then you can -utilize it as: +This is only the code generator plugin, to properly make use of it you +need to download, build and install capnpc and then build and install +this project and then you can utilize it as: - capnpc compiler/test.capnp -oc +```sh +capnpc compiler/test.capnp -oc +``` [![Build Status](https://travis-ci.org/opensourcerouting/c-capnproto.svg?branch=master)](https://travis-ci.org/opensourcerouting/c-capnproto) -## status +## Building on Linux + +```sh +git clone https://github.com/opensourcerouting/c-capnproto +cd c-capnproto +git submodule update --init --recursive +autoreconf -f -i -s +./configure +make +make check +``` + +## Usage + +### Generating C code from a `.capnp` schema file + +The `compiler` directory contains the C language plugin (`capnpc-c`) for use with the `capnp` tool: https://capnproto.org/capnp-tool.html. + +`capnp` will by default search `$PATH` for `capnpc-c` - if it's on your PATH, you can generate code for your schema as follows: + +```sh +capnp compile -o c myschema.capnp +``` + +Otherwise, you can specify the path to the c plugin: + +```sh +capnp compile -o ./capnpc-c myschema.capnp +``` + +`capnp` generates a C struct that corresponds to each capn proto struct, along with read/write functions that convert to/from capn proto form. + +If you want accessor functions for struct members, use attribute `fieldgetset` in your `.capnp` file as follows: + +```capnp +using C = import "${c-capnproto}/compiler/c.capnp"; + +$C.fieldgetset; + +struct MyStruct {} +``` + +### Example C code + +See the unit tests in [`tests/example-test.cpp`](tests/example-test.cpp). +The example schema file is [`tests/addressbook.capnp`](tests/addressbook.capnp). +The tests are written in C++, but only use C features. + +You need to compile these runtime library files and link them into your own project's binaries: + +* [`lib/capn.c`](lib/capn.c) +* [`lib/capn-malloc.c`](lib/capn-malloc.c) +* [`lib/capn-stream.c`](lib/capn-stream.c) + +Your include path must contain the runtime library directory +[`lib`](lib). Header file [`lib/capnp_c.h`](lib/capnp_c.h) contains +the public interfaces of the library. + +Using make-based builds, make may try to compile `${x}.capnp` from +`${x}.capnp.c` using its built-in rule for compiling `${y}` from +`${y}.c`. You can either disable make's built-in compile rules or just +this specific case with the no-op rule: `%.capnp: ;`. + +For further reference, please see the other unit tests in [`tests`](tests), and header file [`lib/capnp_c.h`](lib/capnp_c.h). + +The project [`quagga-capnproto`](https://github.com/opensourcerouting/quagga-capnproto) uses `c-capnproto` and contains some good examples, as found with [this github repository search](https://github.com/opensourcerouting/quagga-capnproto/search?utf8=%E2%9C%93&q=capn&type=): + +* Serialization in function [`bgp_notify_send()`](https://github.com/opensourcerouting/quagga-capnproto/blob/27061648f3418fac0d217b16a46add534343e841/bgpd/bgp_zmq.c#L81-L96) in file `quagga-capnproto/bgpd/bgp_zmq.c` +* Deserialization in function [`qzc_callback()`](https://github.com/opensourcerouting/quagga-capnproto/blob/27061648f3418fac0d217b16a46add534343e841/lib/qzc.c#L249-L257) in file `quagga-capnproto/lib/qzc.c` + +## Status This is a merge of 3 forks of [James McKaskill's great work](https://github.com/jmckaskill/c-capnproto), which has been untouched for @@ -21,33 +93,3 @@ a while: - [liamstask's fork](https://github.com/liamstask/c-capnproto) - [baruch's fork](https://github.com/baruch/c-capnproto) - [kylemanna's fork](https://github.com/kylemanna/c-capnproto) - - -## usage - -The `compiler` directory contains the C language plugin (`capnpc-c`) for use with the `capnp` tool: https://capnproto.org/capnp-tool.html. - -`capnp` will by default search `$PATH` for `capnpc-c` - if it's on your PATH, you can generate code for your schema as follows: - - $ capnp compile -o c myschema.capnp - -Otherwise, you can specify the path to the c plugin: - - $ capnp compile -o ./capnpc-c myschema.capnp - -`capnp` generates a C struct that corresponds to each capn proto struct, along with read/write functions that convert to/from capn proto form. - -TBD whether it will make sense in the future to provide accessor functions for struct members, rather than converting entire structs. - -## building on linux - -``` -git clone https://github.com/opensourcerouting/c-capnproto -cd c-capnproto -git submodule update --init --recursive -autoreconf -f -i -s -./configure -make -make check -``` - diff --git a/compiler/c.capnp b/compiler/c.capnp index 5de7e73..9a0a1d3 100644 --- a/compiler/c.capnp +++ b/compiler/c.capnp @@ -29,6 +29,10 @@ annotation nameinfix @0x85a8d86d736ba637 (file): Text; # to a loop. $nameinfix (recommended parameter: "-gen") inserts its parameter # before the ".c", so the filename becomes "foo-gen.c" # +# Alternatively, add this Makefile rule to disable compiling "foo.capnp.c" -> "foo.capnp": +# %.capnp: ; +# +# # ("foo" is really "foo.capnp", so it's foo.capnp-gen.c) annotation fieldgetset @0xf72bc690355d66de (file): Void; diff --git a/compiler/c.capnp.c b/compiler/c.capnp.c new file mode 100644 index 0000000..f940824 --- /dev/null +++ b/compiler/c.capnp.c @@ -0,0 +1,2 @@ +#include "c.capnp.h" +/* AUTO GENERATED - DO NOT EDIT */ diff --git a/compiler/c.capnp.h b/compiler/c.capnp.h new file mode 100644 index 0000000..07f769e --- /dev/null +++ b/compiler/c.capnp.h @@ -0,0 +1,27 @@ +#ifndef CAPN_C0183DD65FFEF0F3 +#define CAPN_C0183DD65FFEF0F3 +/* AUTO GENERATED - DO NOT EDIT */ +#include + +#if CAPN_VERSION != 1 +#error "version mismatch between capnp_c.h and generated code" +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/compiler/capnpc-c.c b/compiler/capnpc-c.c index 4258f0a..b9c81de 100644 --- a/compiler/capnpc-c.c +++ b/compiler/capnpc-c.c @@ -8,6 +8,7 @@ #include "schema.capnp.h" #include "str.h" +#include #include #include #include @@ -261,6 +262,7 @@ static void decode_value(struct value* v, Type_ptr type, Value_ptr value, const v->ptrval = p; + bool symbol_provided = symbol; if (!symbol) { static struct str buf = STR_INIT; v->intval = ++g_valc; @@ -268,7 +270,7 @@ static void decode_value(struct value* v, Type_ptr type, Value_ptr value, const } str_addf(&SRC, "%scapn_text %s = {%d,(char*)&capn_buf[%d],(struct capn_segment*)&capn_seg};\n", - symbol ? "" : "static ", + symbol_provided ? "" : "static ", symbol, p.len-1, (int) (p.data-p.seg->data-8)); @@ -291,13 +293,14 @@ static void decode_value(struct value* v, Type_ptr type, Value_ptr value, const v->ptrval = p; + bool symbol_provided = symbol; if (!symbol) { static struct str buf = STR_INIT; v->intval = ++g_valc; symbol = strf(&buf, "capn_val%d", (int) v->intval); } - str_addf(&SRC, "%s%s %s = {", symbol ? "" : "static ", v->tname, symbol); + str_addf(&SRC, "%s%s %s = {", symbol_provided ? "" : "static ", v->tname, symbol); if (strcmp(v->tname, "capn_ptr")) str_addf(&SRC, "{"); @@ -1290,7 +1293,11 @@ int main() { for (j = 0; j < capn_len(file_req.imports); j++) { struct CodeGeneratorRequest_RequestedFile_Import im; get_CodeGeneratorRequest_RequestedFile_Import(&im, file_req.imports, j); - str_addf(&HDR, "#include \"%s%s.h\"\n", im.name.str, nameinfix); + + // Ignore leading slashes when generating C file #include's. + // This signifies an absolute import in a library directory. + const char *base_path = im.name.str[0] == '/' ? &im.name.str[1] : im.name.str; + str_addf(&HDR, "#include \"%s%s.h\"\n", base_path, nameinfix); } str_addf(&HDR, "\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); diff --git a/compiler/schema.capnp b/compiler/schema.capnp index 1e7c615..169f775 100644 --- a/compiler/schema.capnp +++ b/compiler/schema.capnp @@ -19,11 +19,14 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. +using C = import "c.capnp"; using Cxx = import "c++.capnp"; @0xa93fc509624c72d9; $Cxx.namespace("capnp::schema"); +$C.fieldgetset; + using Id = UInt64; # The globally-unique ID of a file, type, or annotation. diff --git a/compiler/schema.capnp.c b/compiler/schema.capnp.c index d362e52..2182cf9 100644 --- a/compiler/schema.capnp.c +++ b/compiler/schema.capnp.c @@ -1,6 +1,6 @@ #include "schema.capnp.h" /* AUTO GENERATED - DO NOT EDIT */ -static const capn_text capn_val0 = {0,""}; +static const capn_text capn_val0 = {0,"",0}; uint16_t Field_noDiscriminant = 65535; Node_ptr new_Node(struct capn_segment *s) { diff --git a/compiler/schema.capnp.h b/compiler/schema.capnp.h index 513b435..f5358ea 100644 --- a/compiler/schema.capnp.h +++ b/compiler/schema.capnp.h @@ -8,6 +8,7 @@ #endif #include "c++.capnp.h" +#include "c.capnp.h" #ifdef __cplusplus extern "C" { diff --git a/compiler/test.capnp b/compiler/test.capnp index 9c65721..fbee1f2 100644 --- a/compiler/test.capnp +++ b/compiler/test.capnp @@ -21,8 +21,11 @@ @0xd508eebdc2dc42b8; +using C = import "c.capnp"; using Cxx = import "c++.capnp"; +$C.fieldgetset; + # Use a namespace likely to cause trouble if the generated code doesn't use fully-qualified # names for stuff in the capnproto namespace. $Cxx.namespace("capnproto_test::capnp::test"); diff --git a/compiler/test.capnp.c b/compiler/test.capnp.c index fa5cc7d..46dce92 100644 --- a/compiler/test.capnp.c +++ b/compiler/test.capnp.c @@ -1,19 +1,43 @@ #include "test.capnp.h" /* AUTO GENERATED - DO NOT EDIT */ -static const capn_text capn_val0 = {0,""}; +static const capn_text capn_val0 = {0,"",0}; static const capn_ptr capn_null = {CAPN_NULL}; -static const uint8_t capn_buf[72] = { +static const uint8_t capn_buf[264] = { 102,111,111,0,0,0,0,0, 98,97,114,0,0,0,0,0, - 9,0,0,0,0,0,0,0, - 111,145,0,0,0,0,0,0, - 103,43,153,212,0,0,0,0, - 199,107,159,6,57,148,96,249, - 199,113,196,43,171,117,107,15, - 57,142,59,212,84,138,148,240, - 111,222,0,0,0,0,0,0 + 1,244,128,13,14,16,76,251, + 78,115,232,56,166,51,0,0, + 90,0,210,4,20,136,98,3, + 210,10,111,18,33,25,204,4, + 95,112,9,175,2,0,0,0, + 0,0,0,0,0,144,117,64, + 77,0,0,0,34,0,0,0, + 77,0,0,0,26,0,0,0, + 2,0,0,0,1,0,0,0, + 73,0,0,0,24,0,0,0, + 69,0,0,0,41,0,0,0, + 69,0,0,0,34,0,0,0, + 69,0,0,0,35,0,0,0, + 194,1,0,0,1,0,0,0, + 218,1,0,0,1,0,0,0, + 2,2,0,0,1,0,0,0, + 18,2,0,0,1,0,0,0, + 34,2,0,0,1,0,0,0, + 58,2,0,0,1,0,0,0, + 98,2,0,0,1,0,0,0, + 130,2,0,0,1,0,0,0, + 186,2,0,0,1,0,0,0, + 242,2,0,0,1,0,0,0, + 42,3,0,0,1,0,0,0, + 218,5,0,0,1,0,0,0, + 0,0,0,0,0,0,0,0, + 98,97,122,0,0,0,0,0, + 113,117,120,0,0,0,0,0, + 26,0,0,0,0,0,0,0, + 12,222,128,127,0,0,0,0, + 210,4,210,233,0,128,255,127 }; -static const struct capn_segment capn_seg = {{0},0,0,0,(char*)&capn_buf[0],72,72}; +static const struct capn_segment capn_seg = {{0},0,0,0,(char*)&capn_buf[0],264,264,0}; union capn_conv_f32 TestWholeFloatDefault_constant = {0x43e40000u}; union capn_conv_f32 TestWholeFloatDefault_bigConstant = {0x7249f2cau}; unsigned TestConstants_boolConst = 1; @@ -29,29 +53,29 @@ union capn_conv_f32 TestConstants_float32Const = {0x449a5000u}; union capn_conv_f64 TestConstants_float64Const = {((uint64_t) 0xc9b58b82u << 32) | 0xc0e0bb00u}; capn_text TestConstants_textConst = {3,(char*)&capn_buf[0],(struct capn_segment*)&capn_seg}; capn_data TestConstants_dataConst = {{2,0,0,0,1,0,3,(char*)&capn_buf[8],(struct capn_segment*)&capn_seg}}; -TestAllTypes_ptr TestConstants_structConst = {{1,1,0,0,48,20,0,(char*)&capn_buf[0],(struct capn_segment*)&capn_seg}}; +TestAllTypes_ptr TestConstants_structConst = {{1,0,0,0,48,20,0,(char*)&capn_buf[16],(struct capn_segment*)&capn_seg}}; enum TestEnum TestConstants_enumConst = (enum TestEnum) 5u; -capn_ptr TestConstants_voidListConst = {2,0,0,0,0,0,6,(char*)&capn_buf[16],(struct capn_segment*)&capn_seg}; -capn_list1 TestConstants_boolListConst = {{4,0,0,0,1,0,4,(char*)&capn_buf[16],(struct capn_segment*)&capn_seg}}; -capn_list8 TestConstants_int8ListConst = {{2,0,0,0,1,0,2,(char*)&capn_buf[24],(struct capn_segment*)&capn_seg}}; -capn_list16 TestConstants_int16ListConst = {{2,0,0,0,2,0,2,(char*)&capn_buf[32],(struct capn_segment*)&capn_seg}}; -capn_list32 TestConstants_int32ListConst = {{2,0,0,0,4,0,2,(char*)&capn_buf[40],(struct capn_segment*)&capn_seg}}; -capn_list64 TestConstants_int64ListConst = {{2,0,0,0,8,0,2,(char*)&capn_buf[48],(struct capn_segment*)&capn_seg}}; -capn_list8 TestConstants_uint8ListConst = {{2,0,0,0,1,0,2,(char*)&capn_buf[64],(struct capn_segment*)&capn_seg}}; -capn_list16 TestConstants_uint16ListConst = {{2,1,0,0,2,0,2,(char*)&capn_buf[1664],(struct capn_segment*)&capn_seg}}; -capn_list32 TestConstants_uint32ListConst = {{2,1,0,0,4,0,1,(char*)&capn_buf[1680],(struct capn_segment*)&capn_seg}}; -capn_list64 TestConstants_uint64ListConst = {{2,1,0,0,8,0,1,(char*)&capn_buf[1696],(struct capn_segment*)&capn_seg}}; -capn_list32 TestConstants_float32ListConst = {{2,1,0,0,4,0,4,(char*)&capn_buf[1712],(struct capn_segment*)&capn_seg}}; -capn_list64 TestConstants_float64ListConst = {{2,1,0,0,8,0,4,(char*)&capn_buf[1736],(struct capn_segment*)&capn_seg}}; -capn_ptr TestConstants_textListConst = {3,1,0,0,0,0,3,(char*)&capn_buf[1776],(struct capn_segment*)&capn_seg}; -capn_ptr TestConstants_dataListConst = {3,1,0,0,0,0,3,(char*)&capn_buf[1832],(struct capn_segment*)&capn_seg}; -TestAllTypes_list TestConstants_structListConst = {{2,1,0,1,48,20,3,(char*)&capn_buf[1904],(struct capn_segment*)&capn_seg}}; -capn_list16 TestConstants_enumListConst = {{2,1,0,0,2,0,2,(char*)&capn_buf[2584],(struct capn_segment*)&capn_seg}}; +capn_ptr TestConstants_voidListConst = {2,0,0,0,0,0,6,(char*)&capn_buf[264],(struct capn_segment*)&capn_seg}; +capn_list1 TestConstants_boolListConst = {{4,1,0,0,1,0,4,(char*)&capn_buf[1512],(struct capn_segment*)&capn_seg}}; +capn_list8 TestConstants_int8ListConst = {{2,1,0,0,1,0,2,(char*)&capn_buf[1528],(struct capn_segment*)&capn_seg}}; +capn_list16 TestConstants_int16ListConst = {{2,1,0,0,2,0,2,(char*)&capn_buf[1544],(struct capn_segment*)&capn_seg}}; +capn_list32 TestConstants_int32ListConst = {{2,1,0,0,4,0,2,(char*)&capn_buf[1560],(struct capn_segment*)&capn_seg}}; +capn_list64 TestConstants_int64ListConst = {{2,1,0,0,8,0,2,(char*)&capn_buf[1576],(struct capn_segment*)&capn_seg}}; +capn_list8 TestConstants_uint8ListConst = {{2,1,0,0,1,0,2,(char*)&capn_buf[1600],(struct capn_segment*)&capn_seg}}; +capn_list16 TestConstants_uint16ListConst = {{2,1,0,0,2,0,2,(char*)&capn_buf[1616],(struct capn_segment*)&capn_seg}}; +capn_list32 TestConstants_uint32ListConst = {{2,1,0,0,4,0,1,(char*)&capn_buf[1632],(struct capn_segment*)&capn_seg}}; +capn_list64 TestConstants_uint64ListConst = {{2,1,0,0,8,0,1,(char*)&capn_buf[1648],(struct capn_segment*)&capn_seg}}; +capn_list32 TestConstants_float32ListConst = {{2,1,0,0,4,0,4,(char*)&capn_buf[1664],(struct capn_segment*)&capn_seg}}; +capn_list64 TestConstants_float64ListConst = {{2,1,0,0,8,0,4,(char*)&capn_buf[1688],(struct capn_segment*)&capn_seg}}; +capn_ptr TestConstants_textListConst = {3,1,0,0,0,0,3,(char*)&capn_buf[1728],(struct capn_segment*)&capn_seg}; +capn_ptr TestConstants_dataListConst = {3,1,0,0,0,0,3,(char*)&capn_buf[1784],(struct capn_segment*)&capn_seg}; +TestAllTypes_list TestConstants_structListConst = {{2,1,0,1,48,20,3,(char*)&capn_buf[1856],(struct capn_segment*)&capn_seg}}; +capn_list16 TestConstants_enumListConst = {{2,1,0,0,2,0,2,(char*)&capn_buf[2536],(struct capn_segment*)&capn_seg}}; uint32_t globalInt = 12345u; -capn_text globalText = {6,(char*)&capn_buf[2600],(struct capn_segment*)&capn_seg}; -TestAllTypes_ptr globalStruct = {{1,1,0,0,48,20,0,(char*)&capn_buf[2616],(struct capn_segment*)&capn_seg}}; -TestPrintInlineStructs_ptr globalPrintableStruct = {{1,1,0,0,0,2,0,(char*)&capn_buf[2832],(struct capn_segment*)&capn_seg}}; -TestAllTypes_ptr derivedConstant = {{1,1,0,0,48,20,0,(char*)&capn_buf[2864],(struct capn_segment*)&capn_seg}}; +capn_text globalText = {6,(char*)&capn_buf[2552],(struct capn_segment*)&capn_seg}; +TestAllTypes_ptr globalStruct = {{1,1,0,0,48,20,0,(char*)&capn_buf[2568],(struct capn_segment*)&capn_seg}}; +TestPrintInlineStructs_ptr globalPrintableStruct = {{1,1,0,0,0,2,0,(char*)&capn_buf[2784],(struct capn_segment*)&capn_seg}}; +TestAllTypes_ptr derivedConstant = {{1,1,0,0,48,20,0,(char*)&capn_buf[2816],(struct capn_segment*)&capn_seg}}; TestAllTypes_ptr new_TestAllTypes(struct capn_segment *s) { TestAllTypes_ptr p; @@ -527,25 +551,25 @@ void TestAllTypes_set_interfaceList(TestAllTypes_ptr p, capn_ptr interfaceList) { capn_setp(p.p, 19, interfaceList); } -capn_text capn_val1 = {3,(char*)&capn_buf[1464],(struct capn_segment*)&capn_seg}; -capn_data capn_val2 = {{2,1,0,0,1,0,3,(char*)&capn_buf[1480],(struct capn_segment*)&capn_seg}}; -TestAllTypes_ptr capn_val3 = {{1,1,0,0,48,20,0,(char*)&capn_buf[1496],(struct capn_segment*)&capn_seg}}; -capn_ptr capn_val4 = {2,0,0,0,0,0,6,(char*)&capn_buf[72],(struct capn_segment*)&capn_seg}; -capn_list1 capn_val5 = {{4,1,0,0,1,0,4,(char*)&capn_buf[3160],(struct capn_segment*)&capn_seg}}; -capn_list8 capn_val6 = {{2,1,0,0,1,0,2,(char*)&capn_buf[3176],(struct capn_segment*)&capn_seg}}; -capn_list16 capn_val7 = {{2,1,0,0,2,0,2,(char*)&capn_buf[3192],(struct capn_segment*)&capn_seg}}; -capn_list32 capn_val8 = {{2,1,0,0,4,0,2,(char*)&capn_buf[3208],(struct capn_segment*)&capn_seg}}; -capn_list64 capn_val9 = {{2,1,0,0,8,0,2,(char*)&capn_buf[3224],(struct capn_segment*)&capn_seg}}; -capn_list8 capn_val10 = {{2,1,0,0,1,0,2,(char*)&capn_buf[3248],(struct capn_segment*)&capn_seg}}; -capn_list16 capn_val11 = {{2,1,0,0,2,0,2,(char*)&capn_buf[3264],(struct capn_segment*)&capn_seg}}; -capn_list32 capn_val12 = {{2,1,0,0,4,0,1,(char*)&capn_buf[3280],(struct capn_segment*)&capn_seg}}; -capn_list64 capn_val13 = {{2,1,0,0,8,0,1,(char*)&capn_buf[3296],(struct capn_segment*)&capn_seg}}; -capn_list32 capn_val14 = {{2,1,0,0,4,0,4,(char*)&capn_buf[3312],(struct capn_segment*)&capn_seg}}; -capn_list64 capn_val15 = {{2,1,0,0,8,0,4,(char*)&capn_buf[3336],(struct capn_segment*)&capn_seg}}; -capn_ptr capn_val16 = {3,1,0,0,0,0,3,(char*)&capn_buf[3376],(struct capn_segment*)&capn_seg}; -capn_ptr capn_val17 = {3,1,0,0,0,0,3,(char*)&capn_buf[3432],(struct capn_segment*)&capn_seg}; -TestAllTypes_list capn_val18 = {{2,1,0,1,48,20,3,(char*)&capn_buf[8],(struct capn_segment*)&capn_seg}}; -capn_list16 capn_val19 = {{2,1,0,0,2,0,2,(char*)&capn_buf[3496],(struct capn_segment*)&capn_seg}}; +static capn_text capn_val1 = {3,(char*)&capn_buf[1408],(struct capn_segment*)&capn_seg}; +static capn_data capn_val2 = {{2,1,0,0,1,0,3,(char*)&capn_buf[1424],(struct capn_segment*)&capn_seg}}; +static TestAllTypes_ptr capn_val3 = {{1,1,0,0,48,20,0,(char*)&capn_buf[1440],(struct capn_segment*)&capn_seg}}; +static capn_ptr capn_val4 = {2,0,0,0,0,0,6,(char*)&capn_buf[264],(struct capn_segment*)&capn_seg}; +static capn_list1 capn_val5 = {{4,1,0,0,1,0,4,(char*)&capn_buf[3104],(struct capn_segment*)&capn_seg}}; +static capn_list8 capn_val6 = {{2,1,0,0,1,0,2,(char*)&capn_buf[3120],(struct capn_segment*)&capn_seg}}; +static capn_list16 capn_val7 = {{2,1,0,0,2,0,2,(char*)&capn_buf[3136],(struct capn_segment*)&capn_seg}}; +static capn_list32 capn_val8 = {{2,1,0,0,4,0,2,(char*)&capn_buf[3152],(struct capn_segment*)&capn_seg}}; +static capn_list64 capn_val9 = {{2,1,0,0,8,0,2,(char*)&capn_buf[3168],(struct capn_segment*)&capn_seg}}; +static capn_list8 capn_val10 = {{2,1,0,0,1,0,2,(char*)&capn_buf[3192],(struct capn_segment*)&capn_seg}}; +static capn_list16 capn_val11 = {{2,1,0,0,2,0,2,(char*)&capn_buf[3208],(struct capn_segment*)&capn_seg}}; +static capn_list32 capn_val12 = {{2,1,0,0,4,0,1,(char*)&capn_buf[3224],(struct capn_segment*)&capn_seg}}; +static capn_list64 capn_val13 = {{2,1,0,0,8,0,1,(char*)&capn_buf[3240],(struct capn_segment*)&capn_seg}}; +static capn_list32 capn_val14 = {{2,1,0,0,4,0,4,(char*)&capn_buf[3256],(struct capn_segment*)&capn_seg}}; +static capn_list64 capn_val15 = {{2,1,0,0,8,0,4,(char*)&capn_buf[3280],(struct capn_segment*)&capn_seg}}; +static capn_ptr capn_val16 = {3,1,0,0,0,0,3,(char*)&capn_buf[3320],(struct capn_segment*)&capn_seg}; +static capn_ptr capn_val17 = {3,1,0,0,0,0,3,(char*)&capn_buf[3376],(struct capn_segment*)&capn_seg}; +static TestAllTypes_list capn_val18 = {{2,1,0,1,48,20,3,(char*)&capn_buf[8],(struct capn_segment*)&capn_seg}}; +static capn_list16 capn_val19 = {{2,1,0,0,2,0,2,(char*)&capn_buf[3440],(struct capn_segment*)&capn_seg}}; TestDefaults_ptr new_TestDefaults(struct capn_segment *s) { TestDefaults_ptr p; @@ -1976,10 +2000,10 @@ void set_TestInterleavedGroups(const struct TestInterleavedGroups *s, TestInterl p.p = capn_getp(l.p, i, 0); write_TestInterleavedGroups(s, p); } -TestUnion_ptr capn_val20 = {{1,1,0,0,64,2,0,(char*)&capn_buf[3512],(struct capn_segment*)&capn_seg}}; -TestUnion_ptr capn_val21 = {{1,1,0,0,64,2,0,(char*)&capn_buf[3600],(struct capn_segment*)&capn_seg}}; -TestUnnamedUnion_ptr capn_val22 = {{1,1,0,0,16,2,0,(char*)&capn_buf[3696],(struct capn_segment*)&capn_seg}}; -TestUnnamedUnion_ptr capn_val23 = {{1,1,0,0,16,2,0,(char*)&capn_buf[3736],(struct capn_segment*)&capn_seg}}; +static TestUnion_ptr capn_val20 = {{1,1,0,0,64,2,0,(char*)&capn_buf[3456],(struct capn_segment*)&capn_seg}}; +static TestUnion_ptr capn_val21 = {{1,1,0,0,64,2,0,(char*)&capn_buf[3544],(struct capn_segment*)&capn_seg}}; +static TestUnnamedUnion_ptr capn_val22 = {{1,1,0,0,16,2,0,(char*)&capn_buf[3640],(struct capn_segment*)&capn_seg}}; +static TestUnnamedUnion_ptr capn_val23 = {{1,1,0,0,16,2,0,(char*)&capn_buf[3680],(struct capn_segment*)&capn_seg}}; TestUnionDefaults_ptr new_TestUnionDefaults(struct capn_segment *s) { TestUnionDefaults_ptr p; @@ -3146,7 +3170,7 @@ void TestFieldZeroIsBit_set_thirdField(TestFieldZeroIsBit_ptr p, uint8_t thirdFi { capn_write8(p.p, 1, thirdField ^ 123u); } -TestLists_ptr capn_val24 = {{1,1,0,0,0,10,0,(char*)&capn_buf[3792],(struct capn_segment*)&capn_seg}}; +static TestLists_ptr capn_val24 = {{1,1,0,0,0,10,0,(char*)&capn_buf[3736],(struct capn_segment*)&capn_seg}}; TestListDefaults_ptr new_TestListDefaults(struct capn_segment *s) { TestListDefaults_ptr p; @@ -3388,7 +3412,7 @@ void TestOldVersion_set_old3(TestOldVersion_ptr p, TestOldVersion_ptr old3) { capn_setp(p.p, 1, old3.p); } -capn_text capn_val25 = {3,(char*)&capn_buf[1544],(struct capn_segment*)&capn_seg}; +static capn_text capn_val25 = {3,(char*)&capn_buf[1480],(struct capn_segment*)&capn_seg}; TestNewVersion_ptr new_TestNewVersion(struct capn_segment *s) { TestNewVersion_ptr p; diff --git a/compiler/test.capnp.h b/compiler/test.capnp.h index 7406a69..28a6bd1 100644 --- a/compiler/test.capnp.h +++ b/compiler/test.capnp.h @@ -8,6 +8,7 @@ #endif #include "c++.capnp.h" +#include "c.capnp.h" #ifdef __cplusplus extern "C" { diff --git a/tests/addressbook.capnp b/tests/addressbook.capnp new file mode 100644 index 0000000..c2b85f4 --- /dev/null +++ b/tests/addressbook.capnp @@ -0,0 +1,59 @@ +# Based on the addressbook.capnp example in the capnproto C++ project: +# https://github.com/sandstorm-io/capnproto/blob/6816634a08b08bc8f52b4ee809afb58389f19655/c%2B%2B/samples/addressbook.capnp +# +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0x9eb32e19f86ee174; + +using C = import "/c.capnp"; +$C.fieldgetset; + +struct Person { + id @0 :UInt32; + name @1 :Text; + email @2 :Text; + phones @3 :List(PhoneNumber); + + struct PhoneNumber { + number @0 :Text; + type @1 :Type; + + enum Type { + mobile @0; + home @1; + work @2; + } + } + + employment :union { + unemployed @4 :Void; + employer @5 :Text; + school @6 :Text; + selfEmployed @7 :Void; + # We assume that a person is only one of these. + } +} + +struct AddressBook { + people @0 :List(Person); +} + diff --git a/tests/addressbook.capnp.c b/tests/addressbook.capnp.c new file mode 100644 index 0000000..db2ad3c --- /dev/null +++ b/tests/addressbook.capnp.c @@ -0,0 +1,200 @@ +#include "addressbook.capnp.h" +/* AUTO GENERATED - DO NOT EDIT */ +static const capn_text capn_val0 = {0,"",0}; + +Person_ptr new_Person(struct capn_segment *s) { + Person_ptr p; + p.p = capn_new_struct(s, 8, 4); + return p; +} +Person_list new_Person_list(struct capn_segment *s, int len) { + Person_list p; + p.p = capn_new_list(s, len, 8, 4); + return p; +} +void read_Person(struct Person *s, Person_ptr p) { + capn_resolve(&p.p); + s->id = capn_read32(p.p, 0); + s->name = capn_get_text(p.p, 0, capn_val0); + s->email = capn_get_text(p.p, 1, capn_val0); + s->phones.p = capn_getp(p.p, 2, 0); + s->employment_which = (enum Person_employment_which)(int) capn_read16(p.p, 4); + switch (s->employment_which) { + case Person_employment_employer: + case Person_employment_school: + s->employment.school = capn_get_text(p.p, 3, capn_val0); + break; + default: + break; + } +} +void write_Person(const struct Person *s, Person_ptr p) { + capn_resolve(&p.p); + capn_write32(p.p, 0, s->id); + capn_set_text(p.p, 0, s->name); + capn_set_text(p.p, 1, s->email); + capn_setp(p.p, 2, s->phones.p); + capn_write16(p.p, 4, s->employment_which); + switch (s->employment_which) { + case Person_employment_employer: + case Person_employment_school: + capn_set_text(p.p, 3, s->employment.school); + break; + default: + break; + } +} +void get_Person(struct Person *s, Person_list l, int i) { + Person_ptr p; + p.p = capn_getp(l.p, i, 0); + read_Person(s, p); +} +void set_Person(const struct Person *s, Person_list l, int i) { + Person_ptr p; + p.p = capn_getp(l.p, i, 0); + write_Person(s, p); +} + +uint32_t Person_get_id(Person_ptr p) +{ + uint32_t id; + id = capn_read32(p.p, 0); + return id; +} + +capn_text Person_get_name(Person_ptr p) +{ + capn_text name; + name = capn_get_text(p.p, 0, capn_val0); + return name; +} + +capn_text Person_get_email(Person_ptr p) +{ + capn_text email; + email = capn_get_text(p.p, 1, capn_val0); + return email; +} + +Person_PhoneNumber_list Person_get_phones(Person_ptr p) +{ + Person_PhoneNumber_list phones; + phones.p = capn_getp(p.p, 2, 0); + return phones; +} + +void Person_set_id(Person_ptr p, uint32_t id) +{ + capn_write32(p.p, 0, id); +} + +void Person_set_name(Person_ptr p, capn_text name) +{ + capn_set_text(p.p, 0, name); +} + +void Person_set_email(Person_ptr p, capn_text email) +{ + capn_set_text(p.p, 1, email); +} + +void Person_set_phones(Person_ptr p, Person_PhoneNumber_list phones) +{ + capn_setp(p.p, 2, phones.p); +} + +Person_PhoneNumber_ptr new_Person_PhoneNumber(struct capn_segment *s) { + Person_PhoneNumber_ptr p; + p.p = capn_new_struct(s, 8, 1); + return p; +} +Person_PhoneNumber_list new_Person_PhoneNumber_list(struct capn_segment *s, int len) { + Person_PhoneNumber_list p; + p.p = capn_new_list(s, len, 8, 1); + return p; +} +void read_Person_PhoneNumber(struct Person_PhoneNumber *s, Person_PhoneNumber_ptr p) { + capn_resolve(&p.p); + s->number = capn_get_text(p.p, 0, capn_val0); + s->type = (enum Person_PhoneNumber_Type)(int) capn_read16(p.p, 0); +} +void write_Person_PhoneNumber(const struct Person_PhoneNumber *s, Person_PhoneNumber_ptr p) { + capn_resolve(&p.p); + capn_set_text(p.p, 0, s->number); + capn_write16(p.p, 0, (uint16_t) (s->type)); +} +void get_Person_PhoneNumber(struct Person_PhoneNumber *s, Person_PhoneNumber_list l, int i) { + Person_PhoneNumber_ptr p; + p.p = capn_getp(l.p, i, 0); + read_Person_PhoneNumber(s, p); +} +void set_Person_PhoneNumber(const struct Person_PhoneNumber *s, Person_PhoneNumber_list l, int i) { + Person_PhoneNumber_ptr p; + p.p = capn_getp(l.p, i, 0); + write_Person_PhoneNumber(s, p); +} + +capn_text Person_PhoneNumber_get_number(Person_PhoneNumber_ptr p) +{ + capn_text number; + number = capn_get_text(p.p, 0, capn_val0); + return number; +} + +enum Person_PhoneNumber_Type Person_PhoneNumber_get_type(Person_PhoneNumber_ptr p) +{ + enum Person_PhoneNumber_Type type; + type = (enum Person_PhoneNumber_Type)(int) capn_read16(p.p, 0); + return type; +} + +void Person_PhoneNumber_set_number(Person_PhoneNumber_ptr p, capn_text number) +{ + capn_set_text(p.p, 0, number); +} + +void Person_PhoneNumber_set_type(Person_PhoneNumber_ptr p, enum Person_PhoneNumber_Type type) +{ + capn_write16(p.p, 0, (uint16_t) (type)); +} + +AddressBook_ptr new_AddressBook(struct capn_segment *s) { + AddressBook_ptr p; + p.p = capn_new_struct(s, 0, 1); + return p; +} +AddressBook_list new_AddressBook_list(struct capn_segment *s, int len) { + AddressBook_list p; + p.p = capn_new_list(s, len, 0, 1); + return p; +} +void read_AddressBook(struct AddressBook *s, AddressBook_ptr p) { + capn_resolve(&p.p); + s->people.p = capn_getp(p.p, 0, 0); +} +void write_AddressBook(const struct AddressBook *s, AddressBook_ptr p) { + capn_resolve(&p.p); + capn_setp(p.p, 0, s->people.p); +} +void get_AddressBook(struct AddressBook *s, AddressBook_list l, int i) { + AddressBook_ptr p; + p.p = capn_getp(l.p, i, 0); + read_AddressBook(s, p); +} +void set_AddressBook(const struct AddressBook *s, AddressBook_list l, int i) { + AddressBook_ptr p; + p.p = capn_getp(l.p, i, 0); + write_AddressBook(s, p); +} + +Person_list AddressBook_get_people(AddressBook_ptr p) +{ + Person_list people; + people.p = capn_getp(p.p, 0, 0); + return people; +} + +void AddressBook_set_people(AddressBook_ptr p, Person_list people) +{ + capn_setp(p.p, 0, people.p); +} diff --git a/tests/addressbook.capnp.h b/tests/addressbook.capnp.h new file mode 100644 index 0000000..80be6c8 --- /dev/null +++ b/tests/addressbook.capnp.h @@ -0,0 +1,134 @@ +#ifndef CAPN_9EB32E19F86EE174 +#define CAPN_9EB32E19F86EE174 +/* AUTO GENERATED - DO NOT EDIT */ +#include + +#if CAPN_VERSION != 1 +#error "version mismatch between capnp_c.h and generated code" +#endif + +#include "c.capnp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct Person; +struct Person_PhoneNumber; +struct AddressBook; + +typedef struct {capn_ptr p;} Person_ptr; +typedef struct {capn_ptr p;} Person_PhoneNumber_ptr; +typedef struct {capn_ptr p;} AddressBook_ptr; + +typedef struct {capn_ptr p;} Person_list; +typedef struct {capn_ptr p;} Person_PhoneNumber_list; +typedef struct {capn_ptr p;} AddressBook_list; + +enum Person_PhoneNumber_Type { + Person_PhoneNumber_Type_mobile = 0, + Person_PhoneNumber_Type_home = 1, + Person_PhoneNumber_Type_work = 2 +}; +enum Person_employment_which { + Person_employment_unemployed = 0, + Person_employment_employer = 1, + Person_employment_school = 2, + Person_employment_selfEmployed = 3 +}; + +struct Person { + uint32_t id; + capn_text name; + capn_text email; + Person_PhoneNumber_list phones; + enum Person_employment_which employment_which; + union { + capn_text employer; + capn_text school; + } employment; +}; + +static const size_t Person_word_count = 1; + +static const size_t Person_pointer_count = 4; + +static const size_t Person_struct_bytes_count = 40; + +uint32_t Person_get_id(Person_ptr p); + +capn_text Person_get_name(Person_ptr p); + +capn_text Person_get_email(Person_ptr p); + +Person_PhoneNumber_list Person_get_phones(Person_ptr p); + +void Person_set_id(Person_ptr p, uint32_t id); + +void Person_set_name(Person_ptr p, capn_text name); + +void Person_set_email(Person_ptr p, capn_text email); + +void Person_set_phones(Person_ptr p, Person_PhoneNumber_list phones); + +struct Person_PhoneNumber { + capn_text number; + enum Person_PhoneNumber_Type type; +}; + +static const size_t Person_PhoneNumber_word_count = 1; + +static const size_t Person_PhoneNumber_pointer_count = 1; + +static const size_t Person_PhoneNumber_struct_bytes_count = 16; + +capn_text Person_PhoneNumber_get_number(Person_PhoneNumber_ptr p); + +enum Person_PhoneNumber_Type Person_PhoneNumber_get_type(Person_PhoneNumber_ptr p); + +void Person_PhoneNumber_set_number(Person_PhoneNumber_ptr p, capn_text number); + +void Person_PhoneNumber_set_type(Person_PhoneNumber_ptr p, enum Person_PhoneNumber_Type type); + +struct AddressBook { + Person_list people; +}; + +static const size_t AddressBook_word_count = 0; + +static const size_t AddressBook_pointer_count = 1; + +static const size_t AddressBook_struct_bytes_count = 8; + +Person_list AddressBook_get_people(AddressBook_ptr p); + +void AddressBook_set_people(AddressBook_ptr p, Person_list people); + +Person_ptr new_Person(struct capn_segment*); +Person_PhoneNumber_ptr new_Person_PhoneNumber(struct capn_segment*); +AddressBook_ptr new_AddressBook(struct capn_segment*); + +Person_list new_Person_list(struct capn_segment*, int len); +Person_PhoneNumber_list new_Person_PhoneNumber_list(struct capn_segment*, int len); +AddressBook_list new_AddressBook_list(struct capn_segment*, int len); + +void read_Person(struct Person*, Person_ptr); +void read_Person_PhoneNumber(struct Person_PhoneNumber*, Person_PhoneNumber_ptr); +void read_AddressBook(struct AddressBook*, AddressBook_ptr); + +void write_Person(const struct Person*, Person_ptr); +void write_Person_PhoneNumber(const struct Person_PhoneNumber*, Person_PhoneNumber_ptr); +void write_AddressBook(const struct AddressBook*, AddressBook_ptr); + +void get_Person(struct Person*, Person_list, int i); +void get_Person_PhoneNumber(struct Person_PhoneNumber*, Person_PhoneNumber_list, int i); +void get_AddressBook(struct AddressBook*, AddressBook_list, int i); + +void set_Person(const struct Person*, Person_list, int i); +void set_Person_PhoneNumber(const struct Person_PhoneNumber*, Person_PhoneNumber_list, int i); +void set_AddressBook(const struct AddressBook*, AddressBook_list, int i); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tests/example-test.cpp b/tests/example-test.cpp new file mode 100644 index 0000000..10f0ff8 --- /dev/null +++ b/tests/example-test.cpp @@ -0,0 +1,165 @@ +/* example-test.cpp + * + * Some simple examples using c-capnproto. + * + * Based on the addressbook.capnp example in the capnproto C++ project: + * https://github.com/sandstorm-io/capnproto/blob/6816634a08b08bc8f52b4ee809afb58389f19655/c%2B%2B/samples/addressbook.capnp + * + * Copyright (C) 2017 Alex Helfet + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +#include +#include + +#include "capnp_c.h" +#include "addressbook.capnp.h" + +static capn_text chars_to_text(const char *chars) { + return (capn_text) { + .len = (int) strlen(chars), + .str = chars, + .seg = NULL, + }; +} + +// EXPECT_CAPN_TEXT_EQ arguments: +// const char * expected +// capn_text t +#define EXPECT_CAPN_TEXT_EQ(expected, t) \ + do { \ + EXPECT_EQ(strlen((expected)), (uint32_t) (t).len); \ + EXPECT_STREQ((expected), (t).str); \ + } while(0); + + +// Demonstrates serializing an object tree to a byte array, then deserializing it +// back into an object tree and asserting on the expected values therein. +// +// This example uses generated read_*, write_*, get_*, set_* functions +// to deserialize into structs. +TEST(Examples, RoundTripPerson) { + uint8_t buf[4096]; + ssize_t sz = 0; + + const char *name = "Firstname Lastname"; + const char *email = "username@domain.com"; + const char *school = "of life"; + + { + struct capn c; + capn_init_malloc(&c); + capn_ptr cr = capn_root(&c); + struct capn_segment *cs = cr.seg; + + // Set initial object in `p`. + struct Person p = { + .id = 17, + .name = chars_to_text(name), + .email = chars_to_text(email), + }; + p.employment_which = Person_employment_school; + p.employment.school = chars_to_text(school); + + p.phones = new_Person_PhoneNumber_list(cs, 2); + struct Person_PhoneNumber pn0 = { + .number = chars_to_text("123"), + .type = Person_PhoneNumber_Type_work, + }; + set_Person_PhoneNumber(&pn0, p.phones, 0); + struct Person_PhoneNumber pn1 = { + .number = chars_to_text("234"), + .type = Person_PhoneNumber_Type_home, + }; + set_Person_PhoneNumber(&pn1, p.phones, 1); + + Person_ptr pp = new_Person(cs); + write_Person(&p, pp); + int setp_ret = capn_setp(capn_root(&c), 0, pp.p); + ASSERT_EQ(0, setp_ret); + sz = capn_write_mem(&c, buf, sizeof(buf), 0 /* packed */); + capn_free(&c); + } + + { + // Write serialized object to file system. + FILE *f = fopen("tests/example-test.cpp.Person.out", "wb"); + ASSERT_NE(f, (void*)0); + fwrite(buf, 1 /* size */, sz /* count */, f); + int close_ret = fclose(f); + ASSERT_EQ(0, close_ret); + } + + { + // Deserialize `buf[0..sz-1]` to `rp`. + struct capn rc; + int init_mem_ret = capn_init_mem(&rc, buf, sz, 0 /* packed */); + ASSERT_EQ(0, init_mem_ret); + Person_ptr rroot; + struct Person rp; + rroot.p = capn_getp(capn_root(&rc), 0 /* off */, 1 /* resolve */); + read_Person(&rp, rroot); + + // Assert deserialized values in `rp` + EXPECT_EQ(rp.id, (uint32_t) 17); + EXPECT_CAPN_TEXT_EQ(name, rp.name); + EXPECT_CAPN_TEXT_EQ(email, rp.email); + + EXPECT_EQ(rp.employment_which, Person_employment_school); + EXPECT_CAPN_TEXT_EQ(school, rp.employment.school); + + EXPECT_EQ(2, capn_len(rp.phones)); + + struct Person_PhoneNumber rpn0; + get_Person_PhoneNumber(&rpn0, rp.phones, 0); + EXPECT_CAPN_TEXT_EQ("123", rpn0.number); + EXPECT_EQ(rpn0.type, Person_PhoneNumber_Type_work); + + struct Person_PhoneNumber rpn1; + get_Person_PhoneNumber(&rpn1, rp.phones, 1); + EXPECT_CAPN_TEXT_EQ("234", rpn1.number); + EXPECT_EQ(rpn1.type, Person_PhoneNumber_Type_home); + + capn_free(&rc); + } +} + +// Demonstrate accessing serialized objects using accessor functions without +// first copying values into structs. +TEST(Examples, PersonWithAccessors) { + struct capn c; + capn_init_malloc(&c); + capn_ptr cr = capn_root(&c); + struct capn_segment *cs = cr.seg; + + // Set fields with set_ accessors. + Person_ptr pp = new_Person(cs); + { + Person_set_id(pp, 17); + + capn_text name = chars_to_text("Name"); + EXPECT_CAPN_TEXT_EQ("Name", name); + Person_set_name(pp, name); + + Person_PhoneNumber_list pnl = new_Person_PhoneNumber_list(cs, 1); + Person_set_phones(pp, pnl); + Person_PhoneNumber_ptr pn0; + pn0.p = capn_getp(pnl.p, 0 /* offset */, 0 /* resolve */); + Person_PhoneNumber_set_type(pn0, Person_PhoneNumber_Type_home); + } + + // Assert field values returned by get_ accessors. + { + EXPECT_EQ(Person_get_id(pp), 17); + EXPECT_CAPN_TEXT_EQ("Name", Person_get_name(pp)); + + Person_PhoneNumber_list pnl = Person_get_phones(pp); + Person_PhoneNumber_ptr pn0; + pn0.p = capn_getp(pnl.p, 0 /* offset */, 0 /* resolve */); + EXPECT_EQ(Person_PhoneNumber_Type_home, Person_PhoneNumber_get_type(pn0)); + } + + capn_free(&c); +}