diff --git a/compiler/src/test/scala/org/capnproto/TestUtil.scala b/compiler/src/test/scala/org/capnproto/TestUtil.scala index 6dba625..dfe884e 100644 --- a/compiler/src/test/scala/org/capnproto/TestUtil.scala +++ b/compiler/src/test/scala/org/capnproto/TestUtil.scala @@ -35,8 +35,18 @@ object TestUtil { subBuilder.setFloat32Field(-1.25e-10f); subBuilder.setFloat64Field(345); subBuilder.setTextField(new Text.Reader("baz")); + + { + val subSubBuilder = subBuilder.initStructField(); + subSubBuilder.setTextField(new Text.Reader("nested")); + subSubBuilder.initStructField().setTextField(new Text.Reader("really nested")); + } } + builder.setEnumField(TestEnum.CORGE); + + //builder.initVoidList(6); + } @@ -69,6 +79,11 @@ object TestUtil { assert(subBuilder.getUInt64Field() == 345678901234567890L); assert(subBuilder.getFloat32Field() == -1.25e-10f); assert(subBuilder.getFloat64Field() == 345); + + { + val subSubBuilder = subBuilder.getStructField(); + assert(subSubBuilder.getTextField().toString() == "nested") + } } } diff --git a/runtime/src/main/java/org/capnproto/Constants.java b/runtime/src/main/java/org/capnproto/Constants.java new file mode 100644 index 0000000..5ddbe88 --- /dev/null +++ b/runtime/src/main/java/org/capnproto/Constants.java @@ -0,0 +1,8 @@ +package org.capnproto; + +final class Constants { + public static final int BITS_PER_POINTER = 64; + public static final int BITS_PER_WORD = 64; + public static final int BYTES_PER_WORD = 8; + public static final int POINTER_SIZE_IN_WORDS = 1; +} diff --git a/runtime/src/main/java/org/capnproto/FieldSize.java b/runtime/src/main/java/org/capnproto/FieldSize.java index c3043b7..e2f8604 100644 --- a/runtime/src/main/java/org/capnproto/FieldSize.java +++ b/runtime/src/main/java/org/capnproto/FieldSize.java @@ -9,4 +9,25 @@ public final class FieldSize { public static final byte EIGHT_BYTES = 5; public static final byte POINTER = 6; public static final byte INLINE_COMPOSITE = 7; + + public static final int dataBitsPerElement(byte size) { + switch (size) { + case VOID: return 0; + case BIT: return 1; + case BYTE: return 8; + case TWO_BYTES: return 16; + case FOUR_BYTES: return 32; + case EIGHT_BYTES: return 64; + case POINTER: return 0; + case INLINE_COMPOSITE: return 0; + default : throw new Error("impossible field size: " + size); + } + } + + public static final int pointersPerElement(byte size) { + switch (size) { + case POINTER: return 1; + default: return 0; + } + } } diff --git a/runtime/src/main/java/org/capnproto/WireHelpers.java b/runtime/src/main/java/org/capnproto/WireHelpers.java index 81bf98c..35498e6 100644 --- a/runtime/src/main/java/org/capnproto/WireHelpers.java +++ b/runtime/src/main/java/org/capnproto/WireHelpers.java @@ -6,9 +6,14 @@ final class WireHelpers { return (bytes + 7) / 8; } + public static int roundBitsUpToWords(long bits) { + //# This code assumes 64-bit words. + return (int)((bits + 63) / ((long) Constants.BITS_PER_WORD)); + } + public static int allocate(int refOffset, SegmentBuilder segment, - int amount, + int amount, // in words byte kind) { // TODO check for nullness, amount == 0 case. @@ -65,7 +70,20 @@ final class WireHelpers { SegmentBuilder segment, int elementCount, byte elementSize) { - throw new Error("unimplemented"); + if (elementSize == FieldSize.INLINE_COMPOSITE) { + throw new DecodeException("Should have called initStructListPointer instead"); + } + + int dataSize = FieldSize.dataBitsPerElement(elementSize); + int pointerCount = FieldSize.pointersPerElement(elementSize); + int step = dataSize + pointerCount * Constants.BITS_PER_POINTER; + int wordCount = roundBitsUpToWords((long)elementCount * (long)step); + int ptr = allocate(refOffset, segment, wordCount, WirePointer.LIST); + + ListPointer.set(segment.buffer, refOffset, elementSize, elementCount); + + return new ListBuilder(segment, ptr * Constants.BYTES_PER_WORD, + elementCount, step, dataSize, (short)pointerCount); } public static ListBuilder initStructListPointer(int refOffset, @@ -82,7 +100,8 @@ final class WireHelpers { //# Allocate the list, prefixed by a single WirePointer. int wordCount = elementCount * wordsPerElement; - int ptrOffset = allocate(refOffset, segment, 1 + wordCount, WirePointer.LIST); + int ptrOffset = allocate(refOffset, segment, Constants.POINTER_SIZE_IN_WORDS + wordCount, + WirePointer.LIST); //# Initialize the pointer. ListPointer.setInlineComposite(segment.buffer, refOffset, wordCount);