diff --git a/compiler/src/test/scala/org/capnproto/EncodingTest.scala b/compiler/src/test/scala/org/capnproto/EncodingTest.scala index 7b62e98..21598f9 100644 --- a/compiler/src/test/scala/org/capnproto/EncodingTest.scala +++ b/compiler/src/test/scala/org/capnproto/EncodingTest.scala @@ -122,7 +122,6 @@ class EncodingSuite extends FunSuite { val builder = new MessageBuilder(); val root = builder.initRoot(TestAnyPointer.factory); - val oldReader = { val oldVersion = root.getAnyPointerField().initAs(TestOldVersion.factory); oldVersion.setOld1(123); @@ -211,6 +210,17 @@ class EncodingSuite extends FunSuite { assert(12345 == GLOBAL_INT); } + test("EmptyStruct") { + val builder = new MessageBuilder(); + val root = builder.initRoot(TestAnyPointer.factory); + root.hasAnyPointerField() should equal (false); + val any = root.getAnyPointerField(); + any.isNull() should equal (true); + any.initAs(TestEmptyStruct.factory); + any.isNull() should equal (false); + root.hasAnyPointerField() should equal (true); + } + // to debug, do this: //Serialize.writeMessage((new java.io.FileOutputStream("/Users/dwrensha/Desktop/test.dat")).getChannel(), // message); diff --git a/runtime/src/main/java/org/capnproto/AnyPointer.java b/runtime/src/main/java/org/capnproto/AnyPointer.java index e28ea59..e5cdc1e 100644 --- a/runtime/src/main/java/org/capnproto/AnyPointer.java +++ b/runtime/src/main/java/org/capnproto/AnyPointer.java @@ -25,7 +25,7 @@ public final class AnyPointer { public final static class Reader { final SegmentReader segment; - final int pointer; + final int pointer; // offset in words final int nestingLimit; public Reader(SegmentReader segment, int pointer, int nestingLimit) { @@ -34,6 +34,10 @@ public final class AnyPointer { this.nestingLimit = nestingLimit; } + public final boolean isNull() { + return WirePointer.isNull(this.segment.buffer.getLong(this.pointer * Constants.BYTES_PER_WORD)); + } + public final T getAs(FromPointerReader factory) { return factory.fromPointerReader(this.segment, this.pointer, this.nestingLimit); } @@ -48,6 +52,10 @@ public final class AnyPointer { this.pointer = pointer; } + public final boolean isNull() { + return WirePointer.isNull(this.segment.buffer.getLong(this.pointer * Constants.BYTES_PER_WORD)); + } + public final T getAs(FromPointerBuilder factory) { return factory.fromPointerBuilder(this.segment, this.pointer); } diff --git a/runtime/src/main/java/org/capnproto/WireHelpers.java b/runtime/src/main/java/org/capnproto/WireHelpers.java index db527e4..875738f 100644 --- a/runtime/src/main/java/org/capnproto/WireHelpers.java +++ b/runtime/src/main/java/org/capnproto/WireHelpers.java @@ -48,7 +48,10 @@ final class WireHelpers { int amount, // in words byte kind) { - // TODO check for nullness, amount == 0 case. + if (amount == 0 && kind == WirePointer.STRUCT) { + WirePointer.setKindAndTargetForEmptyStruct(segment.buffer, refOffset); + return new AllocateResult(refOffset, refOffset, segment); + } int ptr = segment.allocate(amount); if (ptr == SegmentBuilder.FAILED_ALLOCATION) { diff --git a/runtime/src/main/java/org/capnproto/WirePointer.java b/runtime/src/main/java/org/capnproto/WirePointer.java index e5deda9..23920d4 100644 --- a/runtime/src/main/java/org/capnproto/WirePointer.java +++ b/runtime/src/main/java/org/capnproto/WirePointer.java @@ -50,6 +50,19 @@ final class WirePointer { (((targetOffset - offset) - 1) << 2) | kind); } + public static void setKindAndTargetForEmptyStruct(ByteBuffer buffer, int offset) { + //# This pointer points at an empty struct. Assuming the + //# WirePointer itself is in-bounds, we can set the target to + //# point either at the WirePointer itself or immediately after + //# it. The latter would cause the WirePointer to be "null" + //# (since for an empty struct the upper 32 bits are going to + //# be zero). So we set an offset of -1, as if the struct were + //# allocated immediately before this pointer, to distinguish + //# it from null. + + buffer.putInt(offset * 8, 0xfffffffc); + } + public static void setOffsetAndKind(ByteBuffer buffer, int offset, int offsetAndKind) { buffer.putInt(offset * 8, offsetAndKind); }