Example usage in unit test.

This commit is contained in:
Alex Helfet 2017-03-23 20:12:44 +00:00
parent 362173091d
commit 29a1342d00
7 changed files with 274 additions and 35 deletions

2
.gitignore vendored
View file

@ -17,6 +17,8 @@ test-driver
*.log
*.trs
tests/*.out
*.o
*.a
*.so

View file

@ -56,6 +56,8 @@ check_PROGRAMS += \
capn_test_SOURCES = \
tests/capn-test.cpp \
tests/capn-stream-test.cpp \
tests/example-test.cpp \
tests/example.capnp.c \
compiler/test.capnp.c \
compiler/schema-test.cpp \
compiler/schema.capnp.c

View file

@ -4,44 +4,19 @@ 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:
```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
This is a merge of 3 forks of [James McKaskill's great
work](https://github.com/jmckaskill/c-capnproto), which has been untouched for
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
```
```sh
git clone https://github.com/opensourcerouting/c-capnproto
cd c-capnproto
git submodule update --init --recursive
@ -51,3 +26,61 @@ 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/example.capnp`](tests/example.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.
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
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)

72
tests/example-test.cpp Normal file
View file

@ -0,0 +1,72 @@
/* example-test.cpp
*
* Some simple examples using c-capnproto
*
* 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 <gtest/gtest.h>
#include <cstdint>
#include "capnp_c.h"
#include "example.capnp.h"
TEST(Examples, RoundTrip) {
uint8_t buf[4096];
ssize_t sz = 0;
const char *s = "Hello.";
{
// Set initial object in `g`.
const capn_text capn_val0 = {
.len = strlen(s),
.str = s,
.seg = NULL
};
struct Greeting g = {
.text = capn_val0,
.timesToSay = 17,
};
// Serialize `g` to `buf[0..sz-1]`.
struct capn c;
capn_init_malloc(&c);
capn_ptr cr = capn_root(&c);
struct capn_segment *cs = cr.seg;
Greeting_ptr gp = new_Greeting(cs);
write_Greeting(&g, gp);
int setp_ret = capn_setp(capn_root(&c), 0, gp.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.Greeting.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 `rg`.
struct capn rc;
int init_mem_ret = capn_init_mem(&rc, buf, sz, 0 /* packed */);
ASSERT_EQ(0, init_mem_ret);
Greeting_ptr rroot;
struct Greeting rg;
rroot.p = capn_getp(capn_root(&rc), 0 /* off */, 1 /* resolve */);
read_Greeting(&rg, rroot);
// Assert deserialized values in `rg`
EXPECT_EQ(rg.timesToSay, 17);
EXPECT_EQ(strlen(s), (uint32_t) rg.text.len);
EXPECT_EQ(0, strncmp(s, rg.text.str, strlen(s)));
}
}

10
tests/example.capnp Normal file
View file

@ -0,0 +1,10 @@
@0xd120e9a4c43868ab;
using C = import "../compiler/c.capnp";
$C.fieldgetset;
struct Greeting {
text @0 :Text = "Default greeting: hello world!";
timesToSay @1 :UInt32;
}

66
tests/example.capnp.c Normal file
View file

@ -0,0 +1,66 @@
#include "example.capnp.h"
/* AUTO GENERATED - DO NOT EDIT */
static const capn_text capn_val0 = {0,"",0};
static const uint8_t capn_buf[32] = {
68,101,102,97,117,108,116,32,
103,114,101,101,116,105,110,103,
58,32,104,101,108,108,111,32,
119,111,114,108,100,33,0,0
};
static const struct capn_segment capn_seg = {{0},0,0,0,(char*)&capn_buf[0],32,32,0};
static capn_text capn_val1 = {30,(char*)&capn_buf[0],(struct capn_segment*)&capn_seg};
Greeting_ptr new_Greeting(struct capn_segment *s) {
Greeting_ptr p;
p.p = capn_new_struct(s, 8, 1);
return p;
}
Greeting_list new_Greeting_list(struct capn_segment *s, int len) {
Greeting_list p;
p.p = capn_new_list(s, len, 8, 1);
return p;
}
void read_Greeting(struct Greeting *s, Greeting_ptr p) {
capn_resolve(&p.p);
s->text = capn_get_text(p.p, 0, capn_val1);
s->timesToSay = capn_read32(p.p, 0);
}
void write_Greeting(const struct Greeting *s, Greeting_ptr p) {
capn_resolve(&p.p);
capn_set_text(p.p, 0, (s->text.str != capn_val1.str) ? s->text : capn_val0);
capn_write32(p.p, 0, s->timesToSay);
}
void get_Greeting(struct Greeting *s, Greeting_list l, int i) {
Greeting_ptr p;
p.p = capn_getp(l.p, i, 0);
read_Greeting(s, p);
}
void set_Greeting(const struct Greeting *s, Greeting_list l, int i) {
Greeting_ptr p;
p.p = capn_getp(l.p, i, 0);
write_Greeting(s, p);
}
capn_text Greeting_get_text(Greeting_ptr p)
{
capn_text text;
text = capn_get_text(p.p, 0, capn_val1);
return text;
}
uint32_t Greeting_get_timesToSay(Greeting_ptr p)
{
uint32_t timesToSay;
timesToSay = capn_read32(p.p, 0);
return timesToSay;
}
void Greeting_set_text(Greeting_ptr p, capn_text text)
{
capn_set_text(p.p, 0, (text.str != capn_val1.str) ? text : capn_val0);
}
void Greeting_set_timesToSay(Greeting_ptr p, uint32_t timesToSay)
{
capn_write32(p.p, 0, timesToSay);
}

54
tests/example.capnp.h Normal file
View file

@ -0,0 +1,54 @@
#ifndef CAPN_D120E9A4C43868AB
#define CAPN_D120E9A4C43868AB
/* AUTO GENERATED - DO NOT EDIT */
#include <capnp_c.h>
#if CAPN_VERSION != 1
#error "version mismatch between capnp_c.h and generated code"
#endif
#ifdef __cplusplus
extern "C" {
#endif
struct Greeting;
typedef struct {capn_ptr p;} Greeting_ptr;
typedef struct {capn_ptr p;} Greeting_list;
struct Greeting {
capn_text text;
uint32_t timesToSay;
};
static const size_t Greeting_word_count = 1;
static const size_t Greeting_pointer_count = 1;
static const size_t Greeting_struct_bytes_count = 16;
capn_text Greeting_get_text(Greeting_ptr p);
uint32_t Greeting_get_timesToSay(Greeting_ptr p);
void Greeting_set_text(Greeting_ptr p, capn_text text);
void Greeting_set_timesToSay(Greeting_ptr p, uint32_t timesToSay);
Greeting_ptr new_Greeting(struct capn_segment*);
Greeting_list new_Greeting_list(struct capn_segment*, int len);
void read_Greeting(struct Greeting*, Greeting_ptr);
void write_Greeting(const struct Greeting*, Greeting_ptr);
void get_Greeting(struct Greeting*, Greeting_list, int i);
void set_Greeting(const struct Greeting*, Greeting_list, int i);
#ifdef __cplusplus
}
#endif
#endif