diff --git a/compiler/src/main/cpp/capnpc-java.c++ b/compiler/src/main/cpp/capnpc-java.c++ index ab80a36..54b994f 100644 --- a/compiler/src/main/cpp/capnpc-java.c++ +++ b/compiler/src/main/cpp/capnpc-java.c++ @@ -965,6 +965,9 @@ private: }; } else if (kind == FieldKind::STRUCT) { + uint64_t typeId = field.getContainingStruct().getProto().getId(); + kj::String defaultParams = defaultOffset == 0 ? kj::str("null, 0") : kj::str( + "Schemas.b_", kj::hex(typeId), ", ", defaultOffset); return FieldText { kj::strTree( @@ -976,7 +979,7 @@ private: spaces(indent), " public ", type, ".Reader get", titleCase, "() {\n", unionDiscrim.check, spaces(indent), " return ", type, - ".factory.fromStructReader(_reader.getPointerField(", offset,").getStruct());\n", + ".factory.fromStructReader(_reader.getPointerField(", offset,").getStruct(", defaultParams, "));\n", spaces(indent), " }\n", "\n"), kj::strTree( @@ -985,7 +988,7 @@ private: unionDiscrim.check, spaces(indent), " return ", type, ".factory.fromStructBuilder(_builder.getPointerField(", offset, ").getStruct(", - type, ".STRUCT_SIZE", "));\n", + type, ".STRUCT_SIZE,", defaultParams, "));\n", spaces(indent), " }\n", spaces(indent), " public final void set", titleCase, "(", type, ".Reader value) {\n", unionDiscrim.set, @@ -1003,7 +1006,7 @@ private: uint64_t typeId = field.getContainingStruct().getProto().getId(); kj::String defaultParams = defaultOffset == 0 ? kj::str() : kj::str( - "Schemas.b_", kj::hex(typeId), ".buffer, ", defaultOffset * 8, ", ", defaultSize); + "Schemas.b_", kj::hex(typeId), ".buffer, ", defaultOffset, ", ", defaultSize); kj::String blobKind = typeBody.which() == schema::Type::TEXT ? kj::str("Text") : kj::str("Data"); kj::String setterInputType = typeBody.which() == schema::Type::TEXT ? kj::str("String") : kj::str("byte []"); diff --git a/compiler/src/test/scala/org/capnproto/EncodingTest.scala b/compiler/src/test/scala/org/capnproto/EncodingTest.scala index 4b03865..6e42aa2 100644 --- a/compiler/src/test/scala/org/capnproto/EncodingTest.scala +++ b/compiler/src/test/scala/org/capnproto/EncodingTest.scala @@ -194,5 +194,4 @@ class EncodingSuite extends FunSuite { //Serialize.writeMessage((new java.io.FileOutputStream("/Users/dwrensha/Desktop/test.dat")).getChannel(), // message); - } diff --git a/compiler/src/test/scala/org/capnproto/TestUtil.scala b/compiler/src/test/scala/org/capnproto/TestUtil.scala index bfa062d..adcfeaa 100644 --- a/compiler/src/test/scala/org/capnproto/TestUtil.scala +++ b/compiler/src/test/scala/org/capnproto/TestUtil.scala @@ -255,7 +255,23 @@ object TestUtil { assert(reader.getFloat32Field() == 1234.5f); assert(reader.getFloat64Field() == -123e45); (reader.getTextField().toString()) should equal ("foo"); + (reader.getDataField().toArray()) should equal (Array(0x62,0x61,0x72)); + { + val subReader = reader.getStructField(); + subReader.getVoidField(); + subReader.getBoolField() should equal (true); + subReader.getInt8Field() should equal (-12); + subReader.getInt16Field() should equal (3456); + subReader.getInt32Field() should equal (-78901234); + // ... + subReader.getTextField().toString() should equal ("baz"); + + { + val subSubReader = subReader.getStructField(); + subSubReader.getTextField().toString() should equal ("nested"); + } + + } } - } diff --git a/compiler/src/test/schema/test.capnp b/compiler/src/test/schema/test.capnp index c7ba359..d454598 100644 --- a/compiler/src/test/schema/test.capnp +++ b/compiler/src/test/schema/test.capnp @@ -70,6 +70,50 @@ struct TestDefaults { float64Field @11 : Float64 = -123e45; textField @12 : Text = "foo"; dataField @13 : Data = "bar"; # 0x"62 61 72"; + + structField @14 : TestAllTypes = ( + voidField = void, + boolField = true, + int8Field = -12, + int16Field = 3456, + int32Field = -78901234, + int64Field = 56789012345678, + uInt8Field = 90, + uInt16Field = 1234, + uInt32Field = 56789012, + uInt64Field = 345678901234567890, + float32Field = -1.25e-10, + float64Field = 345, + textField = "baz", + dataField = "qux", + structField = ( + textField = "nested", + structField = (textField = "really nested")), + enumField = baz, + # interfaceField can't have a default + + voidList = [void, void, void], + boolList = [false, true, false, true, true], + int8List = [12, -34, -0x80, 0x7f], + int16List = [1234, -5678, -0x8000, 0x7fff], + int32List = [12345678, -90123456, -0x80000000, 0x7fffffff], + int64List = [123456789012345, -678901234567890, -0x8000000000000000, 0x7fffffffffffffff], + uInt8List = [12, 34, 0, 0xff], + uInt16List = [1234, 5678, 0, 0xffff], + uInt32List = [12345678, 90123456, 0, 0xffffffff], + uInt64List = [123456789012345, 678901234567890, 0, 0xffffffffffffffff], + float32List = [0, 1234567, 1e37, -1e37, 1e-37, -1e-37], + float64List = [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306], + textList = ["quux", "corge", "grault"], + dataList = ["garply", "waldo", "fred"], + structList = [ + (textField = "x structlist 1"), + (textField = "x structlist 2"), + (textField = "x structlist 3")], + enumList = [qux, bar, grault] + # interfaceList can't have a default + ); + } struct TestAnyPointer { diff --git a/runtime/src/main/java/org/capnproto/PointerBuilder.java b/runtime/src/main/java/org/capnproto/PointerBuilder.java index f8c5e70..8e040ca 100644 --- a/runtime/src/main/java/org/capnproto/PointerBuilder.java +++ b/runtime/src/main/java/org/capnproto/PointerBuilder.java @@ -18,7 +18,11 @@ public final class PointerBuilder { } public final StructBuilder getStruct(StructSize size) { - return WireHelpers.getWritableStructPointer(this.pointer, this.segment, size); + return WireHelpers.getWritableStructPointer(this.pointer, this.segment, size, null, 0); + } + + public final StructBuilder getStruct(StructSize size, SegmentReader defaultBuffer, int defaultOffset) { + return WireHelpers.getWritableStructPointer(this.pointer, this.segment, size, defaultBuffer, defaultOffset); } public final ListBuilder getList(byte elementSize) { diff --git a/runtime/src/main/java/org/capnproto/PointerReader.java b/runtime/src/main/java/org/capnproto/PointerReader.java index 3fa30db..d58216b 100644 --- a/runtime/src/main/java/org/capnproto/PointerReader.java +++ b/runtime/src/main/java/org/capnproto/PointerReader.java @@ -29,27 +29,24 @@ public final class PointerReader { } public StructReader getStruct() { - if (this.segment == null) { - return WireHelpers.readStructPointer(SegmentReader.EMPTY, 0, this.nestingLimit); - } else { - return WireHelpers.readStructPointer(this.segment, - this.pointer, - this.nestingLimit); - } + return WireHelpers.readStructPointer(this.segment, + this.pointer, + null, 0, + this.nestingLimit); + } + + public StructReader getStruct(SegmentReader defaultSegment, int defaultOffset) { + return WireHelpers.readStructPointer(this.segment, + this.pointer, + defaultSegment, defaultOffset, + this.nestingLimit); } public ListReader getList(byte expectedElementSize) { - if (this.segment == null) { - return WireHelpers.readListPointer(SegmentReader.EMPTY, - 0, - expectedElementSize, - this.nestingLimit); - } else { - return WireHelpers.readListPointer(this.segment, - this.pointer, - expectedElementSize, - this.nestingLimit); - } + return WireHelpers.readListPointer(this.segment, + this.pointer, + expectedElementSize, + this.nestingLimit); } public Text.Reader getText() { diff --git a/runtime/src/main/java/org/capnproto/StructReader.java b/runtime/src/main/java/org/capnproto/StructReader.java index ea33d34..f763017 100644 --- a/runtime/src/main/java/org/capnproto/StructReader.java +++ b/runtime/src/main/java/org/capnproto/StructReader.java @@ -9,6 +9,16 @@ public final class StructReader { final byte bit0Offset; final int nestingLimit; + public StructReader() { + this.segment = SegmentReader.EMPTY; + this.data = 0; + this.pointers = 0; + this.dataSize = 0; + this.pointerCount = 0; + this.bit0Offset = 0; + this.nestingLimit = 0x7fffffff; + } + public StructReader(SegmentReader segment, int data, int pointers, int dataSize, short pointerCount, byte bit0Offset, int nestingLimit) { diff --git a/runtime/src/main/java/org/capnproto/WireHelpers.java b/runtime/src/main/java/org/capnproto/WireHelpers.java index 61ee5ff..531a6b5 100644 --- a/runtime/src/main/java/org/capnproto/WireHelpers.java +++ b/runtime/src/main/java/org/capnproto/WireHelpers.java @@ -157,11 +157,17 @@ final class WireHelpers { static StructBuilder getWritableStructPointer(int refOffset, SegmentBuilder segment, - StructSize size) { + StructSize size, + SegmentReader defaultSegment, + int defaultOffset) { long ref = WirePointer.get(segment.buffer, refOffset); int target = WirePointer.target(refOffset, ref); if (WirePointer.isNull(ref)) { - return initStructPointer(refOffset, segment, size); + if (defaultSegment == null) { + return initStructPointer(refOffset, segment, size); + } else { + throw new Error("unimplemented"); + } } FollowBuilderFarsResult resolved = followBuilderFars(ref, target, segment); @@ -325,7 +331,7 @@ final class WireHelpers { Text.Builder builder = initTextPointer(refOffset, segment, defaultSize); // TODO is there a way to do this with bulk methods? for (int i = 0; i < builder.size; ++i) { - builder.buffer.put(builder.offset + i, defaultBuffer.get(defaultOffset + i)); + builder.buffer.put(builder.offset + i, defaultBuffer.get(defaultOffset * 8 + i)); } return builder; } @@ -389,7 +395,7 @@ final class WireHelpers { Data.Builder builder = initDataPointer(refOffset, segment, defaultSize); // TODO is there a way to do this with bulk methods? for (int i = 0; i < builder.size; ++i) { - builder.buffer.put(builder.offset + i, defaultBuffer.get(defaultOffset + i)); + builder.buffer.put(builder.offset + i, defaultBuffer.get(defaultOffset * 8 + i)); } return builder; } @@ -413,13 +419,23 @@ final class WireHelpers { static StructReader readStructPointer(SegmentReader segment, int refOffset, + SegmentReader defaultSegment, + int defaultOffset, int nestingLimit) { - // TODO error handling. is_null + long ref = WirePointer.get(segment.buffer, refOffset); + if (WirePointer.isNull(ref)) { + if (defaultSegment == null) { + return new StructReader(); + } else { + return (new PointerReader(defaultSegment, defaultOffset, 0x7fffffff)).getStruct(); + } + } + if (nestingLimit <= 0) { throw new DecodeException("Message is too deeply nested or contains cycles."); } - long ref = WirePointer.get(segment.buffer, refOffset); + int refTarget = WirePointer.target(refOffset, ref); FollowFarsResult resolved = followFars(ref, refTarget, segment);