diff --git a/Makefile b/Makefile index 12e5b1c..3a82fbe 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ .PHONY: all clean test -CFLAGS=-g -Wall -Werror -fPIC -I. -Wno-unused-function +LDFLAGS=-g -Wall -Werror -fPIC +CFLAGS=-g -Wall -Werror -fPIC -I. -Wno-unused-function -ansi -pedantic all: capn.so test @@ -11,7 +12,7 @@ clean: $(CC) $(CFLAGS) -c $< -o $@ capn.so: capn-malloc.o capn-stream.o capn.o - $(CC) -shared $(CFLAGS) $^ -o $@ + $(CC) -shared $(LDFLAGS) $^ -o $@ test: capn-test ./capn-test diff --git a/capn-list.inc b/capn-list.inc index 8d7f15a..55062da 100644 --- a/capn-list.inc +++ b/capn-list.inc @@ -4,21 +4,21 @@ #define UINT_T CAT(CAT(uint, SZ), _t) #define FLIP CAT(capn_flip, SZ) -UINT_T CAT(capn_get,SZ) (const struct capn_ptr *p, int off) { +UINT_T CAT(capn_get,SZ) (capn_ptr p, int off) { char *d; - if (off >= p->size) { + if (off >= p.size) { return 0; } - switch (p->type) { + switch (p.type) { case CAPN_LIST: - if (p->datasz < SZ/8) + if (p.datasz < SZ/8) return 0; - d = p->data + off * (p->datasz + p->ptrsz); + d = p.data + off * (p.datasz + p.ptrsz); return FLIP(*(UINT_T*)d); case CAPN_PTR_LIST: - d = struct_ptr(p->seg, p->data + 8*off, SZ/8); + d = struct_ptr(p.seg, p.data + 8*off, SZ/8); if (d) { return FLIP(*(UINT_T*)d); } else { @@ -30,31 +30,31 @@ UINT_T CAT(capn_get,SZ) (const struct capn_ptr *p, int off) { } } -int CAT(capn_getv,SZ) (const struct capn_ptr *p, int off, UINT_T *to, int sz) { +int CAT(capn_getv,SZ) (capn_ptr p, int off, UINT_T *to, int sz) { int i; - if (off + sz > p->size) { - sz = p->size - off; + if (off + sz > p.size) { + sz = p.size - off; } - switch (p->type) { + switch (p.type) { case CAPN_LIST: - if (p->datasz == SZ/8 && !p->ptrsz && (SZ == 8 || CAPN_LITTLE)) { - memcpy(to, p->data + off, sz * (SZ/8)); + if (p.datasz == SZ/8 && !p.ptrsz && (SZ == 8 || CAPN_LITTLE)) { + memcpy(to, p.data + off, sz * (SZ/8)); return sz; - } else if (p->datasz < SZ/8) { + } else if (p.datasz < SZ/8) { return -1; } for (i = 0; i < sz; i++) { - char *d = p->data + (i + off) * (p->datasz + p->ptrsz); + char *d = p.data + (i + off) * (p.datasz + p.ptrsz); to[i] = FLIP(*(UINT_T*)d); } return sz; case CAPN_PTR_LIST: for (i = 0; i < sz; i++) { - char *d = struct_ptr(p->seg, p->data + 8*(i+off), SZ/8); + char *d = struct_ptr(p.seg, p.data + 8*(i+off), SZ/8); if (d) { to[i] = FLIP(*(UINT_T*)d); } else { @@ -68,22 +68,22 @@ int CAT(capn_getv,SZ) (const struct capn_ptr *p, int off, UINT_T *to, int sz) { } } -int CAT(capn_set,SZ) (struct capn_ptr *p, int off, UINT_T v) { +int CAT(capn_set,SZ) (capn_ptr p, int off, UINT_T v) { char *d; - if (off >= p->size) { + if (off >= p.size) { return -1; } - switch (p->type) { + switch (p.type) { case CAPN_LIST: - if (p->datasz < SZ/8) + if (p.datasz < SZ/8) return -1; - d = p->data + off * (p->datasz + p->ptrsz); + d = p.data + off * (p.datasz + p.ptrsz); *(UINT_T*) d = FLIP(v); return 0; case CAPN_PTR_LIST: - d = struct_ptr(p->seg, p->data + 8*off, SZ/8); + d = struct_ptr(p.seg, p.data + 8*off, SZ/8); if (!d) { return -1; } @@ -95,31 +95,31 @@ int CAT(capn_set,SZ) (struct capn_ptr *p, int off, UINT_T v) { } } -int CAT(capn_setv,SZ) (struct capn_ptr *p, int off, const UINT_T *from, int sz) { +int CAT(capn_setv,SZ) (capn_ptr p, int off, const UINT_T *from, int sz) { int i; - if (off + sz > p->size) { - sz = p->size - off; + if (off + sz > p.size) { + sz = p.size - off; } - switch (p->type) { + switch (p.type) { case CAPN_LIST: - if (p->datasz == SZ/8 && !p->ptrsz && (SZ == 8 || CAPN_LITTLE)) { - memcpy(p->data + off, from, sz * (SZ/8)); + if (p.datasz == SZ/8 && !p.ptrsz && (SZ == 8 || CAPN_LITTLE)) { + memcpy(p.data + off, from, sz * (SZ/8)); return sz; - } else if (p->datasz < SZ/8) { + } else if (p.datasz < SZ/8) { return -1; } for (i = 0; i < sz; i++) { - char *d = p->data + (i + off) * (p->datasz + p->ptrsz); + char *d = p.data + (i + off) * (p.datasz + p.ptrsz); *(UINT_T*) d = FLIP(from[i]); } return sz; case CAPN_PTR_LIST: for (i = 0; i < sz; i++) { - char *d = struct_ptr(p->seg, p->data + 8*(i+off), SZ/8); + char *d = struct_ptr(p.seg, p.data + 8*(i+off), SZ/8); if (d) { *(UINT_T*) d = FLIP(from[i]); } else { diff --git a/capn-malloc.c b/capn-malloc.c index 9355b02..558b02b 100644 --- a/capn-malloc.c +++ b/capn-malloc.c @@ -37,5 +37,3 @@ void capn_free_malloc(struct capn *c) { s = n; } } - - diff --git a/capn-test.cpp b/capn-test.cpp index 5fb54d3..2dc658c 100644 --- a/capn-test.cpp +++ b/capn-test.cpp @@ -6,15 +6,10 @@ static int g_AddTag = 1; #include "capn.c" #include "capn-malloc.c" -typedef uint64_t word; - template union AlignedData { - // Useful for declaring static constant data blobs as an array of bytes, but forcing those - // bytes to be word-aligned. - - uint8_t bytes[wordCount * sizeof(word)]; - word words[wordCount]; + uint8_t bytes[wordCount * 8]; + uint64_t words[wordCount]; }; class Session { @@ -51,25 +46,21 @@ TEST(WireFormat, SimpleRawDataStruct) { EXPECT_EQ(1, ctx.segnum); EXPECT_EQ(0, seg.id); - struct capn_ptr root = capn_root(&ctx); - EXPECT_EQ(CAPN_PTR_LIST, root.type); - EXPECT_EQ(1, root.size); - - struct capn_ptr ptr = capn_getp(&root, 0); + struct capn_ptr ptr = capn_get_root(&ctx); EXPECT_EQ(CAPN_STRUCT, ptr.type); EXPECT_EQ(8, ptr.datasz); EXPECT_EQ(0, ptr.ptrsz); - EXPECT_EQ(UINT64_C(0xefcdab8967452301), capn_read64(&ptr, 0)); - EXPECT_EQ(UINT64_C(0), capn_read64(&ptr, 8)); - EXPECT_EQ(UINT32_C(0x67452301), capn_read32(&ptr, 0)); - EXPECT_EQ(UINT32_C(0xefcdab89), capn_read32(&ptr, 4)); - EXPECT_EQ(UINT32_C(0), capn_read32(&ptr, 8)); - EXPECT_EQ(UINT16_C(0x2301), capn_read16(&ptr, 0)); - EXPECT_EQ(UINT16_C(0x6745), capn_read16(&ptr, 2)); - EXPECT_EQ(UINT16_C(0xab89), capn_read16(&ptr, 4)); - EXPECT_EQ(UINT16_C(0xefcd), capn_read16(&ptr, 6)); - EXPECT_EQ(UINT16_C(0), capn_read16(&ptr, 8)); + EXPECT_EQ(UINT64_C(0xefcdab8967452301), capn_read64(ptr, 0)); + EXPECT_EQ(UINT64_C(0), capn_read64(ptr, 8)); + EXPECT_EQ(UINT32_C(0x67452301), capn_read32(ptr, 0)); + EXPECT_EQ(UINT32_C(0xefcdab89), capn_read32(ptr, 4)); + EXPECT_EQ(UINT32_C(0), capn_read32(ptr, 8)); + EXPECT_EQ(UINT16_C(0x2301), capn_read16(ptr, 0)); + EXPECT_EQ(UINT16_C(0x6745), capn_read16(ptr, 2)); + EXPECT_EQ(UINT16_C(0xab89), capn_read16(ptr, 4)); + EXPECT_EQ(UINT16_C(0xefcd), capn_read16(ptr, 6)); + EXPECT_EQ(UINT16_C(0), capn_read16(ptr, 8)); } static const AlignedData<2> SUBSTRUCT_DEFAULT = {{0,0,0,0,1,0,0,0, 0,0,0,0,0,0,0,0}}; @@ -77,144 +68,142 @@ static const AlignedData<2> STRUCTLIST_ELEMENT_SUBSTRUCT_DEFAULT = {{0,0,0,0,1,0,0,0, 0,0,0,0,0,0,0,0}}; static void setupStruct(struct capn *ctx) { - struct capn_ptr root = capn_root(ctx); - EXPECT_EQ(CAPN_PTR_LIST, root.type); - EXPECT_EQ(1, root.size); + struct capn_ptr root = capn_new_root(ctx); + ASSERT_EQ(CAPN_PTR_LIST, root.type); + ASSERT_EQ(1, root.size); struct capn_ptr ptr = capn_new_struct(root.seg, 16, 4); - EXPECT_EQ(CAPN_STRUCT, ptr.type); + ASSERT_EQ(CAPN_STRUCT, ptr.type); EXPECT_EQ(16, ptr.datasz); EXPECT_EQ(32, ptr.ptrsz); - EXPECT_EQ(0, capn_setp(&root, 0, &ptr)); + EXPECT_EQ(0, capn_setp(root, 0, ptr)); - EXPECT_EQ(0, capn_write64(&ptr, 0, UINT64_C(0x1011121314151617))); - EXPECT_EQ(0, capn_write32(&ptr, 8, UINT32_C(0x20212223))); - EXPECT_EQ(0, capn_write16(&ptr, 12, UINT16_C(0x3031))); - EXPECT_EQ(0, capn_write8(&ptr, 14, 0x40)); - EXPECT_EQ(0, capn_write8(&ptr, 15, (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2))); + EXPECT_EQ(0, capn_write64(ptr, 0, UINT64_C(0x1011121314151617))); + EXPECT_EQ(0, capn_write32(ptr, 8, UINT32_C(0x20212223))); + EXPECT_EQ(0, capn_write16(ptr, 12, UINT16_C(0x3031))); + EXPECT_EQ(0, capn_write8(ptr, 14, 0x40)); + EXPECT_EQ(0, capn_write8(ptr, 15, (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2))); struct capn_ptr subStruct = capn_new_struct(ptr.seg, 8, 0); - EXPECT_EQ(CAPN_STRUCT, subStruct.type); + ASSERT_EQ(CAPN_STRUCT, subStruct.type); EXPECT_EQ(8, subStruct.datasz); EXPECT_EQ(0, subStruct.ptrsz); - EXPECT_EQ(0, capn_write32(&subStruct, 0, 123)); - EXPECT_NE(0, capn_write32(&subStruct, 8, 124)); - EXPECT_EQ(0, capn_setp(&ptr, 0, &subStruct)); + EXPECT_EQ(0, capn_write32(subStruct, 0, 123)); + EXPECT_NE(0, capn_write32(subStruct, 8, 124)); + EXPECT_EQ(0, capn_setp(ptr, 0, subStruct)); struct capn_ptr list = capn_new_list(ptr.seg, 3, 4, 0); - EXPECT_EQ(CAPN_LIST, list.type); + ASSERT_EQ(CAPN_LIST, list.type); EXPECT_EQ(3, list.size); EXPECT_EQ(4, list.datasz); - EXPECT_EQ(0, capn_set32(&list, 0, 200)); - EXPECT_EQ(0, capn_set32(&list, 1, 201)); - EXPECT_EQ(0, capn_set32(&list, 2, 202)); - EXPECT_NE(0, capn_set32(&list, 3, 203)); - EXPECT_NE(0, capn_set64(&list, 0, 405)); - EXPECT_EQ(0, capn_setp(&ptr, 1, &list)); + EXPECT_EQ(0, capn_set32(list, 0, 200)); + EXPECT_EQ(0, capn_set32(list, 1, 201)); + EXPECT_EQ(0, capn_set32(list, 2, 202)); + EXPECT_NE(0, capn_set32(list, 3, 203)); + EXPECT_NE(0, capn_set64(list, 0, 405)); + EXPECT_EQ(0, capn_setp(ptr, 1, list)); list = capn_new_list(ptr.seg, 4, 4, 1); - EXPECT_EQ(CAPN_LIST, list.type); + ASSERT_EQ(CAPN_LIST, list.type); EXPECT_EQ(4, list.size); EXPECT_EQ(8, list.datasz); EXPECT_EQ(8, list.ptrsz); - EXPECT_EQ(0, capn_setp(&ptr, 2, &list)); + EXPECT_EQ(0, capn_setp(ptr, 2, list)); for (int i = 0; i < 4; i++) { - struct capn_ptr element = capn_getp(&list, i); - EXPECT_EQ(CAPN_LIST_MEMBER, element.type); + struct capn_ptr element = capn_getp(list, i); + ASSERT_EQ(CAPN_STRUCT, element.type); + EXPECT_EQ(1, element.is_list_member); EXPECT_EQ(8, element.datasz); EXPECT_EQ(8, element.ptrsz); - EXPECT_EQ(0, capn_write32(&element, 0, 300+i)); + EXPECT_EQ(0, capn_write32(element, 0, 300+i)); struct capn_ptr subelement = capn_new_struct(element.seg, 8, 0); - EXPECT_EQ(CAPN_STRUCT, subelement.type); + ASSERT_EQ(CAPN_STRUCT, subelement.type); EXPECT_EQ(8, subelement.datasz); EXPECT_EQ(0, subelement.ptrsz); - EXPECT_EQ(0, capn_write32(&subelement, 0, 400+i)); - EXPECT_EQ(0, capn_setp(&element, 0, &subelement)); + EXPECT_EQ(0, capn_write32(subelement, 0, 400+i)); + EXPECT_EQ(0, capn_setp(element, 0, subelement)); } list = capn_new_ptr_list(ptr.seg, 5); - EXPECT_EQ(CAPN_PTR_LIST, list.type); + ASSERT_EQ(CAPN_PTR_LIST, list.type); EXPECT_EQ(5, list.size); - EXPECT_EQ(0, capn_setp(&ptr, 3, &list)); + EXPECT_EQ(0, capn_setp(ptr, 3, list)); for (int i = 0; i < 5; i++) { struct capn_ptr element = capn_new_list(list.seg, i+1, 2, 0); - EXPECT_EQ(CAPN_LIST, element.type); + ASSERT_EQ(CAPN_LIST, element.type); EXPECT_EQ(i+1, element.size); EXPECT_EQ(2, element.datasz); EXPECT_EQ(0, element.ptrsz); - EXPECT_EQ(0, capn_setp(&list, i, &element)); + EXPECT_EQ(0, capn_setp(list, i, element)); for (int j = 0; j <= i; j++) { - EXPECT_EQ(0, capn_set16(&element, j, 500+j)); + EXPECT_EQ(0, capn_set16(element, j, 500+j)); } } } static void checkStruct(struct capn *ctx) { - struct capn_ptr root = capn_root(ctx); - EXPECT_EQ(CAPN_PTR_LIST, root.type); - EXPECT_EQ(1, root.size); - - struct capn_ptr ptr = capn_getp(&root, 0); + struct capn_ptr ptr = capn_get_root(ctx); EXPECT_EQ(CAPN_STRUCT, ptr.type); EXPECT_EQ(16, ptr.datasz); EXPECT_EQ(32, ptr.ptrsz); - EXPECT_EQ(UINT64_C(0x1011121314151617), capn_read64(&ptr, 0)); - EXPECT_EQ(UINT32_C(0x20212223), capn_read32(&ptr, 8)); - EXPECT_EQ(0x3031, capn_read16(&ptr, 12)); - EXPECT_EQ(0x40, capn_read8(&ptr, 14)); - EXPECT_EQ((1 << 6) | (1 << 5) | (1 << 4) | (1 << 2), capn_read8(&ptr, 15)); + EXPECT_EQ(UINT64_C(0x1011121314151617), capn_read64(ptr, 0)); + EXPECT_EQ(UINT32_C(0x20212223), capn_read32(ptr, 8)); + EXPECT_EQ(0x3031, capn_read16(ptr, 12)); + EXPECT_EQ(0x40, capn_read8(ptr, 14)); + EXPECT_EQ((1 << 6) | (1 << 5) | (1 << 4) | (1 << 2), capn_read8(ptr, 15)); - struct capn_ptr subStruct = capn_getp(&ptr, 0); + struct capn_ptr subStruct = capn_getp(ptr, 0); EXPECT_EQ(CAPN_STRUCT, subStruct.type); EXPECT_EQ(8, subStruct.datasz); EXPECT_EQ(0, subStruct.ptrsz); - EXPECT_EQ(123, capn_read32(&subStruct, 0)); + EXPECT_EQ(123, capn_read32(subStruct, 0)); - struct capn_ptr list = capn_getp(&ptr, 1); + struct capn_ptr list = capn_getp(ptr, 1); EXPECT_EQ(CAPN_LIST, list.type); EXPECT_EQ(3, list.size); EXPECT_EQ(4, list.datasz); EXPECT_EQ(0, list.ptrsz); - EXPECT_EQ(200, capn_get32(&list, 0)); - EXPECT_EQ(201, capn_get32(&list, 1)); - EXPECT_EQ(202, capn_get32(&list, 2)); - EXPECT_EQ(0, capn_get32(&list, 3)); - EXPECT_EQ(0, capn_get64(&list, 0)); - EXPECT_EQ(201, capn_get8(&list, 1)); - EXPECT_EQ(202, capn_get16(&list, 2)); + EXPECT_EQ(200, capn_get32(list, 0)); + EXPECT_EQ(201, capn_get32(list, 1)); + EXPECT_EQ(202, capn_get32(list, 2)); + EXPECT_EQ(0, capn_get32(list, 3)); + EXPECT_EQ(0, capn_get64(list, 0)); + EXPECT_EQ(201, capn_get8(list, 1)); + EXPECT_EQ(202, capn_get16(list, 2)); - list = capn_getp(&ptr, 2); + list = capn_getp(ptr, 2); EXPECT_EQ(CAPN_LIST, list.type); EXPECT_EQ(4, list.size); EXPECT_EQ(8, list.datasz); EXPECT_EQ(8, list.ptrsz); for (int i = 0; i < 4; i++) { - struct capn_ptr element = capn_getp(&list, i); - EXPECT_EQ(CAPN_LIST_MEMBER, element.type); + struct capn_ptr element = capn_getp(list, i); + EXPECT_EQ(CAPN_STRUCT, element.type); + EXPECT_EQ(1, element.is_list_member); EXPECT_EQ(8, element.datasz); EXPECT_EQ(8, element.ptrsz); - EXPECT_EQ(300+i, capn_read32(&element,0)); + EXPECT_EQ(300+i, capn_read32(element,0)); - struct capn_ptr subelement = capn_getp(&element, 0); + struct capn_ptr subelement = capn_getp(element, 0); EXPECT_EQ(CAPN_STRUCT, subelement.type); EXPECT_EQ(8, subelement.datasz); EXPECT_EQ(0, subelement.ptrsz); - EXPECT_EQ(400+i, capn_read32(&subelement, 0)); + EXPECT_EQ(400+i, capn_read32(subelement, 0)); } - list = capn_getp(&ptr, 3); + list = capn_getp(ptr, 3); EXPECT_EQ(CAPN_PTR_LIST, list.type); EXPECT_EQ(5, list.size); for (int i = 0; i < 5; i++) { - struct capn_ptr element = capn_getp(&list, i); + struct capn_ptr element = capn_getp(list, i); EXPECT_EQ(CAPN_LIST, element.type); EXPECT_EQ(i+1, element.size); EXPECT_EQ(2, element.datasz); EXPECT_EQ(0, element.ptrsz); for (int j = 0; j <= i; j++) { - EXPECT_EQ(500+j, capn_get16(&element, j)); + EXPECT_EQ(500+j, capn_get16(element, j)); } } } diff --git a/capn.c b/capn.c index b65bc60..a63b6c0 100644 --- a/capn.c +++ b/capn.c @@ -8,6 +8,7 @@ #define STRUCT_PTR 0 #define LIST_PTR 1 #define FAR_PTR 2 +#define DOUBLE_PTR 6 #define VOID_LIST 0 #define BIT_1_LIST 1 @@ -228,6 +229,42 @@ static struct capn_segment *lookup_segment(struct capn* c, struct capn_segment * return s; } +static uint64_t lookup_double(struct capn_segment **s, char **d, uint64_t val) { + uint64_t far, tag; + uint32_t off = (U32(val) >> 3) * 8; + char *p; + + if ((*s = lookup_segment((*s)->capn, *s, U32(val >> 32))) == NULL) { + return 0; + } + + p = (*s)->data + off; + if (off + 16 > (*s)->len) { + return 0; + } + + far = capn_flip64(*(uint64_t*) p); + tag = capn_flip64(*(uint64_t*) (p+8)); + + /* the far tag should not be another double, and the tag + * should be struct/list and have no offset */ + if ((far&7) != FAR_PTR || U32(tag) > LIST_PTR) { + return 0; + } + + if ((*s = lookup_segment((*s)->capn, *s, U32(far >> 32))) == NULL) { + return 0; + } + + /* -8 because far pointers reference from the start of + * the segment, but offsets reference the end of the + * pointer data. Here *d points to where an equivalent + * ptr would be. + */ + *d = (*s)->data - 8; + return U64(U32(far) >> 3 << 2) | tag; +} + static uint64_t lookup_far(struct capn_segment **s, char **d, uint64_t val) { uint32_t off = (U32(val) >> 3) * 8; @@ -235,50 +272,25 @@ static uint64_t lookup_far(struct capn_segment **s, char **d, uint64_t val) { return 0; } - if (val & 4) { - /* Double far pointer */ - uint64_t far, tag; - char *p = (*s)->data + off; - if (off + 16 > (*s)->len) { - return 0; - } - - far = capn_flip64(*(uint64_t*) p); - tag = capn_flip64(*(uint64_t*) (p+8)); - - /* the far tag should not be another double, and the tag - * should be struct/list and have no offset */ - if ((far&7) != FAR_PTR || U32(tag) > LIST_PTR) { - return 0; - } - - if ((*s = lookup_segment((*s)->capn, *s, U32(far >> 32))) == NULL) { - return 0; - } - - /* -8 because far pointers reference from the start of - * the segment, but offsets reference the end of the - * pointer data. Here *d points to where an equivalent - * ptr would be. - */ - *d = (*s)->data - 8; - return U64(U32(far) >> 3 << 2) | tag; - } else { - if (off + 8 > (*s)->len) { - return 0; - } - - *d = (*s)->data + off; - return capn_flip64(*(uint64_t*) *d); + if (off + 8 > (*s)->len) { + return 0; } + + *d = (*s)->data + off; + return capn_flip64(*(uint64_t*)*d); } static char *struct_ptr(struct capn_segment *s, char *d, int minsz) { uint64_t val = capn_flip64(*(uint64_t*)d); uint16_t datasz; - if ((val&3) == FAR_PTR) { + switch (val&7) { + case FAR_PTR: val = lookup_far(&s, &d, val); + break; + case DOUBLE_PTR: + val = lookup_double(&s, &d, val); + break; } datasz = U16(val >> 32); @@ -291,15 +303,21 @@ static char *struct_ptr(struct capn_segment *s, char *d, int minsz) { return NULL; } -static struct capn_ptr read_ptr(struct capn_segment *s, char *d) { - char *e; - struct capn_ptr ret; +static capn_ptr read_ptr(struct capn_segment *s, char *d) { + capn_ptr ret = {CAPN_NULL}; uint64_t val; + char *e; val = capn_flip64(*(uint64_t*) d); - if ((val&3) == FAR_PTR) { + switch (val&7) { + case FAR_PTR: val = lookup_far(&s, &d, val); + ret.has_ptr_tag = (U32(val) >> 2) == 0; + break; + case DOUBLE_PTR: + val = lookup_double(&s, &d, val); + break; } d += (I32(U32(val)) >> 2) * 8 + 8; @@ -310,15 +328,12 @@ static struct capn_ptr read_ptr(struct capn_segment *s, char *d) { if ((val&3) == STRUCT_PTR) { ret.type = CAPN_STRUCT; - ret.size = 0; ret.datasz = U32(U16(val >> 32)) * 8; ret.ptrsz = U32(U16(val >> 48)) * 8; e = d + ret.size * (ret.datasz + ret.ptrsz); } else { ret.type = CAPN_LIST; ret.size = val >> 35; - ret.datasz = 0; - ret.ptrsz = 0; switch ((val >> 32) & 7) { case VOID_LIST: @@ -362,6 +377,7 @@ static struct capn_ptr read_ptr(struct capn_segment *s, char *d) { ret.datasz = U32(U16(val >> 32)) * 8; ret.ptrsz = U32(U16(val >> 48)) * 8; ret.size = U32(val) >> 2; + ret.has_composite_tag = 1; if ((ret.datasz + ret.ptrsz) * ret.size != e - d) { goto err; @@ -381,76 +397,77 @@ err: return ret; } -struct capn_ptr capn_getp(const struct capn_ptr *p, int off) { - struct capn_ptr ret; - - switch (p->type) { +capn_ptr capn_getp(capn_ptr p, int off) { + switch (p.type) { case CAPN_LIST: /* Return an inner pointer */ - if (off >= p->size) { + if (off < p.size) { + capn_ptr ret = {CAPN_NULL}; + ret.type = CAPN_STRUCT; + ret.is_list_member = 1; + ret.data = p.data + off * (p.datasz + p.ptrsz); + ret.seg = p.seg; + ret.datasz = p.datasz; + ret.ptrsz = p.ptrsz; + return ret; + } else { goto err; } - ret = *p; - ret.type = CAPN_LIST_MEMBER; - ret.data += off * (p->datasz + p->ptrsz); - ret.size = 0; - return ret; case CAPN_STRUCT: - case CAPN_LIST_MEMBER: off *= 8; - if (off >= p->ptrsz) { + if (off >= p.ptrsz) { goto err; } - return read_ptr(p->seg, p->data + p->datasz + off); + return read_ptr(p.seg, p.data + p.datasz + off); case CAPN_PTR_LIST: - if (off >= p->size) { + if (off >= p.size) { goto err; } - return read_ptr(p->seg, p->data + off * 8); + return read_ptr(p.seg, p.data + off * 8); default: goto err; } err: - memset(&ret, 0, sizeof(ret)); - return ret; + memset(&p, 0, sizeof(p)); + return p; } -static uint64_t ptr_value(const struct capn_ptr *p, int off) { +static uint64_t ptr_value(capn_ptr p, int off) { uint64_t val = U64(U32(I32(off/8) << 2)); - switch (p->type) { + switch (p.type) { case CAPN_STRUCT: - val |= STRUCT_PTR | (U64(p->datasz/8) << 32) | (U64(p->ptrsz/8) << 48); + val |= STRUCT_PTR | (U64(p.datasz/8) << 32) | (U64(p.ptrsz/8) << 48); break; case CAPN_LIST: - if (p->ptrsz || p->datasz > 8) { - val |= LIST_PTR | (U64(COMPOSITE_LIST) << 32) | (U64(p->size * (p->datasz + p->ptrsz)/8) << 35); - } else if (p->datasz == 8) { - val |= LIST_PTR | (U64(BYTE_8_LIST) << 32) | (U64(p->size) << 35); - } else if (p->datasz == 4) { - val |= LIST_PTR | (U64(BYTE_4_LIST) << 32) | (U64(p->size) << 35); - } else if (p->datasz == 2) { - val |= LIST_PTR | (U64(BYTE_2_LIST) << 32) | (U64(p->size) << 35); - } else if (p->datasz == 1) { - val |= LIST_PTR | (U64(BYTE_1_LIST) << 32) | (U64(p->size) << 35); + if (p.has_composite_tag) { + val |= LIST_PTR | (U64(COMPOSITE_LIST) << 32) | (U64(p.size * (p.datasz + p.ptrsz)/8) << 35); + } else if (p.datasz == 8) { + val |= LIST_PTR | (U64(BYTE_8_LIST) << 32) | (U64(p.size) << 35); + } else if (p.datasz == 4) { + val |= LIST_PTR | (U64(BYTE_4_LIST) << 32) | (U64(p.size) << 35); + } else if (p.datasz == 2) { + val |= LIST_PTR | (U64(BYTE_2_LIST) << 32) | (U64(p.size) << 35); + } else if (p.datasz == 1) { + val |= LIST_PTR | (U64(BYTE_1_LIST) << 32) | (U64(p.size) << 35); } else { - val |= LIST_PTR | (U64(VOID_LIST) << 32) | (U64(p->size) << 35); + val |= LIST_PTR | (U64(VOID_LIST) << 32) | (U64(p.size) << 35); } break; case CAPN_BIT_LIST: - val |= LIST_PTR | (U64(BIT_1_LIST) << 32) | (U64(p->size) << 35); + val |= LIST_PTR | (U64(BIT_1_LIST) << 32) | (U64(p.size) << 35); break; case CAPN_PTR_LIST: - val |= LIST_PTR | (U64(PTR_LIST) << 32) | (U64(p->size) << 35); + val |= LIST_PTR | (U64(PTR_LIST) << 32) | (U64(p.size) << 35); break; default: @@ -466,57 +483,50 @@ static void write_far_ptr(char *d, struct capn_segment *s, char *tgt) { } static void write_double_far(char *d, struct capn_segment *s, char *tgt) { - *(uint64_t*) d = capn_flip64(FAR_PTR | 4 | U64(tgt - s->data) | (U64(s->id) << 32)); + *(uint64_t*) d = capn_flip64(DOUBLE_PTR | U64(tgt - s->data) | (U64(s->id) << 32)); } -static void write_ptr_tag(char *d, const struct capn_ptr *p, int off) { +static void write_ptr_tag(char *d, capn_ptr p, int off) { *(uint64_t*) d = ptr_value(p, off); } -static int has_tag(const struct capn_ptr* p, const char *pdata) { - const char *d = pdata - 8; - return d >= p->seg->data && ptr_value(p, 0) == *(uint64_t*) d; -} - #define NEED_TO_COPY 1 -static int write_ptr_no_copy(struct capn_segment *s, char *d, const struct capn_ptr *p) { - /* note p->seg can be NULL if its a ptr to static data */ - char *pdata = p->data; +static int write_ptr_no_copy(struct capn_segment *s, char *d, capn_ptr p) { + /* note p.seg can be NULL if its a ptr to static data */ + char *pdata = p.data; - /* TODO: how to distinguish between 8 byte list and a composite - * list with ptrs == 0, data == 1? */ - if (p->type == CAPN_LIST && (p->ptrsz || p->datasz > 8)) { + if (p.has_composite_tag) { pdata -= 8; } - if (!p || p->type == CAPN_NULL) { + if (p.type == CAPN_NULL) { *(uint64_t*) d = 0; return 0; - } else if (!p->seg || p->seg->capn != s->capn || p->type == CAPN_LIST_MEMBER) { + } else if (!p.seg || p.seg->capn != s->capn || p.is_list_member) { return NEED_TO_COPY; - } else if (p->seg == s) { + } else if (p.seg == s) { write_ptr_tag(d, p, pdata - d - 8); return 0; } else { /* if its in the same context we can create a far pointer */ - if (has_tag(p, pdata)) { + if (p.has_ptr_tag) { /* By lucky chance, the data has a tag in front * of it. This happens when new_object had to move * the data to a new segment. */ - write_far_ptr(d, p->seg, pdata-8); + write_far_ptr(d, p.seg, pdata-8); return 0; - } else if (p->seg->len + 8 <= p->seg->cap) { + } else if (p.seg->len + 8 <= p.seg->cap) { /* The target segment has enough room for tag */ - char *t = p->seg->data + p->seg->len; + char *t = p.seg->data + p.seg->len; write_ptr_tag(t, p, pdata - t - 8); - write_far_ptr(d, p->seg, t); - p->seg->len += 8; + write_far_ptr(d, p.seg, t); + p.seg->len += 8; return 0; } else { @@ -535,7 +545,7 @@ static int write_ptr_no_copy(struct capn_segment *s, char *d, const struct capn_ if (!t) return -1; } - write_far_ptr(t, p->seg, pdata); + write_far_ptr(t, p.seg, pdata); write_ptr_tag(t+8, p, 0); write_double_far(d, s, t); return 0; @@ -546,6 +556,7 @@ static int write_ptr_no_copy(struct capn_segment *s, char *d, const struct capn_ struct copy { struct capn_tree hdr; struct capn_ptr to, from; + char *fdata; int fsize; }; @@ -556,7 +567,6 @@ static int data_size(const struct capn_ptr *p) { case CAPN_PTR_LIST: return p->size*8; case CAPN_STRUCT: - case CAPN_LIST_MEMBER: return p->datasz + p->ptrsz; case CAPN_LIST: return p->size * (p->datasz + p->ptrsz); @@ -565,31 +575,41 @@ static int data_size(const struct capn_ptr *p) { } } -static struct capn_ptr new_clone(struct capn_segment *s, const struct capn_ptr *p) { - switch (p->type) { - case CAPN_LIST_MEMBER: +static capn_ptr new_clone(struct capn_segment *s, capn_ptr p) { + switch (p.type) { case CAPN_STRUCT: - return capn_new_struct(s, p->datasz, p->ptrsz); + return capn_new_struct(s, p.datasz, p.ptrsz); case CAPN_PTR_LIST: - return capn_new_ptr_list(s, p->size); + return capn_new_ptr_list(s, p.size); case CAPN_BIT_LIST: - return capn_new_bit_list(s, p->size); + return capn_new_bit_list(s, p.size); case CAPN_LIST: - return capn_new_list(s, p->size, p->datasz, p->ptrsz); + return capn_new_list(s, p.size, p.datasz, p.ptrsz); default: - return *p; + return p; } } static int is_ptr_equal(const struct capn_ptr *a, const struct capn_ptr *b) { - return a->data == b->data && a->type == b->type && a->size == b->size && a->datasz == b->datasz && a->ptrsz == b->ptrsz; + return a->data == b->data + && a->type == b->type + && a->size == b->size + && a->datasz == b->datasz + && a->ptrsz == b->ptrsz + && a->has_composite_tag == b->has_composite_tag; } static int write_copy(struct capn_segment *seg, char *data, struct capn_ptr *t, struct capn_ptr *f, int *dep, int zeros) { struct capn *c = seg->capn; struct copy *cp = (struct copy*) c->copy; - int sz = data_size(f); + int fsize = data_size(f); + char *fdata = f->data; + + if (f->has_composite_tag) { + fsize += 8; + fdata -= 8; + } /* We always copy list members as it would otherwise be an * overlapped pointer (the data is owned by the inclosing list). @@ -599,14 +619,14 @@ static int write_copy(struct capn_segment *seg, char *data, struct capn_ptr *t, * pointers. */ - while (c && sz) { - if (f->data + sz <= cp->from.data) { + while (c && fsize) { + if (fdata + fsize <= cp->fdata) { cp = (struct copy*) cp->hdr.link[0]; - } else if (cp->from.data + cp->fsize <= f->data) { + } else if (cp->fdata + cp->fsize <= fdata) { cp = (struct copy*) cp->hdr.link[1]; } else if (is_ptr_equal(f, &cp->from)) { /* we already have a copy so just point to that */ - return write_ptr_no_copy(seg, data, &cp->from); + return write_ptr_no_copy(seg, data, cp->from); } else { /* pointer to overlapped data */ return -1; @@ -614,11 +634,11 @@ static int write_copy(struct capn_segment *seg, char *data, struct capn_ptr *t, } /* no copy - have to copy */ - *t = new_clone(seg, f); + *t = new_clone(seg, *f); /* add the copy to the copy tree so we can look for overlapping * source pointers and handle recursive structures */ - if (sz && f->type != CAPN_LIST_MEMBER) { + if (fsize && !f->is_list_member) { struct copy *n; struct capn_segment *cs = c->copylist; @@ -636,18 +656,15 @@ static int write_copy(struct capn_segment *seg, char *data, struct capn_ptr *t, n = (struct copy*) (cs->data + cs->len); cs->len += sizeof(*n); - n->hdr.parent = &cp->hdr; n->from = *f; n->to = *t; - n->fsize = sz; + n->fdata = fdata; + n->fsize = fsize; - if (f->data < cp->from.data) { - cp->hdr.link[0] = &n->hdr; - } else { - cp->hdr.link[1] = &n->hdr; - } + n->hdr.parent = &cp->hdr; + cp->hdr.link[cp->fdata < f->data] = &n->hdr; - seg->capn->copy = insert_rebalance(seg->capn->copy, &n->hdr); + seg->capn->copy = capn_tree_insert(seg->capn->copy, &n->hdr); } /* minimize the number of types the main copy routine has to @@ -656,7 +673,6 @@ static int write_copy(struct capn_segment *seg, char *data, struct capn_ptr *t, * be valid */ switch (t->type) { case CAPN_STRUCT: - case CAPN_LIST_MEMBER: if (t->datasz) { memcpy(t->data, f->data, t->datasz - zeros); t->data += t->datasz; @@ -700,28 +716,28 @@ static int write_copy(struct capn_segment *seg, char *data, struct capn_ptr *t, #define MAX_COPY_DEPTH 32 -int write_ptr(struct capn_ptr *p, int off, const struct capn_ptr *tgt, int zeros) { +int write_ptr(capn_ptr p, int off, struct capn_ptr tgt, int zeros) { struct capn_ptr to[MAX_COPY_DEPTH], from[MAX_COPY_DEPTH]; char *data; int err, dep; - switch (p->type) { + switch (p.type) { case CAPN_LIST: - if (off < p->size && (tgt->type == CAPN_STRUCT || tgt->type == CAPN_LIST_MEMBER)) { + if (off < p.size && tgt.type == CAPN_STRUCT) { struct capn_ptr *f, *t; char *d; int sz; /* copy struct data */ - d = p->data + off * (p->datasz + p->ptrsz); - sz = min(p->datasz, tgt->datasz); - memcpy(d, tgt->data, sz); - memset(d + sz, 0, p->datasz - sz); + d = p.data + off * (p.datasz + p.ptrsz); + sz = min(p.datasz, tgt.datasz); + memcpy(d, tgt.data, sz); + memset(d + sz, 0, p.datasz - sz); /* reset excess pointers */ - d += p->datasz; - sz = min(p->ptrsz, tgt->ptrsz); - memset(d + sz, 0, p->ptrsz - sz); + d += p.datasz; + sz = min(p.ptrsz, tgt.ptrsz); + memset(d + sz, 0, p.ptrsz - sz); /* create a pointer list for the main loop to copy */ dep = 1; @@ -729,14 +745,14 @@ int write_ptr(struct capn_ptr *p, int off, const struct capn_ptr *tgt, int zeros /* main copy loop doesn't need the other fields * for ptr lists */ f = &from[0]; - f->data = tgt->data + tgt->datasz; - f->seg = tgt->seg; + f->data = tgt.data + tgt.datasz; + f->seg = tgt.seg; t = &to[0]; t->type = CAPN_PTR_LIST; t->data = d; t->size = sz/8; - t->seg = p->seg; + t->seg = p.seg; goto copy_loop; } else { @@ -744,24 +760,23 @@ int write_ptr(struct capn_ptr *p, int off, const struct capn_ptr *tgt, int zeros } case CAPN_PTR_LIST: - if (off >= p->size) + if (off >= p.size) return -1; - data = p->data + off * 8; + data = p.data + off * 8; break; case CAPN_STRUCT: - case CAPN_LIST_MEMBER: off *= 8; - if (off >= p->ptrsz) + if (off >= p.ptrsz) return -1; - data = p->data + p->datasz + off; + data = p.data + p.datasz + off; break; default: return -1; } - err = write_ptr_no_copy(p->seg, data, tgt); + err = write_ptr_no_copy(p.seg, data, tgt); if (err != NEED_TO_COPY) return err; @@ -774,8 +789,8 @@ int write_ptr(struct capn_ptr *p, int off, const struct capn_ptr *tgt, int zeros */ dep = 0; - from[0] = *tgt; - if (write_copy(p->seg, data, to, from, &dep, zeros)) + from[0] = tgt; + if (write_copy(p.seg, data, to, from, &dep, zeros)) return -1; copy_loop: @@ -797,7 +812,8 @@ copy_loop: case CAPN_LIST: *fn = *fc; *tn = *tc; - fn->type = tn->type = CAPN_LIST_MEMBER; + fn->type = tn->type = CAPN_STRUCT; + fn->is_list_member = tn->is_list_member = 1; fn->size = tn->size = 0; if (write_copy(tc->seg, tc->data, tn, fn, &dep, 0)) @@ -825,42 +841,42 @@ copy_loop: return 0; } -int capn_setp(struct capn_ptr *p, int off, const struct capn_ptr *tgt) { +int capn_setp(capn_ptr p, int off, capn_ptr tgt) { return write_ptr(p, off, tgt, 0); } -int capn_read1(const struct capn_ptr *p, int off, uint8_t *data, int sz) { +int capn_read1(capn_ptr p, int off, uint8_t *data, int sz) { /* Note we only support aligned reads */ int bsz; - if (p->type != CAPN_BIT_LIST || (off & 7) != 0) + if (p.type != CAPN_BIT_LIST || (off & 7) != 0) return -1; bsz = (sz + 7) / 8; off /= 8; - if (off + sz > p->datasz) { - memcpy(data, p->data + off, p->datasz - off); - return p->size - off*8; + if (off + sz > p.datasz) { + memcpy(data, p.data + off, p.datasz - off); + return p.size - off*8; } else { - memcpy(data, p->data + off, bsz); + memcpy(data, p.data + off, bsz); return sz; } } -int capn_write1(struct capn_ptr *p, int off, const uint8_t *data, int sz) { +int capn_write1(capn_ptr p, int off, const uint8_t *data, int sz) { /* Note we only support aligned writes */ int bsz; - if (p->type != CAPN_BIT_LIST || (off & 7) != 0) + if (p.type != CAPN_BIT_LIST || (off & 7) != 0) return -1; bsz = (sz + 7) / 8; off /= 8; - if (off + sz > p->datasz) { - memcpy(p->data + off, data, p->datasz - off); - return p->size - off*8; + if (off + sz > p.datasz) { + memcpy(p.data + off, data, p.datasz - off); + return p.size - off*8; } else { - memcpy(p->data + off, data, bsz); + memcpy(p.data + off, data, bsz); return sz; } } @@ -887,7 +903,7 @@ int capn_write1(struct capn_ptr *p, int off, const uint8_t *data, int sz) { #define ADD_TAG 1 #endif -static void new_object(struct capn_ptr *p, int bytes) { +static void new_object(capn_ptr *p, int bytes) { struct capn_segment *s = p->seg; /* all allocations are 8 byte aligned */ @@ -908,54 +924,57 @@ static void new_object(struct capn_ptr *p, int bytes) { } if (ADD_TAG) { - write_ptr_tag(p->data, p, 0); + write_ptr_tag(p->data, *p, 0); p->data += 8; + p->has_ptr_tag = 1; } } -struct capn_ptr capn_root(struct capn* c) { - struct capn_ptr p; - p.seg = lookup_segment(c, NULL, 0); +capn_ptr capn_get_root(struct capn* c) { + struct capn_segment* s = lookup_segment(c, NULL, 0); + if (s->len < 8) { + capn_ptr ret = {CAPN_NULL}; + return ret; + } else { + return read_ptr(s, s->data); + } +} + +capn_ptr capn_new_root(struct capn *c) { + capn_ptr p = {CAPN_NULL}; + struct capn_segment *s = lookup_segment(c, NULL, 0); /* don't use new_object as we don't want the tag */ - if (!p.seg && new_data(c, 8, &p.seg) == NULL) - goto err; + if ((s || new_data(c, 8, &s) != NULL) && s->len >= 8) { + p.seg = s; + p.data = p.seg->data; + p.size = 1; + p.type = CAPN_PTR_LIST; + } - if (p.seg->len < 8) - goto err; - - p.data = p.seg->data; - p.size = 1; - p.type = CAPN_PTR_LIST; - p.datasz = 0; - p.ptrsz = 0; - return p; -err: - memset(&p, 0, sizeof(p)); return p; } -struct capn_ptr capn_new_struct(struct capn_segment *seg, int datasz, int ptrs) { - struct capn_ptr p; +capn_ptr capn_new_struct(struct capn_segment *seg, int datasz, int ptrs) { + capn_ptr p = {CAPN_NULL}; p.seg = seg; p.type = CAPN_STRUCT; - p.size = 0; p.datasz = (datasz + 7) & ~7; p.ptrsz = ptrs * 8; new_object(&p, p.datasz + p.ptrsz); return p; } -struct capn_ptr capn_new_list(struct capn_segment *seg, int sz, int datasz, int ptrs) { - struct capn_ptr p; +capn_ptr capn_new_list(struct capn_segment *seg, int sz, int datasz, int ptrs) { + capn_ptr p = {CAPN_NULL}; p.seg = seg; p.type = CAPN_LIST; p.size = sz; - p.ptrsz = 0; if (ptrs || datasz > 8) { p.datasz = (datasz + 7) & ~7; p.ptrsz = ptrs*8; + p.has_composite_tag = 1; new_object(&p, p.size * (p.datasz + p.ptrsz) + 8); if (p.data) { uint64_t hdr = STRUCT_PTR | (U64(p.size) << 2) | (U64(p.datasz/8) << 32) | (U64(ptrs) << 48); @@ -976,19 +995,18 @@ struct capn_ptr capn_new_list(struct capn_segment *seg, int sz, int datasz, int return p; } -struct capn_ptr capn_new_bit_list(struct capn_segment *seg, int sz) { - struct capn_ptr p; +capn_ptr capn_new_bit_list(struct capn_segment *seg, int sz) { + capn_ptr p = {CAPN_NULL}; p.seg = seg; p.type = CAPN_BIT_LIST; p.datasz = (sz+7)/8; - p.ptrsz = 0; p.size = sz; new_object(&p, p.datasz); return p; } -struct capn_ptr capn_new_ptr_list(struct capn_segment *seg, int sz) { - struct capn_ptr p; +capn_ptr capn_new_ptr_list(struct capn_segment *seg, int sz) { + capn_ptr p = {CAPN_NULL}; p.seg = seg; p.type = CAPN_PTR_LIST; p.size = sz; @@ -998,13 +1016,12 @@ struct capn_ptr capn_new_ptr_list(struct capn_segment *seg, int sz) { return p; } -struct capn_ptr capn_new_string(struct capn_segment *seg, const char *str, int sz) { - struct capn_ptr p; +capn_ptr capn_new_string(struct capn_segment *seg, const char *str, int sz) { + capn_ptr p = {CAPN_NULL}; p.seg = seg; p.type = CAPN_LIST; p.size = ((sz >= 0) ? sz : strlen(str)) + 1; p.datasz = 1; - p.ptrsz = 0; new_object(&p, p.size); if (p.data) { memcpy(p.data, str, p.size-1); @@ -1012,80 +1029,53 @@ struct capn_ptr capn_new_string(struct capn_segment *seg, const char *str, int s return p; } -char *capn_to_string(const struct capn_ptr *p, int *psz) { - if (p->type != CAPN_LIST || p->size < 1 || p->data[p->size - 1] != 0) { - if (psz) *psz = 0; - return NULL; - } - - if (psz) *psz = p->size - 1; - return p->data; -} - -struct capn_text capn_get_text(const struct capn_ptr *p, int off) { - struct capn_ptr m = capn_getp(p, off); - struct capn_text ret; +capn_text capn_get_text(capn_ptr p, int off) { + capn_ptr m = capn_getp(p, off); + capn_text ret = {CAPN_NULL}; if (m.type == CAPN_LIST && m.datasz == 1 && m.size && m.data[m.size - 1] == 0) { ret.seg = m.seg; ret.str = m.data; ret.size = m.size - 1; - } else { - ret.seg = NULL; - ret.str = NULL; - ret.size = 0; } return ret; } -struct capn_data capn_get_data(const struct capn_ptr *p, int off) { - struct capn_ptr m = capn_getp(p, off); - struct capn_data ret; +capn_data capn_get_data(capn_ptr p, int off) { + capn_ptr m = capn_getp(p, off); + capn_data ret = {CAPN_NULL}; if (m.type == CAPN_LIST && m.datasz == 1) { ret.seg = m.seg; ret.data = (uint8_t*) m.data; ret.size = m.size; - } else { - ret.seg = NULL; - ret.data = NULL; - ret.size = 0; } return ret; } -int capn_set_text(struct capn_ptr *p, int off, struct capn_text tgt) { - struct capn_ptr m; +int capn_set_text(capn_ptr p, int off, capn_text tgt) { + capn_ptr m = {CAPN_NULL}; if (tgt.str) { m.type = CAPN_LIST; m.seg = tgt.seg; m.data = (char*)tgt.str; m.size = (tgt.size >= 0 ? tgt.size : strlen(tgt.str)) + 1; m.datasz = 1; - m.ptrsz = 0; - } else { - m.type = CAPN_NULL; } /* in the case that the size is specified we need to be careful * that we don't read the extra byte as it may be not be null or * may be in a different page and cause a segfault */ - return write_ptr(p, off, &m, 1); + return write_ptr(p, off, m, 1); } -int capn_set_data(struct capn_ptr *p, int off, struct capn_data tgt) { - struct capn_ptr m; +int capn_set_data(capn_ptr p, int off, capn_data tgt) { + capn_ptr m = {CAPN_NULL}; if (tgt.data) { m.type = CAPN_LIST; m.seg = tgt.seg; m.data = (char*)tgt.data; m.size = tgt.size; m.datasz = 1; - m.ptrsz = 0; - } else { - m.type = CAPN_NULL; } - return write_ptr(p, off, &m, 0); + return write_ptr(p, off, m, 0); } -int capn_marshal_iptr(const union capn_iptr *ip, struct capn_ptr *p, int off) { - return write_ptr(p, off, &ip->c, 0); -} diff --git a/capn.h b/capn.h index 518509e..469e0d6 100644 --- a/capn.h +++ b/capn.h @@ -79,17 +79,19 @@ enum CAPN_TYPE { CAPN_STRUCT = 1, CAPN_LIST = 2, CAPN_PTR_LIST = 3, - CAPN_BIT_LIST = 4, - CAPN_LIST_MEMBER = 5, + CAPN_BIT_LIST = 4 }; struct capn_ptr { - enum CAPN_TYPE type; + enum CAPN_TYPE type : 3; + unsigned int is_list_member : 1; + unsigned int has_ptr_tag : 1; + unsigned int has_composite_tag : 1; + unsigned int datasz : 19; + unsigned int ptrsz : 19; int size; char *data; struct capn_segment *seg; - uint32_t datasz; - uint32_t ptrsz; }; struct capn_text { @@ -104,25 +106,14 @@ struct capn_data { struct capn_segment *seg; }; -union capn_iptr { - struct capn_ptr c; - uintptr_t u; - void *p; -}; - -struct capn_ret_vt { - void (*free)(void*); -}; +typedef struct capn_ptr capn_ptr; +typedef struct capn_text capn_text; +typedef struct capn_data capn_data; /* capn_append_segment appends a segment to a session */ void capn_append_segment(struct capn*, struct capn_segment*); -/* capn_root returns a fake pointer that can be used to get/set the session - * root object using capn_(get|set)_ptr at index 0. The root is the object - * pointed to by a ptr at offset 0 in segment 0. This will allocate room for - * the root if not already. - */ -struct capn_ptr capn_root(struct capn*); +capn_ptr capn_get_root(struct capn*); /* capn_getp|setp functions get/set ptrs in list/structs * off is the list index or pointer index in a struct @@ -130,18 +121,13 @@ struct capn_ptr capn_root(struct capn*); * is in a different segment/context. * Both of these will use/return inner pointers for composite lists. */ -struct capn_ptr capn_getp(const struct capn_ptr *p, int off); -int capn_setp(struct capn_ptr *p, int off, const struct capn_ptr *tgt); +capn_ptr capn_getp(capn_ptr p, int off); +int capn_setp(capn_ptr p, int off, capn_ptr tgt); -/* capn_to_string returns a pointer to a string - * Use this instead of accessing the data directly as these checks that the - * string is null terminated, the list type, etc. - * psz is filled out with the string length if non NULL - */ -struct capn_text capn_get_text(const struct capn_ptr *p, int off); -struct capn_data capn_get_data(const struct capn_ptr *p, int off); -int capn_set_text(struct capn_ptr *p, int off, struct capn_text tgt); -int capn_set_data(struct capn_ptr *p, int off, struct capn_data tgt); +capn_text capn_get_text(capn_ptr p, int off); +capn_data capn_get_data(capn_ptr p, int off); +int capn_set_text(capn_ptr p, int off, capn_text tgt); +int capn_set_data(capn_ptr p, int off, capn_data tgt); /* capn_get_* functions get data from a list * The length of the list is given by p->size @@ -150,16 +136,16 @@ int capn_set_data(struct capn_ptr *p, int off, struct capn_data tgt); * The function returns the number of elements read or -1 on an error. * off must be byte aligned for capn_get1v */ -int capn_get1(const struct capn_ptr *p, int off); -uint8_t capn_get8(const struct capn_ptr *p, int off); -uint16_t capn_get16(const struct capn_ptr *p, int off); -uint32_t capn_get32(const struct capn_ptr *p, int off); -uint64_t capn_get64(const struct capn_ptr *p, int off); -int capn_getv1(const struct capn_ptr *p, int off, uint8_t *data, int sz); -int capn_getv8(const struct capn_ptr *p, int off, uint8_t *data, int sz); -int capn_getv16(const struct capn_ptr *p, int off, uint16_t *data, int sz); -int capn_getv32(const struct capn_ptr *p, int off, uint32_t *data, int sz); -int capn_getv64(const struct capn_ptr *p, int off, uint64_t *data, int sz); +int capn_get1(capn_ptr p, int off); +uint8_t capn_get8(capn_ptr p, int off); +uint16_t capn_get16(capn_ptr p, int off); +uint32_t capn_get32(capn_ptr p, int off); +uint64_t capn_get64(capn_ptr p, int off); +int capn_getv1(capn_ptr p, int off, uint8_t *data, int sz); +int capn_getv8(capn_ptr p, int off, uint8_t *data, int sz); +int capn_getv16(capn_ptr p, int off, uint16_t *data, int sz); +int capn_getv32(capn_ptr p, int off, uint32_t *data, int sz); +int capn_getv64(capn_ptr p, int off, uint64_t *data, int sz); /* capn_set_* function set data in a list * off specifies how far into the list to start @@ -167,27 +153,28 @@ int capn_getv64(const struct capn_ptr *p, int off, uint64_t *data, int sz); * The function returns the number of elemnts written or -1 on an error. * off must be byte aligned for capn_set1v */ -int capn_set1(struct capn_ptr *p, int off, int v); -int capn_set8(struct capn_ptr *p, int off, uint8_t v); -int capn_set16(struct capn_ptr *p, int off, uint16_t v); -int capn_set32(struct capn_ptr *p, int off, uint32_t v); -int capn_set64(struct capn_ptr *p, int off, uint64_t v); -int capn_setv1(struct capn_ptr *p, int off, const uint8_t *data, int sz); -int capn_setv8(struct capn_ptr *p, int off, const uint8_t *data, int sz); -int capn_setv16(struct capn_ptr *p, int off, const uint16_t *data, int sz); -int capn_setv32(struct capn_ptr *p, int off, const uint32_t *data, int sz); -int capn_setv64(struct capn_ptr *p, int off, const uint64_t *data, int sz); +int capn_set1(capn_ptr p, int off, int v); +int capn_set8(capn_ptr p, int off, uint8_t v); +int capn_set16(capn_ptr p, int off, uint16_t v); +int capn_set32(capn_ptr p, int off, uint32_t v); +int capn_set64(capn_ptr p, int off, uint64_t v); +int capn_setv1(capn_ptr p, int off, const uint8_t *data, int sz); +int capn_setv8(capn_ptr p, int off, const uint8_t *data, int sz); +int capn_setv16(capn_ptr p, int off, const uint16_t *data, int sz); +int capn_setv32(capn_ptr p, int off, const uint32_t *data, int sz); +int capn_setv64(capn_ptr p, int off, const uint64_t *data, int sz); /* capn_new_* functions create a new object * datasz is in bytes, ptrs is # of pointers, sz is # of elements in the list * If capn_new_string sz < 0, strlen is used to compute the string length * On an error a CAPN_NULL pointer is returned */ -struct capn_ptr capn_new_struct(struct capn_segment *seg, int datasz, int ptrs); -struct capn_ptr capn_new_list(struct capn_segment *seg, int sz, int datasz, int ptrs); -struct capn_ptr capn_new_bit_list(struct capn_segment *seg, int sz); -struct capn_ptr capn_new_ptr_list(struct capn_segment *seg, int sz); -struct capn_ptr capn_new_string(struct capn_segment *seg, const char *str, int sz); +capn_ptr capn_new_struct(struct capn_segment *seg, int datasz, int ptrs); +capn_ptr capn_new_list(struct capn_segment *seg, int sz, int datasz, int ptrs); +capn_ptr capn_new_bit_list(struct capn_segment *seg, int sz); +capn_ptr capn_new_ptr_list(struct capn_segment *seg, int sz); +capn_ptr capn_new_string(struct capn_segment *seg, const char *str, int sz); +capn_ptr capn_new_root(struct capn*); #if defined(__cplusplus) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) #define CAPN_INLINE static inline @@ -201,14 +188,14 @@ struct capn_ptr capn_new_string(struct capn_segment *seg, const char *str, int s * Data must be xored with the default value * These are inlined */ -CAPN_INLINE uint8_t capn_read8(const struct capn_ptr *p, int off); -CAPN_INLINE uint16_t capn_read16(const struct capn_ptr *p, int off); -CAPN_INLINE uint32_t capn_read32(const struct capn_ptr *p, int off); -CAPN_INLINE uint64_t capn_read64(const struct capn_ptr *p, int off); -CAPN_INLINE int capn_write8(struct capn_ptr *p, int off, uint8_t val); -CAPN_INLINE int capn_write16(struct capn_ptr *p, int off, uint16_t val); -CAPN_INLINE int capn_write32(struct capn_ptr *p, int off, uint32_t val); -CAPN_INLINE int capn_write64(struct capn_ptr *p, int off, uint64_t val); +CAPN_INLINE uint8_t capn_read8(capn_ptr p, int off); +CAPN_INLINE uint16_t capn_read16(capn_ptr p, int off); +CAPN_INLINE uint32_t capn_read32(capn_ptr p, int off); +CAPN_INLINE uint64_t capn_read64(capn_ptr p, int off); +CAPN_INLINE int capn_write8(capn_ptr p, int off, uint8_t val); +CAPN_INLINE int capn_write16(capn_ptr p, int off, uint16_t val); +CAPN_INLINE int capn_write32(capn_ptr p, int off, uint32_t val); +CAPN_INLINE int capn_write64(capn_ptr p, int off, uint64_t val); /* capn_init_malloc inits the capn struct with a create function which @@ -274,61 +261,61 @@ CAPN_INLINE uint64_t capn_flip64(uint64_t v) { } #undef T -CAPN_INLINE uint8_t capn_read8(const struct capn_ptr *p, int off) { - return off+1 <= p->datasz ? capn_flip8(*(uint8_t*) (p->data+off)) : 0; +CAPN_INLINE uint8_t capn_read8(capn_ptr p, int off) { + return off+1 <= p.datasz ? capn_flip8(*(uint8_t*) (p.data+off)) : 0; } -CAPN_INLINE int capn_write8(struct capn_ptr *p, int off, uint8_t val) { - if (off+1 <= p->datasz) { - *(uint8_t*) (p->data+off) = capn_flip8(val); +CAPN_INLINE int capn_write8(capn_ptr p, int off, uint8_t val) { + if (off+1 <= p.datasz) { + *(uint8_t*) (p.data+off) = capn_flip8(val); return 0; } else { return -1; } } -CAPN_INLINE uint16_t capn_read16(const struct capn_ptr *p, int off) { - return off+2 <= p->datasz ? capn_flip16(*(uint16_t*) (p->data+off)) : 0; +CAPN_INLINE uint16_t capn_read16(capn_ptr p, int off) { + return off+2 <= p.datasz ? capn_flip16(*(uint16_t*) (p.data+off)) : 0; } -CAPN_INLINE int capn_write16(struct capn_ptr *p, int off, uint16_t val) { - if (off+2 <= p->datasz) { - *(uint16_t*) (p->data+off) = capn_flip16(val); +CAPN_INLINE int capn_write16(capn_ptr p, int off, uint16_t val) { + if (off+2 <= p.datasz) { + *(uint16_t*) (p.data+off) = capn_flip16(val); return 0; } else { return -1; } } -CAPN_INLINE uint32_t capn_read32(const struct capn_ptr *p, int off) { - return off+4 <= p->datasz ? capn_flip32(*(uint32_t*) (p->data+off)) : 0; +CAPN_INLINE uint32_t capn_read32(capn_ptr p, int off) { + return off+4 <= p.datasz ? capn_flip32(*(uint32_t*) (p.data+off)) : 0; } -CAPN_INLINE int capn_write32(struct capn_ptr *p, int off, uint32_t val) { - if (off+4 <= p->datasz) { - *(uint32_t*) (p->data+off) = capn_flip32(val); +CAPN_INLINE int capn_write32(capn_ptr p, int off, uint32_t val) { + if (off+4 <= p.datasz) { + *(uint32_t*) (p.data+off) = capn_flip32(val); return 0; } else { return -1; } } -CAPN_INLINE uint64_t capn_read64(const struct capn_ptr *p, int off) { - return off+8 <= p->datasz ? capn_flip64(*(uint64_t*) (p->data+off)) : 0; +CAPN_INLINE uint64_t capn_read64(capn_ptr p, int off) { + return off+8 <= p.datasz ? capn_flip64(*(uint64_t*) (p.data+off)) : 0; } -CAPN_INLINE int capn_write64(struct capn_ptr *p, int off, uint64_t val) { - if (off+8 <= p->datasz) { - *(uint64_t*) (p->data+off) = capn_flip64(val); +CAPN_INLINE int capn_write64(capn_ptr p, int off, uint64_t val) { + if (off+8 <= p.datasz) { + *(uint64_t*) (p.data+off) = capn_flip64(val); return 0; } else { return -1; } } -CAPN_INLINE float capn_read_float(const struct capn_ptr *p, int off, float def) { +CAPN_INLINE float capn_read_float(capn_ptr p, int off, float def) { union { float f; uint32_t u;} u; u.f = def; u.u ^= capn_read32(p, off); return u.f; } -CAPN_INLINE int capn_write_float(struct capn_ptr *p, int off, float f, float def) { +CAPN_INLINE int capn_write_float(capn_ptr p, int off, float f, float def) { union { float f; uint32_t u;} u; union { float f; uint32_t u;} d; u.f = f; @@ -336,13 +323,13 @@ CAPN_INLINE int capn_write_float(struct capn_ptr *p, int off, float f, float def return capn_write32(p, off, u.u ^ d.u); } -CAPN_INLINE double capn_read_double(const struct capn_ptr *p, int off, double def) { +CAPN_INLINE double capn_read_double(capn_ptr p, int off, double def) { union { double f; uint64_t u;} u; u.f = def; u.u ^= capn_read64(p, off); return u.f; } -CAPN_INLINE int capn_write_double(struct capn_ptr *p, int off, double f, double def) { +CAPN_INLINE int capn_write_double(capn_ptr p, int off, double f, double def) { union { double f; uint64_t u;} u; union { double f; uint64_t u;} d; d.f = f; diff --git a/compiler/capnpc-c.c b/compiler/capnpc-c.c new file mode 100644 index 0000000..4a39386 --- /dev/null +++ b/compiler/capnpc-c.c @@ -0,0 +1,29 @@ +#include "schema.h" + + +int main() { + struct capn capn; + struct CodeGeneratorRequest_ptr root; + struct CodeGeneratorRequest req; + int i; + + if (capn_init_fp(&capn, stdin)) { + fprintf(stderr, "failed to read schema on input\n"); + return -1; + } + + root.p = capn_root(&capn); + read_CodeGeneratorRequest(&root, &req); + + for (i = 0; i < req.nodes.size; i++) { + struct Node_ptr p; + struct Node n; + p.p = capn_getp(&req.nodes, i); + read_Node(&p, &n); + + fprintf(stderr, "node %s id:%#llx scope:%#llx type:%d\n", + n.displayName.str, n.id, n.scopeId, n.body_tag); + } + + return 0; +} diff --git a/compiler/schema.c b/compiler/schema.c new file mode 100644 index 0000000..db321fb --- /dev/null +++ b/compiler/schema.c @@ -0,0 +1,222 @@ +#include "schema.h" + +void read_Node(const struct Node_ptr *p, struct Node *s) { + s->id = capn_read64(&p->p, 0); + s->displayName = capn_get_text(&p->p, 0); + s->scopeId = capn_read64(&p->p, 8); + s->nestedNodes = capn_getp(&p->p, 1); + s->annotations = capn_getp(&p->p, 2); + s->body_tag = capn_read16(&p->p, 16); + switch (s->body_tag) { + case Node_fileNode: + s->body.fileNode.p = capn_getp(&p->p, 3); + break; + case Node_structNode: + s->body.structNode.p = capn_getp(&p->p, 3); + break; + case Node_enumNode: + s->body.enumNode.p = capn_getp(&p->p, 3); + break; + case Node_interfaceNode: + s->body.interfaceNode.p = capn_getp(&p->p, 3); + break; + case Node_constNode: + s->body.constNode.p = capn_getp(&p->p, 3); + break; + case Node_annotationNode: + s->body.annotationNode.p = capn_getp(&p->p, 3); + break; + default: + break; + } +} + +void read_Node_NestedNode(const struct Node_NestedNode_ptr *p, struct Node_NestedNode *s) { + s->name = capn_get_text(&p->p, 0); + s->id = capn_read64(&p->p, 0); +} + +void read_Type(const struct Type_ptr *p, struct Type *s) { + s->body_tag = capn_read16(&p->p, 0); + switch (s->body_tag) { + case Type_listType: + s->body.listType.p = capn_getp(&p->p, 0); + break; + case Type_enumType: + s->body.enumType = capn_read64(&p->p, 0); + break; + case Type_structType: + s->body.structType = capn_read64(&p->p, 0); + break; + case Type_interfaceType: + s->body.interfaceType = capn_read64(&p->p, 0); + break; + default: + break; + } +} + +void read_Value(const struct Value_ptr *p, struct Value *s) { + s->body_tag = capn_read16(&p->p, 0); + switch (s->body_tag) { + case Value_boolValue: + s->body.boolValue = (capn_read8(&p->p, 8) & 1) != 0; + break; + case Value_int8Value: + s->body.int8Value = (int8_t) capn_read8(&p->p, 8); + break; + case Value_int16Value: + s->body.int16Value = (int16_t) capn_read16(&p->p, 8); + break; + case Value_int32Value: + s->body.int32Value = (int32_t) capn_read32(&p->p, 8); + break; + case Value_int64Value: + s->body.int64Value = (int64_t) capn_read64(&p->p, 8); + break; + case Value_uint8Value: + s->body.uint8Value = capn_read8(&p->p, 8); + break; + case Value_uint16Value: + s->body.uint16Value = capn_read16(&p->p, 8); + break; + case Value_uint32Value: + s->body.uint32Value = capn_read32(&p->p, 8); + break; + case Value_uint64Value: + s->body.uint64Value = capn_read64(&p->p, 8); + break; + case Value_float32Value: + s->body.float32Value = capn_read_float(&p->p, 8, 0.0f); + break; + case Value_float64Value: + s->body.float64Value = capn_read_double(&p->p, 8, 0.0); + break; + case Value_textValue: + s->body.textValue = capn_get_text(&p->p, 0); + break; + case Value_dataValue: + s->body.dataValue = capn_get_data(&p->p, 0); + break; + case Value_listValue: + s->body.listValue = capn_getp(&p->p, 0); + break; + case Value_enumValue: + s->body.enumValue = capn_read16(&p->p, 8); + break; + case Value_structValue: + s->body.structValue = capn_getp(&p->p, 0); + break; + case Value_objectValue: + s->body.objectValue = capn_getp(&p->p, 0); + break; + default: + break; + } +} + +void read_Annotation(const struct Annotation_ptr *p, struct Annotation *s) { + s->id = capn_read64(&p->p, 0); + s->value.p = capn_getp(&p->p, 0); +} + +void read_FileNode(const struct FileNode_ptr *p, struct FileNode *s) { + s->imports = capn_getp(&p->p, 0); +} + +void read_FileNode_Import(const struct FileNode_Import_ptr *p, struct FileNode_Import *s) { + s->id = capn_read64(&p->p, 0); + s->name = capn_get_text(&p->p, 0); +} + +void read_StructNode(const struct StructNode_ptr *p, struct StructNode *s) { + s->dataSectionWordSize = capn_read16(&p->p, 0); + s->pointerSectionSize = capn_read16(&p->p, 2); + s->preferredListEncoding = (enum ElementSize) capn_read16(&p->p, 4); + s->members = capn_getp(&p->p, 0); +} + +void read_StructNode_Member(const struct StructNode_Member_ptr *p, struct StructNode_Member *s) { + s->name = capn_get_text(&p->p, 0); + s->ordinal = capn_read16(&p->p, 0); + s->codeOrder = capn_read16(&p->p, 2); + s->annotations = capn_getp(&p->p, 1); + s->body_tag = (enum StructNode_Member_body) capn_read16(&p->p, 4); + switch (s->body_tag) { + case StructNode_Member_fieldMember: + s->body.fieldMember.p = capn_getp(&p->p, 2); + break; + case StructNode_Member_unionMember: + s->body.unionMember.p = capn_getp(&p->p, 2); + break; + default: + break; + } +} + +void read_StructNode_Field(const struct StructNode_Field_ptr *p, struct StructNode_Field *s) { + s->offset = capn_read32(&p->p, 0); + s->type.p = capn_getp(&p->p, 0); + s->defaultValue.p = capn_getp(&p->p, 1); +} + +void read_StructNode_Union(const struct StructNode_Union_ptr *p, struct StructNode_Union *s) { + s->discriminantOffset = capn_read32(&p->p, 0); + s->members = capn_getp(&p->p, 0); +} + +void read_EnumNode(const struct EnumNode_ptr *p, struct EnumNode *s) { + s->enumerants = capn_getp(&p->p, 0); +} + +void read_EnumNode_Enumerant(const struct EnumNode_Enumerant_ptr *p, struct EnumNode_Enumerant *s) { + s->name = capn_get_text(&p->p, 0); + s->codeOrder = capn_read16(&p->p, 0); + s->annotations = capn_getp(&p->p, 1); +} + +void read_InterfaceNode(const struct InterfaceNode_ptr *p, struct InterfaceNode *s) { + s->methods = capn_getp(&p->p, 0); +} + +void read_InterfaceNode_Method(const struct InterfaceNode_Method_ptr *p, struct InterfaceNode_Method *s) { + s->name = capn_get_text(&p->p, 0); + s->codeOrder = capn_read16(&p->p, 0); + s->params = capn_getp(&p->p, 1); + s->requiredParamCount = capn_read16(&p->p, 2); + s->returnType.p = capn_getp(&p->p, 2); + s->annotations = capn_getp(&p->p, 3); +} + +void read_InterfaceNode_Method_Param(const struct InterfaceNode_Method_Param_ptr *p, struct InterfaceNode_Method_Param *s) { + s->name = capn_get_text(&p->p, 0); + s->type.p = capn_getp(&p->p, 1); + s->defaultValue.p = capn_getp(&p->p, 2); + s->annotations = capn_getp(&p->p, 3); +} + +void read_ConstNode(const struct ConstNode_ptr *p, struct ConstNode *s) { + s->type.p = capn_getp(&p->p, 0); + s->value.p = capn_getp(&p->p, 1); +} + +void read_AnnotationNode(const struct AnnotationNode_ptr *p, struct AnnotationNode *s) { + s->type.p = capn_getp(&p->p, 0); + s->targetsFile = (capn_read8(&p->p, 0) & 1) != 0; + s->targetsConst = (capn_read8(&p->p, 0) & 3) != 0; + s->targetsEnum = (capn_read8(&p->p, 0) & 4) != 0; + s->targetsEnumerant = (capn_read8(&p->p, 0) & 8) != 0; + s->targetsStruct = (capn_read8(&p->p, 0) & 16) != 0; + s->targetsField = (capn_read8(&p->p, 0) & 32) != 0; + s->targetsUnion = (capn_read8(&p->p, 0) & 64) != 0; + s->targetsInterface = (capn_read8(&p->p, 0) & 128) != 0; + s->targetsMethod = (capn_read8(&p->p, 1) & 1) != 0; + s->targetsParam = (capn_read8(&p->p, 1) & 2) != 0; + s->targetsAnnotation = (capn_read8(&p->p, 1) & 4) != 0; +} + +void read_CodeGeneratorRequest(const struct CodeGeneratorRequest_ptr *p, struct CodeGeneratorRequest *s) { + s->nodes = capn_getp(&p->p, 0); + s->requestedFiles = capn_getp(&p->p, 1); +} + diff --git a/compiler/schema.capnp b/compiler/schema.capnp new file mode 100644 index 0000000..2b1b5a6 --- /dev/null +++ b/compiler/schema.capnp @@ -0,0 +1,316 @@ +# Copyright (c) 2013, Kenton Varda +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +@0xb471df2f45ca32c7; + +# WARNING: This protocol is still subject to backwards-incompatible change. + +using Id = UInt64; +# The globally-unique ID of a file, type, or annotation. + +struct Node { + id @0 :Id; + + displayName @1 :Text; + # Name to present to humans to identify this Node. You should not attempt to parse this. Its + # format could change. It is not guaranteed to be unique. + # + # (On Zooko's triangle, this is the node's nickname.) + + scopeId @2 :Id = 0; + # ID of the lexical parent node. Typically, the scope node will have a NestedNode pointing back + # at this node, but robust code should avoid relying on this. `scopeId` is zero if the node has + # no parent, which is normally only the case with files, but should be allowed for any kind of + # node (in order to make runtime type generation easier). + + nestedNodes @3 :List(NestedNode); + # List of nodes nested within this node, along with the names under which they were declared. + + struct NestedNode { + name @0 :Text; + # Unqualified symbol name. Unlike Node.name, this *can* be used programmatically. + # + # (On Zooko's triangle, this is the node's petname according to its parent scope.) + + id @1 :Id; + # ID of the nested node. Typically, the target node's scopeId points back to this node, but + # robust code should avoid relying on this. + } + + annotations @4 :List(Annotation); + # Annotations applied to this node. + + body @5 union { + # Info specific to each kind of node. + + fileNode @6 :FileNode; + structNode @7 :StructNode; + enumNode @8 :EnumNode; + interfaceNode @9 :InterfaceNode; + constNode @10 :ConstNode; + annotationNode @11 :AnnotationNode; + } +} + +struct Type { + # Represents a type expression. + + body @0 union { + voidType @1 :Void; + boolType @2 :Void; + int8Type @3 :Void; + int16Type @4 :Void; + int32Type @5 :Void; + int64Type @6 :Void; + uint8Type @7 :Void; + uint16Type @8 :Void; + uint32Type @9 :Void; + uint64Type @10 :Void; + float32Type @11 :Void; + float64Type @12 :Void; + textType @13 :Void; + dataType @14 :Void; + + listType @15 :Type; # Value = the element type. + + enumType @16 :Id; + structType @17 :Id; + interfaceType @18 :Id; + + objectType @19 :Void; + } +} + +struct Value { + # Represents a value, e.g. a field default value, constant value, or annotation value. + + body @0 union { + # Note ordinals 1 and 10 are intentionally swapped to improve union layout. + voidValue @10 :Void; + boolValue @2 :Bool; + int8Value @3 :Int8; + int16Value @4 :Int16; + int32Value @5 :Int32; + int64Value @6 :Int64; + uint8Value @7 :UInt8; + uint16Value @8 :UInt16; + uint32Value @9 :UInt32; + uint64Value @1 :UInt64; + float32Value @11 :Float32; + float64Value @12 :Float64; + textValue @13 :Text; + dataValue @14 :Data; + + listValue @15 :Object; + + enumValue @16 :UInt16; + structValue @17 :Object; + + interfaceValue @18 :Void; + # The only interface value that can be represented statically is "null", whose methods always + # throw exceptions. + + objectValue @19 :Object; + } +} + +struct Annotation { + # Describes an annotation applied to a declaration. Note AnnotationNode describes the + # annotation's declaration, while this describes a use of the annotation. + + id @0 :Id; + # ID of the annotation node. + + value @1 :Value; +} + +struct FileNode { + imports @0 :List(Import); + struct Import { + id @0 :Id; + # ID of the imported file. + + name @1 :Text; + # Name which *this* file used to refer to the foreign file. This may be a relative name. + # This information is provided because it might be useful for code generation, e.g. to generate + # #include directives in C++. + # + # (On Zooko's triangle, this is the import's petname according to the importing file.) + } +} + +enum ElementSize { + # Possible element sizes for encoded lists. These correspond exactly to the possible values of + # the 3-bit element size component of a list pointer. + + empty @0; # aka "void", but that's a keyword. + bit @1; + byte @2; + twoBytes @3; + fourBytes @4; + eightBytes @5; + pointer @6; + inlineComposite @7; +} + +struct StructNode { + dataSectionWordSize @0 :UInt16; + pointerSectionSize @1 :UInt16; + + preferredListEncoding @2 :ElementSize; + # The preferred element size to use when encoding a list of this struct. If this is anything + # other than `inlineComposite` then the struct is one word or less in size and is a candidate for + # list packing optimization. + + members @3 :List(Member); + # Top-level fields and unions of the struct, ordered by ordinal number, except that members of + # unions are not included in this list (because they are nested inside the union declaration). + # Note that this ordering is stable as the protocol evolves -- new members can only be added to + # the end. So, when encoding a struct as tag/value pairs with numeric tags, it actually may make + # sense to use the field's position in this list rather than the original ordinal number to + # identify fields. + + struct Member { + name @0 :Text; + + ordinal @1 :UInt16; + + codeOrder @2 :UInt16; + # Indicates where this member appeared in the code, relative to other members. + # Code ordering may have semantic relevance -- programmers tend to place related fields + # together. So, using code ordering makes sense in human-readable formats where ordering is + # otherwise irrelevant, like JSON. The values of codeOrder are tightly-packed, so for unions + # and non-union fields the maximum value of codeOrder is count(fields) + count(unions). + # Fields that are members of a union are only ordered relative to the other members of that + # union, so the maximum value there is count(union.fields). + + annotations @3 :List(Annotation); + + body @4 union { + # More member types could be added over time. Consumers should skip those that they + # don't understand. + + fieldMember @5 :Field; + unionMember @6 :Union; + } + } + + struct Field { + offset @0 :UInt32; + # Offset, in units of the field's size, from the beginning of the section in which the field + # resides. E.g. for a UInt32 field, multiply this by 4 to get the byte offset from the + # beginning of the data section. + + type @1 :Type; + defaultValue @2 :Value; + } + + struct Union { + discriminantOffset @0 :UInt32; + # Offset of the union's 16-bit discriminant within the struct's data section, in 16-bit units. + + members @1 :List(Member); + # Fields of this union, ordered by ordinal. Currently all members are fields, but + # consumers should skip member types that they don't understand. The first member in this list + # gets discriminant value zero, the next gets one, and so on. + # + # TODO(soon): Discriminant zero should be reserved to mean "unset", unless the first field in + # the union actually predates the union (it was retroactively unionized), in which case it + # gets discriminant zero. + } +} + +struct EnumNode { + enumerants @0 :List(Enumerant); + # Enumerants, in order by ordinal. + + struct Enumerant { + name @0 :Text; + + codeOrder @1 :UInt16; + # Specifies order in which the enumerants were declared in the code. + # Like Struct.Field.codeOrder. + + annotations @2 :List(Annotation); + } +} + +struct InterfaceNode { + methods @0 :List(Method); + # Methods, in order by ordinal. + + struct Method { + name @0 :Text; + + codeOrder @1 :UInt16; + # Specifies order in which the methods were declared in the code. + # Like Struct.Field.codeOrder. + + params @2 :List(Param); + struct Param { + name @0 :Text; + type @1 :Type; + defaultValue @2 :Value; + annotations @3 :List(Annotation); + } + + requiredParamCount @3 :UInt16; + # One plus the index of the last parameter that has no default value. In languages where + # method calls look like function calls, this is the minimum number of parameters that must + # always be specified, while subsequent parameters are optional. + + returnType @4 :Type; + + annotations @5 :List(Annotation); + } +} + +struct ConstNode { + type @0 :Type; + value @1 :Value; +} + +struct AnnotationNode { + type @0 :Type; + + targetsFile @1 :Bool; + targetsConst @2 :Bool; + targetsEnum @3 :Bool; + targetsEnumerant @4 :Bool; + targetsStruct @5 :Bool; + targetsField @6 :Bool; + targetsUnion @7 :Bool; + targetsInterface @8 :Bool; + targetsMethod @9 :Bool; + targetsParam @10 :Bool; + targetsAnnotation @11 :Bool; +} + +struct CodeGeneratorRequest { + nodes @0 :List(Node); + # All nodes parsed by the compiler, including for the files on the command line and their + # imports. + + requestedFiles @1 :List(Id); + # IDs of files which were listed on the command line. +} diff --git a/compiler/schema.h b/compiler/schema.h new file mode 100644 index 0000000..aca8709 --- /dev/null +++ b/compiler/schema.h @@ -0,0 +1,266 @@ +/* vim: set sw=8 ts=8 sts=8 noet: */ +#include + +struct Node_ptr {struct capn_ptr p;}; +struct Node_NestedNode_ptr {struct capn_ptr p;}; +struct Type_ptr {struct capn_ptr p;}; +struct Value_ptr {struct capn_ptr p;}; +struct Annotation_ptr {struct capn_ptr p;}; +struct FileNode_ptr {struct capn_ptr p;}; +struct FileNode_Import_ptr {struct capn_ptr p;}; +struct StructNode_ptr {struct capn_ptr p;}; +struct StructNode_Member_ptr {struct capn_ptr p;}; +struct StructNode_Field_ptr {struct capn_ptr p;}; +struct StructNode_Union_ptr {struct capn_ptr p;}; +struct EnumNode_ptr {struct capn_ptr p;}; +struct EnumNode_Enumerant_ptr {struct capn_ptr p;}; +struct InterfaceNode_ptr {struct capn_ptr p;}; +struct InterfaceNode_Method_ptr {struct capn_ptr p;}; +struct InterfaceNode_Method_Param_ptr {struct capn_ptr p;}; +struct ConstNode_ptr {struct capn_ptr p;}; +struct AnnotationNode_ptr {struct capn_ptr p;}; +struct CodeGeneratorRequest_ptr {struct capn_ptr p;}; + +enum Node_body { + Node_fileNode = 0, + Node_structNode = 1, + Node_enumNode = 2, + Node_interfaceNode = 3, + Node_constNode = 4, + Node_annotationNode = 5, +}; + +struct Node { + uint64_t id; + struct capn_text displayName; + uint64_t scopeId; + struct capn_ptr nestedNodes; /* List(Node_NestedNode) */ + struct capn_ptr annotations; /* List(Annotation) */ + enum Node_body body_tag; + union { + struct FileNode_ptr fileNode; + struct StructNode_ptr structNode; + struct EnumNode_ptr enumNode; + struct InterfaceNode_ptr interfaceNode; + struct ConstNode_ptr constNode; + struct AnnotationNode_ptr annotationNode; + } body; +}; + +struct Node_NestedNode { + struct capn_text name; + uint64_t id; +}; + +enum Type_body { + Type_voidType = 0, + Type_boolType = 1, + Type_int8Type = 2, + Type_int16Type = 3, + Type_int32Type = 4, + Type_int64Type = 5, + Type_uint8Type = 6, + Type_uint16Type = 7, + Type_uint32Type = 8, + Type_uint64Type = 9, + Type_float32Type = 10, + Type_float64Type = 11, + Type_textType = 12, + Type_dataType = 13, + Type_listType = 14, + Type_enumType = 15, + Type_structType = 16, + Type_interfaceType = 17, + Type_objectType = 18, +}; + +struct Type { + enum Type_body body_tag; + union { + struct Type_ptr listType; + uint64_t enumType; + uint64_t structType; + uint64_t interfaceType; + } body; +}; + +enum Value_body { + Value_voidValue = 9, + Value_boolValue = 1, + Value_int8Value = 2, + Value_int16Value = 3, + Value_int32Value = 4, + Value_int64Value = 5, + Value_uint8Value = 6, + Value_uint16Value = 7, + Value_uint32Value = 8, + Value_uint64Value = 0, + Value_float32Value = 10, + Value_float64Value = 11, + Value_textValue = 12, + Value_dataValue = 13, + Value_listValue = 14, + Value_enumValue = 15, + Value_structValue = 16, + Value_interfaceValue = 17, + Value_objectValue = 18, +}; + +struct Value { + enum Value_body body_tag; + union { + unsigned int boolValue : 1; + int8_t int8Value; + int16_t int16Value; + int32_t int32Value; + int64_t int64Value; + uint8_t uint8Value; + uint16_t uint16Value; + uint32_t uint32Value; + uint64_t uint64Value; + float float32Value; + double float64Value; + struct capn_text textValue; + struct capn_data dataValue; + struct capn_ptr listValue; + uint16_t enumValue; + struct capn_ptr structValue; + struct capn_ptr objectValue; + } body; +}; + +struct Annotation { + uint64_t id; + struct Value_ptr value; +}; + +struct FileNode { + struct capn_ptr imports; /* List(FileNode_Import) */ +}; + +struct FileNode_Import { + uint64_t id; + struct capn_text name; +}; + +enum ElementSize { + ElementSize_empty = 0, + ElementSize_bit = 1, + ElementSize_byte = 2, + ElementSize_twoBytes = 3, + ElementSize_fourBytes = 4, + ElementSize_eightBytes = 5, + ElementSize_pointer = 6, + ElementSize_inlineComposite = 7, +}; + +struct StructNode { + uint16_t dataSectionWordSize; + uint16_t pointerSectionSize; + enum ElementSize preferredListEncoding; + struct capn_ptr members; /* List(StructNode_Member) */ +}; + +enum StructNode_Member_body { + StructNode_Member_fieldMember = 0, + StructNode_Member_unionMember = 1, +}; + +struct StructNode_Member { + struct capn_text name; + uint16_t ordinal; + uint16_t codeOrder; + struct capn_ptr annotations; /* List(Annotation) */ + enum StructNode_Member_body body_tag; + union { + struct StructNode_Field_ptr fieldMember; + struct StructNode_Field_ptr unionMember; + } body; +}; + +struct StructNode_Field { + uint32_t offset; + struct Type_ptr type; + struct Value_ptr defaultValue; +}; + +struct StructNode_Union { + uint32_t discriminantOffset; + struct capn_ptr members; /* List(StructNode_Member) */ +}; + +struct EnumNode { + struct capn_ptr enumerants; /* List(EnumNode_Enumerant) */ +}; + +struct EnumNode_Enumerant { + struct capn_text name; + uint16_t codeOrder; + struct capn_ptr annotations; /* List(Annotation) */ +}; + +struct InterfaceNode { + struct capn_ptr methods; /* List(InterfaceNode_Method) */ +}; + +struct InterfaceNode_Method { + struct capn_text name; + uint16_t codeOrder; + struct capn_ptr params; /* List(InterfaceNode_Method_Param) */ + uint16_t requiredParamCount; + struct Type_ptr returnType; + struct capn_ptr annotations; /* List(Annotation) */ +}; + +struct InterfaceNode_Method_Param { + struct capn_text name; + struct Type_ptr type; + struct Value_ptr defaultValue; + struct capn_ptr annotations; /* List(Annotation) */ +}; + +struct ConstNode { + struct Type_ptr type; + struct Value_ptr value; +}; + +struct AnnotationNode { + struct Type_ptr type; + unsigned int targetsFile : 1; + unsigned int targetsConst : 1; + unsigned int targetsEnum : 1; + unsigned int targetsEnumerant : 1; + unsigned int targetsStruct : 1; + unsigned int targetsField : 1; + unsigned int targetsUnion : 1; + unsigned int targetsInterface : 1; + unsigned int targetsMethod : 1; + unsigned int targetsParam : 1; + unsigned int targetsAnnotation : 1; +}; + +struct CodeGeneratorRequest { + struct capn_ptr nodes; /* List(Node) */ + struct capn_ptr requestedFiles; /* List(uint64_t) */ +}; + +void read_Node(const struct Node_ptr*, struct Node*); +void read_Node_NestedNode(const struct Node_NestedNode_ptr*, struct Node_NestedNode*); +void read_Type(const struct Type_ptr*, struct Type*); +void read_Value(const struct Value_ptr*, struct Value*); +void read_Annotation(const struct Annotation_ptr*, struct Annotation*); +void read_FileNode(const struct FileNode_ptr*, struct FileNode*); +void read_FileNode_Import(const struct FileNode_Import_ptr*, struct FileNode_Import*); +void read_StructNode(const struct StructNode_ptr*, struct StructNode*); +void read_StructNode_Member(const struct StructNode_Member_ptr*, struct StructNode_Member*); +void read_StructNode_Field(const struct StructNode_Field_ptr*, struct StructNode_Field*); +void read_StructNode_Union(const struct StructNode_Union_ptr*, struct StructNode_Union*); +void read_EnumNode(const struct EnumNode_ptr*, struct EnumNode*); +void read_EnumNode_Enumerant(const struct EnumNode_Enumerant_ptr*, struct EnumNode_Enumerant*); +void read_InterfaceNode(const struct InterfaceNode_ptr*, struct InterfaceNode*); +void read_InterfaceNode_Method(const struct InterfaceNode_Method_ptr*, struct InterfaceNode_Method*); +void read_InterfaceNode_Method_Param(const struct InterfaceNode_Method_Param_ptr*, struct InterfaceNode_Method_Param*); +void read_ConstNode(const struct ConstNode_ptr*, struct ConstNode*); +void read_AnnotationNode(const struct AnnotationNode_ptr*, struct AnnotationNode*); +void read_CodeGeneratorRequest(const struct CodeGeneratorRequest_ptr*, struct CodeGeneratorRequest*); +