From 07788c83fc2533ccc72a79ebafb00df7b94c5439 Mon Sep 17 00:00:00 2001 From: Adam Rosenberger Date: Thu, 15 May 2014 19:12:58 -0400 Subject: [PATCH] Moved files, updated readme, added src/main/generated to build.scala for IDE support --- Makefile | 52 +- README.md | 14 +- .../capnproto/examples/AddressbookMain.java | 14 +- examples/src/main/schema/addressbook.capnp | 3 + .../src/main/cpp/compiler/capnpc-java.c++ | 24 +- project/build.scala | 2 + src/capnp/AnyPointer.java | 17 - src/capnp/DecodeException.java | 7 - src/capnp/FieldSize.java | 12 - src/capnp/FromStructBuilder.java | 6 - src/capnp/FromStructReader.java | 5 - src/capnp/InputStreamMessageReader.java | 84 - src/capnp/ListBuilder.java | 24 - src/capnp/ListPointer.java | 17 - src/capnp/ListReader.java | 52 - src/capnp/MessageBuilder.java | 11 - src/capnp/MessageReader.java | 20 - src/capnp/PointerBuilder.java | 20 - src/capnp/PointerReader.java | 49 - src/capnp/SegmentBuilder.java | 34 - src/capnp/SegmentReader.java | 11 - src/capnp/StructBuilder.java | 42 - src/capnp/StructList.java | 34 - src/capnp/StructPointer.java | 17 - src/capnp/StructReader.java | 71 - src/capnp/StructSize.java | 18 - src/capnp/Text.java | 45 - src/capnp/WireHelpers.java | 174 -- src/capnp/WirePointer.java | 51 - src/capnp/WordPointer.java | 13 - src/capnp/layout.java | 3 - src/compiler/capnpc-java.c++ | 1639 ----------------- 32 files changed, 48 insertions(+), 2537 deletions(-) delete mode 100644 src/capnp/AnyPointer.java delete mode 100644 src/capnp/DecodeException.java delete mode 100644 src/capnp/FieldSize.java delete mode 100644 src/capnp/FromStructBuilder.java delete mode 100644 src/capnp/FromStructReader.java delete mode 100644 src/capnp/InputStreamMessageReader.java delete mode 100644 src/capnp/ListBuilder.java delete mode 100644 src/capnp/ListPointer.java delete mode 100644 src/capnp/ListReader.java delete mode 100644 src/capnp/MessageBuilder.java delete mode 100644 src/capnp/MessageReader.java delete mode 100644 src/capnp/PointerBuilder.java delete mode 100644 src/capnp/PointerReader.java delete mode 100644 src/capnp/SegmentBuilder.java delete mode 100644 src/capnp/SegmentReader.java delete mode 100644 src/capnp/StructBuilder.java delete mode 100644 src/capnp/StructList.java delete mode 100644 src/capnp/StructPointer.java delete mode 100644 src/capnp/StructReader.java delete mode 100644 src/capnp/StructSize.java delete mode 100644 src/capnp/Text.java delete mode 100644 src/capnp/WireHelpers.java delete mode 100644 src/capnp/WirePointer.java delete mode 100644 src/capnp/WordPointer.java delete mode 100644 src/capnp/layout.java delete mode 100644 src/compiler/capnpc-java.c++ diff --git a/Makefile b/Makefile index 8e24093..528646c 100644 --- a/Makefile +++ b/Makefile @@ -1,51 +1,19 @@ -CXX=g++ -std=c++11 +CXX=clang++ -std=c++11 -stdlib=libc++ `pkg-config capnp --cflags --libs` -CAPNP_SOURCES=\ - src/capnp/AnyPointer.java\ - src/capnp/DecodeException.java\ - src/capnp/FieldSize.java\ - src/capnp/FromStructBuilder.java\ - src/capnp/FromStructReader.java\ - src/capnp/InputStreamMessageReader.java\ - src/capnp/ListPointer.java\ - src/capnp/ListBuilder.java\ - src/capnp/ListReader.java\ - src/capnp/MessageBuilder.java\ - src/capnp/MessageReader.java\ - src/capnp/PointerBuilder.java\ - src/capnp/PointerReader.java\ - src/capnp/SegmentBuilder.java\ - src/capnp/SegmentReader.java\ - src/capnp/StructBuilder.java\ - src/capnp/StructList.java\ - src/capnp/StructPointer.java\ - src/capnp/StructReader.java\ - src/capnp/StructSize.java\ - src/capnp/Text.java\ - src/capnp/WireHelpers.java\ - src/capnp/WirePointer.java\ - src/capnp/WordPointer.java - -CAPNP_COMPILATION_MARKER=org/capnproto/PointerReader.class - -CAPNPC_JAVA_SOURCES=src/compiler/capnpc-java.c++ +CAPNPC_JAVA_SOURCES=generator/src/main/cpp/compiler/capnpc-java.c++ .PHONY: all clean addressbook -all : capnpc-java addressbook capnp +all : capnpc-java addressbook clean : - rm -rf capnpc-java org examples/*.class - -capnp : $(CAPNP_COMPILATION_MARKER) - -$(CAPNP_COMPILATION_MARKER) : $(CAPNP_SOURCES) - javac -d . $(CAPNP_SOURCES) + rm capnpc-java + sbt clean capnpc-java : $(CAPNPC_JAVA_SOURCES) - $(CXX) -I/usr/local/include -L/usr/local/lib -lkj -lcapnp $(CAPNPC_JAVA_SOURCES) -o capnpc-java + $(CXX) -I/usr/local/include -g $(CAPNPC_JAVA_SOURCES) -o capnpc-java - -addressbook : capnp capnpc-java examples/AddressbookMain.java - capnp compile -o ./capnpc-java examples/addressbook.capnp - javac -cp .:examples examples/AddressbookMain.java +addressbook : capnpc-java + PWD=pwd + capnp compile -I$(PWD)/generator/src/main/cpp/compiler --src-prefix=examples/src/main/schema -o./capnpc-java:examples/src/main/generated examples/src/main/schema/addressbook.capnp + sbt examples/"run read" diff --git a/README.md b/README.md index a38c16f..34d51d6 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,11 @@ This is an experimental pure Java implementation of Cap'n Proto. -It doesn't do much yet. +It doesn't do much yet. An attempt to use SBT as the build system and integration with `make` is currently underway. -To get started, try this: +To get started with SBT, visit https://github.com/paulp/sbt-extras or to run direct, try `curl -s https://raw.githubusercontent.com/paulp/sbt-extras/master/sbt > ~/bin/sbt && chmod 0755 ~/bin/sbt` + +When you first build the project, try running `sbt update gen-idea`. This will bootstrap SBT and generate IntelliJ project files for those who wish to develop in an IDE. + +When running `make`, the supporting Java code will be built, and the sample schema will be run through the code generator as well to produce the Java binding. You can find the generated code in `/examples/src/main/generated/Addressbook.java` -``` -$ make -$ cd examples -$ echo '(people = [(id = 123, name = "Alice", email = "alice@example.com", employment = (school = "MIT"))])' \ - | capnp encode addressbook.capnp AddressBook | java -cp .:.. AddressbookMain read -``` \ No newline at end of file diff --git a/examples/src/main/java/org/capnproto/examples/AddressbookMain.java b/examples/src/main/java/org/capnproto/examples/AddressbookMain.java index a190733..c1f98ee 100644 --- a/examples/src/main/java/org/capnproto/examples/AddressbookMain.java +++ b/examples/src/main/java/org/capnproto/examples/AddressbookMain.java @@ -4,6 +4,8 @@ import org.capnproto.MessageReader; import org.capnproto.StructList; import org.capnproto.InputStreamMessageReader; +import org.capnproto.examples.Addressbook.*; + public class AddressbookMain { public static void writeAddressBook() { @@ -12,16 +14,16 @@ public class AddressbookMain { public static void printAddressBook() throws java.io.IOException { MessageReader message = InputStreamMessageReader.create(System.in); - Addressbook.AddressBook.Reader addressbook = message.getRoot(Addressbook.AddressBook.Reader.factory); - StructList.Reader people = addressbook.getPeople(); + AddressBook.Reader addressbook = message.getRoot(AddressBook.Reader.factory); + StructList.Reader people = addressbook.getPeople(); int size = people.size(); for(int ii = 0; ii < size; ++ii) { - Addressbook.Person.Reader person = people.get(ii); + Person.Reader person = people.get(ii); System.out.println(person.getName() + ": " + person.getEmail()); - StructList.Reader phones = person.getPhones(); + StructList.Reader phones = person.getPhones(); for (int jj = 0; jj < phones.size(); ++jj) { - Addressbook.Person.PhoneNumber.Reader phone = phones.get(jj); + Person.PhoneNumber.Reader phone = phones.get(jj); String typeName = "UNKNOWN"; switch (phone.getType()) { case MOBILE : @@ -37,7 +39,7 @@ public class AddressbookMain { System.out.println(" " + typeName + " phone: " + phone.getNumber()); } - Addressbook.Person.Employment.Reader employment = person.getEmployment(); + Person.Employment.Reader employment = person.getEmployment(); switch (employment.which()) { case UNEMPLOYED : System.out.println(" unemployed"); diff --git a/examples/src/main/schema/addressbook.capnp b/examples/src/main/schema/addressbook.capnp index 9c9b9ad..4981bf3 100644 --- a/examples/src/main/schema/addressbook.capnp +++ b/examples/src/main/schema/addressbook.capnp @@ -26,6 +26,9 @@ using Cxx = import "/capnp/c++.capnp"; $Cxx.namespace("addressbook"); +using Java = import "/java_support/java.capnp"; +$Java.package("org.capnproto.examples"); + struct Person { id @0 :UInt32; name @1 :Text; diff --git a/generator/src/main/cpp/compiler/capnpc-java.c++ b/generator/src/main/cpp/compiler/capnpc-java.c++ index f6ee5bc..8ebffb7 100644 --- a/generator/src/main/cpp/compiler/capnpc-java.c++ +++ b/generator/src/main/cpp/compiler/capnpc-java.c++ @@ -27,13 +27,13 @@ #include -#include "capnp/serialize.h" +#include #include #include #include #include -#include "capnp/schema-loader.h" -#include "capnp/dynamic.h" +#include +#include #include #include #include @@ -57,6 +57,7 @@ namespace capnp { namespace { static constexpr uint64_t NAMESPACE_ANNOTATION_ID = 0xb9c6f99ebf805f2cull; +static constexpr uint64_t PACKAGE_ANNOTATION_ID = 0x9ee4c8f803b3b596ull; static constexpr const char* FIELD_SIZE_NAMES[] = { "VOID", "BIT", "BYTE", "TWO_BYTES", "FOUR_BYTES", "EIGHT_BYTES", "POINTER", "INLINE_COMPOSITE" @@ -1508,6 +1509,7 @@ private: kj::Vector> namespaceParts; kj::String namespacePrefix; + kj::StringPtr packageName; for (auto annotation: node.getAnnotations()) { if (annotation.getId() == NAMESPACE_ANNOTATION_ID) { @@ -1532,6 +1534,18 @@ private: break; } } + + for (auto annotation: node.getAnnotations()) { + if (annotation.getId() == PACKAGE_ANNOTATION_ID) { + packageName = annotation.getValue().getText(); + break; + } + } + + if (packageName.size() == 0) { + context.exitError(kj::str(displayName, ": must provide a Java package name.")); + } + auto nodeTexts = KJ_MAP(nested, node.getNestedNodes()) { return makeNodeText(namespacePrefix, "", nested.getName(), schemaLoader.get(nested.getId()), 1); }; @@ -1551,8 +1565,8 @@ private: return FileText { kj::strTree( "// Generated by Cap'n Proto compiler, DO NOT EDIT\n" - "// source: ", baseName(displayName), "\n", - "\n", + "// source: ", baseName(displayName), "\n\n", + "package ", packageName, ";\n\n", //"import org.capnproto;\n", // KJ_MAP(n, namespaceParts) { return kj::strTree("namespace ", n, " {\n"); }, "\n", "public class ", outerClassName, " {\n", diff --git a/project/build.scala b/project/build.scala index 3dbb063..4a66949 100644 --- a/project/build.scala +++ b/project/build.scala @@ -1,5 +1,6 @@ import sbt.Keys._ import sbt._ +import org.sbtidea.SbtIdeaPlugin._ object Build extends sbt.Build { @@ -21,6 +22,7 @@ object Build extends sbt.Build { id = "examples", base = file("examples") ).dependsOn(generator) + .settings(unmanagedSourceDirectories in Compile += sourceDirectory.value / "main" / "generated") .settings(publish := {}) .settings(publishLocal := {}) .settings(fork in run := true) diff --git a/src/capnp/AnyPointer.java b/src/capnp/AnyPointer.java deleted file mode 100644 index 26346e8..0000000 --- a/src/capnp/AnyPointer.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.capnproto; - -public class AnyPointer { - - public static class Reader { - public PointerReader reader; - - public Reader(PointerReader reader) { - this.reader = reader; - } - - public T getAsStruct(FromStructReader factory) { - return factory.fromStructReader(this.reader.getStruct()); - } - } - -} diff --git a/src/capnp/DecodeException.java b/src/capnp/DecodeException.java deleted file mode 100644 index 4aad297..0000000 --- a/src/capnp/DecodeException.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.capnproto; - -public class DecodeException extends RuntimeException { - public DecodeException(String message) { - super(message); - } -} diff --git a/src/capnp/FieldSize.java b/src/capnp/FieldSize.java deleted file mode 100644 index 52886ad..0000000 --- a/src/capnp/FieldSize.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.capnproto; - -public class FieldSize { - public static final byte VOID = 0; - public static final byte BIT = 1; - public static final byte BYTE = 2; - public static final byte TWO_BYTES = 3; - public static final byte FOUR_BYTES = 4; - public static final byte EIGHT_BYTES = 5; - public static final byte POINTER = 6; - public static final byte INLINE_COMPOSITE = 7; -} diff --git a/src/capnp/FromStructBuilder.java b/src/capnp/FromStructBuilder.java deleted file mode 100644 index 4b44e0b..0000000 --- a/src/capnp/FromStructBuilder.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.capnproto; - -public interface FromStructBuilder { - public abstract T fromStructBuilder(StructBuilder builder); - public abstract StructSize structSize(); -} diff --git a/src/capnp/FromStructReader.java b/src/capnp/FromStructReader.java deleted file mode 100644 index eaf1413..0000000 --- a/src/capnp/FromStructReader.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.capnproto; - -public interface FromStructReader { - public abstract T fromStructReader(StructReader reader); -} diff --git a/src/capnp/InputStreamMessageReader.java b/src/capnp/InputStreamMessageReader.java deleted file mode 100644 index 1d8f796..0000000 --- a/src/capnp/InputStreamMessageReader.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.capnproto; - -import java.io.InputStream; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Vector; - - -public class InputStreamMessageReader { - - static byte[] readExact(InputStream is, int length) throws IOException { - byte[] bytes = new byte[length]; - - int bytesRead = 0; - while (bytesRead < length) { - int r = is.read(bytes, bytesRead, length - bytesRead); - if (r < 0) { - throw new IOException("premature EOF"); - } - bytesRead += r; - } - - return bytes; - } - - static ByteBuffer makeByteBuffer(byte[] bytes) { - ByteBuffer result = ByteBuffer.wrap(bytes); - result.order(ByteOrder.LITTLE_ENDIAN); - result.mark(); - return result; - } - - public static MessageReader create(InputStream is) throws IOException { - ByteBuffer firstWord = makeByteBuffer(readExact(is, 8)); - - int segmentCount = 1 + firstWord.getInt(0); - - int segment0Size = 0; - if (segmentCount > 0) { - segment0Size = firstWord.getInt(4); - } - - int totalWords = segment0Size; - - if (segmentCount > 512) { - throw new IOException("too many segments"); - } - - // in words - Vector moreSizes = new Vector(); - - if (segmentCount > 1) { - ByteBuffer moreSizesRaw = makeByteBuffer(readExact(is, 4 * (segmentCount & ~1))); - for(int ii = 0; ii < segmentCount - 1; ++ii) { - int size = moreSizesRaw.getInt(ii * 4); - moreSizes.add(size); - totalWords += size; - } - } - - // TODO check that totalWords is reasonable - - byte[] allSegments = readExact(is, totalWords * 8); - - ByteBuffer[] segmentSlices = new ByteBuffer[segmentCount]; - - segmentSlices[0] = ByteBuffer.wrap(allSegments, 0, segment0Size * 8); - segmentSlices[0].order(ByteOrder.LITTLE_ENDIAN); - segmentSlices[0].mark(); - - int offset = segment0Size; - - for (int ii = 1; ii < segmentCount; ++ii) { - segmentSlices[ii] = ByteBuffer.wrap(allSegments, offset * 8, moreSizes.get(ii - 1) * 8); - segmentSlices[ii].order(ByteOrder.LITTLE_ENDIAN); - segmentSlices[ii].mark(); - offset += moreSizes.get(ii - 1); - } - - return new MessageReader(segmentSlices); - } - -} diff --git a/src/capnp/ListBuilder.java b/src/capnp/ListBuilder.java deleted file mode 100644 index cb5edbe..0000000 --- a/src/capnp/ListBuilder.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.capnproto; - -public final class ListBuilder { - SegmentBuilder segment; - int ptr; // byte offset to front of list - int elementCount; - int step; // in bits - int structDataSize; // in bits - short structPointerCount; - - public ListBuilder(SegmentBuilder segment, int ptr, - int elementCount, int step, - int structDataSize, short structPointerCount) { - this.segment = segment; - this.ptr = ptr; - this.elementCount = elementCount; - this.step = step; - this.structDataSize = structDataSize; - this.structPointerCount = structPointerCount; - } - - - -} diff --git a/src/capnp/ListPointer.java b/src/capnp/ListPointer.java deleted file mode 100644 index faafa97..0000000 --- a/src/capnp/ListPointer.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.capnproto; - -import java.nio.ByteBuffer; - -final class ListPointer { - public static byte elementSize(int elementSizeAndCount) { - return (byte) (elementSizeAndCount & 7); - } - - public static int elementCount(int elementSizeAndCount) { - return elementSizeAndCount >> 3; - } - - public static int inlineCompositeWordCount(int elementSizeAndCount) { - return elementCount(elementSizeAndCount); - } -} diff --git a/src/capnp/ListReader.java b/src/capnp/ListReader.java deleted file mode 100644 index 4c019f9..0000000 --- a/src/capnp/ListReader.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.capnproto; - -public class ListReader { - SegmentReader segment; - int ptr; // byte offset to front of list - int elementCount; - int step; // in bits - int structDataSize; // in bits - short structPointerCount; - int nestingLimit; - - - public ListReader () { - this.segment = null; - this.ptr = 0; - this.elementCount = 0; - this.step = 0; - this.structDataSize = 0; - this.structPointerCount = 0; - this.nestingLimit = 0x7fffffff; - } - - public ListReader(SegmentReader segment, int ptr, - int elementCount, int step, - int structDataSize, short structPointerCount, - int nestingLimit) { - this.segment = segment; - this.ptr = ptr; - this.elementCount = elementCount; - this.step = step; - this.structDataSize = structDataSize; - this.structPointerCount = structPointerCount; - this.nestingLimit = nestingLimit; - - } - - public int size() { - return this.elementCount; - } - - public StructReader getStructElement(int index) { - // TODO check nesting limit - - int indexBit = index * this.step; - - int structData = this.ptr + (indexBit / 8); - int structPointers = structData + (this.structDataSize / 8); - - return new StructReader(this.segment, structData, structPointers / 8, this.structDataSize, - this.structPointerCount, (byte)(indexBit % 8), this.nestingLimit - 1); - } -} diff --git a/src/capnp/MessageBuilder.java b/src/capnp/MessageBuilder.java deleted file mode 100644 index d54e9b8..0000000 --- a/src/capnp/MessageBuilder.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.capnproto; - -public final class MessageBuilder { - public T getRoot(FromStructBuilder factory) { - throw new Error("unimplemented"); - } - - public T initRoot(FromStructBuilder factory) { - throw new Error("unimplemented"); - } -} diff --git a/src/capnp/MessageReader.java b/src/capnp/MessageReader.java deleted file mode 100644 index 1337184..0000000 --- a/src/capnp/MessageReader.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.capnproto; - -import java.nio.ByteBuffer; - -public class MessageReader { - ByteBuffer[] segmentSlices; - - public MessageReader(ByteBuffer[] segmentSlices) { - this.segmentSlices = segmentSlices; - } - - public T getRoot(FromStructReader factory) { - SegmentReader segment = new SegmentReader(this.segmentSlices[0]); - PointerReader pointerReader = PointerReader.getRoot(segment, - new WordPointer(this.segmentSlices[0], 0), - 0x7fffffff /* XXX */); - AnyPointer.Reader any = new AnyPointer.Reader(pointerReader); - return any.getAsStruct(factory); - } -} diff --git a/src/capnp/PointerBuilder.java b/src/capnp/PointerBuilder.java deleted file mode 100644 index 24faeed..0000000 --- a/src/capnp/PointerBuilder.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.capnproto; - -public final class PointerBuilder { - public SegmentBuilder segment; - public int pointer; // word offset - - public PointerBuilder(SegmentBuilder segment, int pointer) { - this.segment = segment; - this.pointer = pointer; - } - - public final ListBuilder initStructList(int elementCount, StructSize elementSize) { - return WireHelpers.initStructListPointer(this.pointer, this.segment, elementCount, elementSize); - } - - public final void setText(Text.Reader value) { - WireHelpers.setTextPointer(this.pointer, this.segment, value); - } - -} diff --git a/src/capnp/PointerReader.java b/src/capnp/PointerReader.java deleted file mode 100644 index 8f2e27c..0000000 --- a/src/capnp/PointerReader.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.capnproto; - -public class PointerReader { - public SegmentReader segment; - public int pointer; // word offset - public int nestingLimit; - - public PointerReader() { - this.segment = null; - this.pointer = 0; // XXX ? - this.nestingLimit = 0x7fffffff; - } - - public PointerReader(SegmentReader segment, int pointer, int nestingLimit) { - this.segment = segment; - this.pointer = pointer; - this.nestingLimit = nestingLimit; - } - - public static PointerReader getRoot(SegmentReader segment, - WordPointer location, - int nestingLimit) { - // TODO bounds check - return new PointerReader(segment, location.offset, nestingLimit); - } - - public boolean isNull() { - return this.segment.buffer.getLong(this.pointer) == 0; - } - - public StructReader getStruct() { - return WireHelpers.readStructPointer(this.segment, - this.pointer, - this.nestingLimit); - } - - public ListReader getList(byte expectedElementSize) { - // TODO check nullness - return WireHelpers.readListPointer(this.segment, - this.pointer, - expectedElementSize, - this.nestingLimit); - } - - public Text.Reader getText() { - return WireHelpers.readTextPointer(this.segment, - this.pointer); - } -} diff --git a/src/capnp/SegmentBuilder.java b/src/capnp/SegmentBuilder.java deleted file mode 100644 index 08e1160..0000000 --- a/src/capnp/SegmentBuilder.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.capnproto; - -import java.nio.ByteBuffer; - -public class SegmentBuilder extends SegmentReader { - public int pos = 0; // in words - - public static final int FAILED_ALLOCATION = -1; - - public SegmentBuilder(ByteBuffer buf) { - super(buf); - } - - // the total number of words the buffer can hold - private final int capacity() { - this.buffer.reset(); - return this.buffer.remaining() / 8; - } - - // return how many words have already been allocated - private final int currentSize() { - return this.pos; - } - - public final int allocate(int amount) { - if (amount > this.capacity() - this.currentSize()) { - return FAILED_ALLOCATION; // no space left; - } else { - int result = this.pos; - this.pos += amount; - return result; - } - } -} diff --git a/src/capnp/SegmentReader.java b/src/capnp/SegmentReader.java deleted file mode 100644 index bc53125..0000000 --- a/src/capnp/SegmentReader.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.capnproto; - -import java.nio.ByteBuffer; - -public class SegmentReader { - ByteBuffer buffer; - - public SegmentReader(ByteBuffer buffer) { - this.buffer = buffer; - } -} diff --git a/src/capnp/StructBuilder.java b/src/capnp/StructBuilder.java deleted file mode 100644 index 3ff05c0..0000000 --- a/src/capnp/StructBuilder.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.capnproto; - -public final class StructBuilder { - public SegmentBuilder segment; - public int data; //byte offset to data section - public int pointers; // word offset of pointer section - public int dataSize; // in bits - public short pointerCount; - public byte bit0Offset; - - public StructBuilder(SegmentBuilder segment, int data, - int pointers, int dataSize, short pointerCount, - byte bit0Offset) { - this.segment = segment; - this.data = data; - this.pointers = pointers; - this.dataSize = dataSize; - this.pointerCount = pointerCount; - this.bit0Offset = bit0Offset; - } - - public final int getShortField(int offset) { - return this.segment.buffer.getShort(this.data + offset * 2); - } - - public final void setShortField(int offset, short value) { - this.segment.buffer.putShort(this.data + offset * 2, value); - } - - public final int getIntField(int offset) { - return this.segment.buffer.getInt(this.data + offset * 4); - } - - public final void setIntField(int offset, int value) { - this.segment.buffer.putInt(this.data + offset * 4, value); - } - - public final PointerBuilder getPointerField(int index) { - return new PointerBuilder(this.segment, this.pointers + index); - } - -} diff --git a/src/capnp/StructList.java b/src/capnp/StructList.java deleted file mode 100644 index 4027907..0000000 --- a/src/capnp/StructList.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.capnproto; - - -public final class StructList { - public static final class Reader { - public ListReader reader; - public final FromStructReader factory; - - public Reader(ListReader reader, FromStructReader factory) { - this.reader = reader; - this.factory = factory; - } - - public int size() { - return this.reader.size(); - } - - public T get(int index) { - return this.factory.fromStructReader(this.reader.getStructElement(index)); - } - } - - public static final class Builder { - public ListBuilder builder; - public final FromStructBuilder factory; - - public Builder(ListBuilder builder, FromStructBuilder factory) { - this.builder = builder; - this.factory = factory; - } - - } - -} diff --git a/src/capnp/StructPointer.java b/src/capnp/StructPointer.java deleted file mode 100644 index 656d696..0000000 --- a/src/capnp/StructPointer.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.capnproto; - -import java.nio.ByteBuffer; - -final class StructPointer{ - public static short dataSize(int structRef) { - return (short)(structRef & 0xffff); - } - - public static short ptrCount(int structRef) { - return (short)(structRef >> 16); - } - - public static int wordSize(int structRef) { - return (int)dataSize(structRef) + (int)ptrCount(structRef); - } -} diff --git a/src/capnp/StructReader.java b/src/capnp/StructReader.java deleted file mode 100644 index 23c45f9..0000000 --- a/src/capnp/StructReader.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.capnproto; - -public final class StructReader { - public SegmentReader segment; - public int data; //byte offset to data section - public int pointers; // word offset of pointer section - public int dataSize; // in bits - public short pointerCount; - public byte bit0Offset; - public int nestingLimit; - - - public StructReader(SegmentReader segment, int data, - int pointers, int dataSize, short pointerCount, - byte bit0Offset, int nestingLimit) { - this.segment = segment; - this.data = data; - this.pointers = pointers; - this.dataSize = dataSize; - this.pointerCount = pointerCount; - this.bit0Offset = bit0Offset; - this.nestingLimit = nestingLimit; - } - - public final boolean getBoolField(int offset) { - // XXX should use unsigned operations - if (offset < this.dataSize) { - if (offset == 0) { - offset = this.bit0Offset; - } - byte b = this.segment.buffer.get(offset / 8); - return (b & (1 << (offset % 8))) != 0; - } else { - return false; - } - } - - public final byte getByteField(int offset) { - if ((offset + 1) * 8 <= this.dataSize) { - return this.segment.buffer.get(this.data + offset); - } else { - return 0; - } - } - - public final byte getShortField(int offset) { - if ((offset + 1) * 16 <= this.dataSize) { - return this.segment.buffer.get(this.data + offset * 2); - } else { - return 0; - } - } - - public final int getIntField(int offset) { - if ((offset + 1) * 32 <= this.dataSize) { - return this.segment.buffer.getInt(this.data + offset * 4); - } else { - return 0; - } - } - - public final PointerReader getPointerField(int ptrIndex) { - if (ptrIndex < this.pointerCount) { - return new PointerReader(this.segment, - this.pointers + ptrIndex, - this.nestingLimit); - } else { - return new PointerReader(); - } - } -} diff --git a/src/capnp/StructSize.java b/src/capnp/StructSize.java deleted file mode 100644 index 835561d..0000000 --- a/src/capnp/StructSize.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.capnproto; - -public final class StructSize { - public final short data; // number of words in data section - public final short pointers; // number of words in pointer section - public final byte preferredListEncoding; // a FieldSize - - public StructSize(short data, short pointers, byte preferredListEncoding) { - this.data = data; - this.pointers = pointers; - this.preferredListEncoding = preferredListEncoding; - } - - public final int total() { - return (int)this.data + (int)this.pointers; - } - -} diff --git a/src/capnp/Text.java b/src/capnp/Text.java deleted file mode 100644 index 5bad020..0000000 --- a/src/capnp/Text.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.capnproto; - -import java.nio.ByteBuffer; - -public class Text { - - public static class Reader { - public final ByteBuffer buffer; - public final int offset; // in bytes - public final int size; // in bytes - - public Reader(ByteBuffer buffer, int offset, int size) { - this.buffer = buffer; - this.offset = offset * 8; - this.size = size; - } - - public Reader(String value) { - try { - byte[] bytes = value.getBytes("UTF-8"); - this.buffer = ByteBuffer.wrap(bytes); - this.offset = 0; - this.size = bytes.length; - } catch (java.io.UnsupportedEncodingException e) { - throw new Error("UTF-8 is unsupported"); - } - } - - @Override - public final String toString() { - byte[] bytes = new byte[this.size]; - - this.buffer.position(this.offset); - this.buffer.get(bytes, 0, this.size); - - try { - return new String(bytes, "UTF-8"); - } catch(java.io.UnsupportedEncodingException e) { - return "unsupported encoding"; // XXX - } - } - - } - -} diff --git a/src/capnp/WireHelpers.java b/src/capnp/WireHelpers.java deleted file mode 100644 index 8314dc7..0000000 --- a/src/capnp/WireHelpers.java +++ /dev/null @@ -1,174 +0,0 @@ -package org.capnproto; - -final class WireHelpers { - - public static int roundBytesUpToWords(int bytes) { - return (bytes + 7) / 8; - } - - public static int allocate(int refOffset, - SegmentBuilder segment, - int amount, - byte kind) { - - // TODO check for nullness, amount == 0 case. - - int allocation = segment.allocate(amount); - if (allocation == SegmentBuilder.FAILED_ALLOCATION) { - //# Need to allocate in a new segment. We'll need to - //# allocate an extra pointer worth of space to act as - //# the landing pad for a far pointer. - throw new Error("unimplemented"); - } else { - WirePointer.setKindAndTarget(segment.buffer, refOffset, kind, allocation); - return allocation; - } - } - - public static ListBuilder initListPointer(int refOffset, - SegmentBuilder segment, - int elementCount, - byte elementSize) { - throw new Error("unimplemented"); - } - - public static ListBuilder initStructListPointer(int refOffset, - SegmentBuilder segment, - int elementCount, - StructSize elementSize) { - if (elementSize.preferredListEncoding != FieldSize.INLINE_COMPOSITE) { - //# Small data-only struct. Allocate a list of primitives instead. - return initListPointer(refOffset, segment, elementCount, - elementSize.preferredListEncoding); - } - - int wordsPerElement = elementSize.total(); - - throw new Error("unimplemented"); - } - - // size is in bytes - public static void initTextPointer(int refOffset, - SegmentBuilder segment, - int size) { - //# The byte list must include a NUL terminator. - int byteSize = size + 1; - - int ptrOffset = allocate(refOffset, segment, roundBytesUpToWords(byteSize), WirePointer.LIST); - - throw new Error("unimplemented"); - } - - public static void setTextPointer(int refOffset, - SegmentBuilder segment, - Text.Reader value) { - throw new Error("unimplemented"); - } - - public static StructReader readStructPointer(SegmentReader segment, - int refOffset, - int nestingLimit) { - - // TODO error handling - - if (nestingLimit < 0) { - throw new DecodeException("Message is too deeply nested or contains cycles."); - } - - long ref = WirePointer.get(segment.buffer, refOffset); - int ptrOffset = WirePointer.target(refOffset, ref); - int structPtr = WirePointer.structPointer(ref); - int dataSizeWords = StructPointer.dataSize(structPtr); - - return new StructReader(segment, - ptrOffset * 8, - (ptrOffset + dataSizeWords), - dataSizeWords * 64, - StructPointer.ptrCount(structPtr), - (byte)0, - nestingLimit - 1); - - } - - - public static ListReader readListPointer(SegmentReader segment, - int refOffset, - byte expectedElementSize, - int nestingLimit) { - - long ref = WirePointer.get(segment.buffer, refOffset); - - // TODO check for null, follow fars, nestingLimit - if (WirePointer.isNull(ref)) { - return new ListReader(); - } - - int listPtr = WirePointer.listPointer(ref); - - int ptrOffset = WirePointer.target(refOffset, ref); - long ptr = WirePointer.get(segment.buffer, ptrOffset); - - switch (ListPointer.elementSize(listPtr)) { - case FieldSize.INLINE_COMPOSITE : { - int wordCount = ListPointer.inlineCompositeWordCount(listPtr); - - long tag = ptr; - ptrOffset += 1; - - // TODO bounds check - - int size = WirePointer.inlineCompositeListElementCount(tag); - - int structPtr = WirePointer.structPointer(tag); - int wordsPerElement = StructPointer.wordSize(structPtr); - - // TODO check that elemements do not overrun word count - - // TODO check whether the size is compatible - - return new ListReader(segment, // TODO follow fars - ptrOffset * 8, // - size, - wordsPerElement * 64, - StructPointer.dataSize(structPtr) * 64, - StructPointer.ptrCount(structPtr), - nestingLimit - 1); - } - case FieldSize.VOID : break; - default : - throw new Error("unrecognized element size"); - } - - throw new Error(); - } - - public static Text.Reader readTextPointer(SegmentReader segment, - int refOffset) { - long ref = WirePointer.get(segment.buffer, refOffset); - - if (WirePointer.isNull(ref)) { - // XXX should use the default value - return new Text.Reader(java.nio.ByteBuffer.wrap(new byte[0]), 0, 0); - } - - int ptrOffset = WirePointer.target(refOffset, ref); - int listPtr = WirePointer.listPointer(ref); - int size = ListPointer.elementCount(listPtr); - - if (WirePointer.kind(ref) != WirePointer.LIST) { - throw new DecodeException("Message contains non-list pointer where text was expected."); - } - - if (ListPointer.elementSize(listPtr) != FieldSize.BYTE) { - throw new DecodeException("Message contains list pointer of non-bytes where text was expected."); - } - - // TODO bounds check? - - if (size == 0 || segment.buffer.get(8 * ptrOffset + size - 1) != 0) { - throw new DecodeException("Message contains text that is not NUL-terminated."); - } - - return new Text.Reader(segment.buffer, ptrOffset, size - 1); - } -} diff --git a/src/capnp/WirePointer.java b/src/capnp/WirePointer.java deleted file mode 100644 index 9c90f94..0000000 --- a/src/capnp/WirePointer.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.capnproto; - -import java.nio.ByteBuffer; - -final class WirePointer { - public static final byte STRUCT = 0; - public static final byte LIST = 1; - public static final byte FAR = 2; - public static final byte OTHER = 3; - - public static boolean isNull(long wirePointer) { - return wirePointer == 0; - } - - public static int offsetAndKind(long wirePointer) { - return (int)(wirePointer & 0xffffffff); - } - - public static byte kind(long wirePointer) { - return (byte)(offsetAndKind(wirePointer) & 3); - } - - public static int target(int offset, long wirePointer) { - return offset + 1 + (offsetAndKind(wirePointer) >> 2); - } - - public static void setKindAndTarget(ByteBuffer buffer, int offset, byte kind, int targetOffset) { - buffer.putInt(offset * 8, - (((targetOffset - offset) - 1) << 2) | kind); - } - - public static int inlineCompositeListElementCount(long wirePointer) { - return offsetAndKind(wirePointer) >> 2; - } - - public static int upper32Bits(long wirePointer) { - return (int)(wirePointer >> 32); - } - - public static int listPointer(long wirePointer) { - return upper32Bits(wirePointer); - } - - public static int structPointer(long wirePointer) { - return upper32Bits(wirePointer); - } - - public static long get(ByteBuffer buffer, int offset) { - return buffer.getLong(offset * 8); - } -} diff --git a/src/capnp/WordPointer.java b/src/capnp/WordPointer.java deleted file mode 100644 index 8ba7f20..0000000 --- a/src/capnp/WordPointer.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.capnproto; - -import java.nio.ByteBuffer; - -class WordPointer { - public final ByteBuffer buffer; - public int offset; // in words - - public WordPointer(ByteBuffer buffer, int offset) { - this.buffer = buffer; - this.offset = offset; - } -} diff --git a/src/capnp/layout.java b/src/capnp/layout.java deleted file mode 100644 index d8da6a5..0000000 --- a/src/capnp/layout.java +++ /dev/null @@ -1,3 +0,0 @@ -package org.capnproto; - - diff --git a/src/compiler/capnpc-java.c++ b/src/compiler/capnpc-java.c++ deleted file mode 100644 index f6ee5bc..0000000 --- a/src/compiler/capnpc-java.c++ +++ /dev/null @@ -1,1639 +0,0 @@ -// 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. - - -// This program is a code generator plugin for `capnp compile` which generates java code. -// It is a modified version of the C++ code generator plugin, capnpc-c++. - - -#include -#include "capnp/serialize.h" -#include -#include -#include -#include -#include "capnp/schema-loader.h" -#include "capnp/dynamic.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#ifndef VERSION -#define VERSION "(unknown)" -#endif - -namespace capnp { -namespace { - -static constexpr uint64_t NAMESPACE_ANNOTATION_ID = 0xb9c6f99ebf805f2cull; - -static constexpr const char* FIELD_SIZE_NAMES[] = { - "VOID", "BIT", "BYTE", "TWO_BYTES", "FOUR_BYTES", "EIGHT_BYTES", "POINTER", "INLINE_COMPOSITE" -}; - -bool hasDiscriminantValue(const schema::Field::Reader& reader) { - return reader.getDiscriminantValue() != schema::Field::NO_DISCRIMINANT; -} - -void enumerateDeps(schema::Type::Reader type, std::set& deps) { - switch (type.which()) { - case schema::Type::STRUCT: - deps.insert(type.getStruct().getTypeId()); - break; - case schema::Type::ENUM: - deps.insert(type.getEnum().getTypeId()); - break; - case schema::Type::INTERFACE: - deps.insert(type.getInterface().getTypeId()); - break; - case schema::Type::LIST: - enumerateDeps(type.getList().getElementType(), deps); - break; - default: - break; - } -} - -void enumerateDeps(schema::Node::Reader node, std::set& deps) { - switch (node.which()) { - case schema::Node::STRUCT: { - auto structNode = node.getStruct(); - for (auto field: structNode.getFields()) { - switch (field.which()) { - case schema::Field::SLOT: - enumerateDeps(field.getSlot().getType(), deps); - break; - case schema::Field::GROUP: - deps.insert(field.getGroup().getTypeId()); - break; - } - } - if (structNode.getIsGroup()) { - deps.insert(node.getScopeId()); - } - break; - } - case schema::Node::INTERFACE: { - auto interfaceNode = node.getInterface(); - for (auto extend: interfaceNode.getExtends()) { - deps.insert(extend); - } - for (auto method: interfaceNode.getMethods()) { - deps.insert(method.getParamStructType()); - deps.insert(method.getResultStructType()); - } - break; - } - default: - break; - } -} - -struct OrderByName { - template - inline bool operator()(const T& a, const T& b) const { - return a.getProto().getName() < b.getProto().getName(); - } -}; - -template -kj::Array makeMembersByName(MemberList&& members) { - auto sorted = KJ_MAP(member, members) { return member; }; - std::sort(sorted.begin(), sorted.end(), OrderByName()); - return KJ_MAP(member, sorted) { return member.getIndex(); }; -} - -kj::StringPtr baseName(kj::StringPtr path) { - KJ_IF_MAYBE(slashPos, path.findLast('/')) { - return path.slice(*slashPos + 1); - } else { - return path; - } -} - -kj::String safeIdentifier(kj::StringPtr identifier) { - // Given a desired identifier name, munge it to make it safe for use in generated code. - // - // If the identifier is a keyword, this adds an underscore to the end. - - static const std::set keywords({ - "alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", - "case", "catch", "char", "char16_t", "char32_t", "class", "compl", "const", "constexpr", - "const_cast", "continue", "decltype", "default", "delete", "do", "double", "dynamic_cast", - "else", "enum", "explicit", "export", "extern", "false", "float", "for", "friend", "goto", - "if", "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not", "not_eq", - "nullptr", "operator", "or", "or_eq", "private", "protected", "public", "register", - "reinterpret_cast", "return", "short", "signed", "sizeof", "static", "static_assert", - "static_cast", "struct", "switch", "template", "this", "thread_local", "throw", "true", - "try", "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", "void", - "volatile", "wchar_t", "while", "xor", "xor_eq" - }); - - if (keywords.count(identifier) > 0) { - return kj::str(identifier, '_'); - } else { - return kj::heapString(identifier); - } -} - - kj::String spaces(int n) { - return kj::str(kj::repeat(' ', n * 2)); - } - -// ======================================================================================= - -class CapnpcCppMain { -public: - CapnpcCppMain(kj::ProcessContext& context): context(context) {} - - kj::MainFunc getMain() { - return kj::MainBuilder(context, "Cap'n Proto loopback plugin version " VERSION, - "This is a Cap'n Proto compiler plugin which \"de-compiles\" the schema back into " - "Cap'n Proto schema language format, with comments showing the offsets chosen by the " - "compiler. This is meant to be run using the Cap'n Proto compiler, e.g.:\n" - " capnp compile -ocapnp foo.capnp") - .callAfterParsing(KJ_BIND_METHOD(*this, run)) - .build(); - } - -private: - kj::ProcessContext& context; - SchemaLoader schemaLoader; - std::unordered_set usedImports; - bool hasInterfaces = false; - - kj::String outerClassName; - - kj::StringTree javaFullName(Schema schema) { - auto node = schema.getProto(); - if (node.getScopeId() == 0) { - usedImports.insert(node.getId()); - for (auto annotation: node.getAnnotations()) { - /* if (annotation.getId() == NAMESPACE_ANNOTATION_ID) { - return kj::strTree("", annotation.getValue().getText()); - }*/ - } - return kj::strTree(outerClassName); - } else { - Schema parent = schemaLoader.get(node.getScopeId()); - for (auto nested: parent.getProto().getNestedNodes()) { - if (nested.getId() == node.getId()) { - return kj::strTree(javaFullName(parent), ".", nested.getName()); - } - } - KJ_FAIL_REQUIRE("A schema Node's supposed scope did not contain the node as a NestedNode."); - } - } - - - kj::String toUpperCase(kj::StringPtr name) { - kj::Vector result(name.size() + 4); - - for (char c: name) { - if ('a' <= c && c <= 'z') { - result.add(c - 'a' + 'A'); - } else if (result.size() > 0 && 'A' <= c && c <= 'Z') { - result.add('_'); - result.add(c); - } else { - result.add(c); - } - } - - result.add('\0'); - - return kj::String(result.releaseAsArray()); - } - - kj::String toTitleCase(kj::StringPtr name) { - kj::String result = kj::heapString(name); - if ('a' <= result[0] && result[0] <= 'z') { - result[0] = result[0] - 'a' + 'A'; - } - return kj::mv(result); - } - - kj::StringTree typeName(schema::Type::Reader type) { - switch (type.which()) { - case schema::Type::VOID: return kj::strTree("void"); - - case schema::Type::BOOL: return kj::strTree("boolean"); - case schema::Type::INT8: return kj::strTree("byte"); - case schema::Type::INT16: return kj::strTree("short"); - case schema::Type::INT32: return kj::strTree("int"); - case schema::Type::INT64: return kj::strTree("long"); - case schema::Type::UINT8: return kj::strTree("byte"); - case schema::Type::UINT16: return kj::strTree("short"); - case schema::Type::UINT32: return kj::strTree("int"); - case schema::Type::UINT64: return kj::strTree("long"); - case schema::Type::FLOAT32: return kj::strTree("float"); - case schema::Type::FLOAT64: return kj::strTree("double"); - - case schema::Type::TEXT: return kj::strTree(" org.capnproto.Text"); - case schema::Type::DATA: return kj::strTree(" org.capnproto.Data"); - - case schema::Type::ENUM: - return javaFullName(schemaLoader.get(type.getEnum().getTypeId())); - case schema::Type::STRUCT: - return javaFullName(schemaLoader.get(type.getStruct().getTypeId())); - case schema::Type::INTERFACE: - return javaFullName(schemaLoader.get(type.getInterface().getTypeId())); - - case schema::Type::LIST: - // XXX - return kj::strTree(" org.capnproto.StructList"); - - case schema::Type::ANY_POINTER: - // Not used. - return kj::strTree(); - } - KJ_UNREACHABLE; - } - - kj::StringTree literalValue(schema::Type::Reader type, schema::Value::Reader value) { - switch (value.which()) { - case schema::Value::VOID: return kj::strTree(" ::capnp::VOID"); - case schema::Value::BOOL: return kj::strTree(value.getBool() ? "true" : "false"); - case schema::Value::INT8: return kj::strTree(value.getInt8()); - case schema::Value::INT16: return kj::strTree(value.getInt16()); - case schema::Value::INT32: return kj::strTree(value.getInt32()); - case schema::Value::INT64: return kj::strTree(value.getInt64(), "ll"); - case schema::Value::UINT8: return kj::strTree(value.getUint8(), "u"); - case schema::Value::UINT16: return kj::strTree(value.getUint16(), "u"); - case schema::Value::UINT32: return kj::strTree(value.getUint32(), "u"); - case schema::Value::UINT64: return kj::strTree(value.getUint64(), "llu"); - case schema::Value::FLOAT32: return kj::strTree(value.getFloat32(), "f"); - case schema::Value::FLOAT64: return kj::strTree(value.getFloat64()); - case schema::Value::ENUM: { - EnumSchema schema = schemaLoader.get(type.getEnum().getTypeId()).asEnum(); - if (value.getEnum() < schema.getEnumerants().size()) { - return kj::strTree( - javaFullName(schema), "::", - toUpperCase(schema.getEnumerants()[value.getEnum()].getProto().getName())); - } else { - return kj::strTree("static_cast<", javaFullName(schema), ">(", value.getEnum(), ")"); - } - } - - case schema::Value::TEXT: - case schema::Value::DATA: - case schema::Value::STRUCT: - case schema::Value::INTERFACE: - case schema::Value::LIST: - case schema::Value::ANY_POINTER: - KJ_FAIL_REQUIRE("literalValue() can only be used on primitive types."); - } - KJ_UNREACHABLE; - } - - // ----------------------------------------------------------------- - // Code to deal with "slots" -- determines what to zero out when we clear a group. - - static uint typeSizeBits(schema::Type::Which whichType) { - switch (whichType) { - case schema::Type::BOOL: return 1; - case schema::Type::INT8: return 8; - case schema::Type::INT16: return 16; - case schema::Type::INT32: return 32; - case schema::Type::INT64: return 64; - case schema::Type::UINT8: return 8; - case schema::Type::UINT16: return 16; - case schema::Type::UINT32: return 32; - case schema::Type::UINT64: return 64; - case schema::Type::FLOAT32: return 32; - case schema::Type::FLOAT64: return 64; - case schema::Type::ENUM: return 16; - - case schema::Type::VOID: - case schema::Type::TEXT: - case schema::Type::DATA: - case schema::Type::LIST: - case schema::Type::STRUCT: - case schema::Type::INTERFACE: - case schema::Type::ANY_POINTER: - KJ_FAIL_REQUIRE("Should only be called for data types."); - } - KJ_UNREACHABLE; - } - - enum class Section { - NONE, - DATA, - POINTERS - }; - - static Section sectionFor(schema::Type::Which whichType) { - switch (whichType) { - case schema::Type::VOID: - return Section::NONE; - case schema::Type::BOOL: - case schema::Type::INT8: - case schema::Type::INT16: - case schema::Type::INT32: - case schema::Type::INT64: - case schema::Type::UINT8: - case schema::Type::UINT16: - case schema::Type::UINT32: - case schema::Type::UINT64: - case schema::Type::FLOAT32: - case schema::Type::FLOAT64: - case schema::Type::ENUM: - return Section::DATA; - case schema::Type::TEXT: - case schema::Type::DATA: - case schema::Type::LIST: - case schema::Type::STRUCT: - case schema::Type::INTERFACE: - case schema::Type::ANY_POINTER: - return Section::POINTERS; - } - KJ_UNREACHABLE; - } - - static kj::StringPtr maskType(schema::Type::Which whichType) { - switch (whichType) { - case schema::Type::BOOL: return "bool"; - case schema::Type::INT8: return " ::uint8_t"; - case schema::Type::INT16: return " ::uint16_t"; - case schema::Type::INT32: return " ::uint32_t"; - case schema::Type::INT64: return " ::uint64_t"; - case schema::Type::UINT8: return " ::uint8_t"; - case schema::Type::UINT16: return " ::uint16_t"; - case schema::Type::UINT32: return " ::uint32_t"; - case schema::Type::UINT64: return " ::uint64_t"; - case schema::Type::FLOAT32: return " ::uint32_t"; - case schema::Type::FLOAT64: return " ::uint64_t"; - case schema::Type::ENUM: return " ::uint16_t"; - - case schema::Type::VOID: - case schema::Type::TEXT: - case schema::Type::DATA: - case schema::Type::LIST: - case schema::Type::STRUCT: - case schema::Type::INTERFACE: - case schema::Type::ANY_POINTER: - KJ_FAIL_REQUIRE("Should only be called for data types."); - } - KJ_UNREACHABLE; - } - - struct Slot { - schema::Type::Which whichType; - uint offset; - - bool isSupersetOf(Slot other) const { - auto section = sectionFor(whichType); - if (section != sectionFor(other.whichType)) return false; - switch (section) { - case Section::NONE: - return true; // all voids overlap - case Section::DATA: { - auto bits = typeSizeBits(whichType); - auto start = offset * bits; - auto otherBits = typeSizeBits(other.whichType); - auto otherStart = other.offset * otherBits; - return start <= otherStart && otherStart + otherBits <= start + bits; - } - case Section::POINTERS: - return offset == other.offset; - } - KJ_UNREACHABLE; - } - - bool operator<(Slot other) const { - // Sort by section, then start position, and finally size. - - auto section = sectionFor(whichType); - auto otherSection = sectionFor(other.whichType); - if (section < otherSection) { - return true; - } else if (section > otherSection) { - return false; - } - - switch (section) { - case Section::NONE: - return false; - case Section::DATA: { - auto bits = typeSizeBits(whichType); - auto start = offset * bits; - auto otherBits = typeSizeBits(other.whichType); - auto otherStart = other.offset * otherBits; - if (start < otherStart) { - return true; - } else if (start > otherStart) { - return false; - } - - // Sort larger sizes before smaller. - return bits > otherBits; - } - case Section::POINTERS: - return offset < other.offset; - } - KJ_UNREACHABLE; - } - }; - - void getSlots(StructSchema schema, kj::Vector& slots) { - auto structProto = schema.getProto().getStruct(); - if (structProto.getDiscriminantCount() > 0) { - slots.add(Slot { schema::Type::UINT16, structProto.getDiscriminantOffset() }); - } - - for (auto field: schema.getFields()) { - auto proto = field.getProto(); - switch (proto.which()) { - case schema::Field::SLOT: { - auto slot = proto.getSlot(); - slots.add(Slot { slot.getType().which(), slot.getOffset() }); - break; - } - case schema::Field::GROUP: - getSlots(schema.getDependency(proto.getGroup().getTypeId()).asStruct(), slots); - break; - } - } - } - - kj::Array getSortedSlots(StructSchema schema) { - // Get a representation of all of the field locations owned by this schema, e.g. so that they - // can be zero'd out. - - kj::Vector slots(schema.getFields().size()); - getSlots(schema, slots); - std::sort(slots.begin(), slots.end()); - - kj::Vector result(slots.size()); - - // All void slots are redundant, and they sort towards the front of the list. By starting out - // with `prevSlot` = void, we will end up skipping them all, which is what we want. - Slot prevSlot = { schema::Type::VOID, 0 }; - for (auto slot: slots) { - if (prevSlot.isSupersetOf(slot)) { - // This slot is redundant as prevSlot is a superset of it. - continue; - } - - // Since all sizes are power-of-two, if two slots overlap at all, one must be a superset of - // the other. Since we sort slots by starting position, we know that the only way `slot` - // could be a superset of `prevSlot` is if they have the same starting position. However, - // since we sort slots with the same starting position by descending size, this is not - // possible. - KJ_DASSERT(!slot.isSupersetOf(prevSlot)); - - result.add(slot); - - prevSlot = slot; - } - - return result.releaseAsArray(); - } - - // ----------------------------------------------------------------- - - struct DiscriminantChecks { - kj::String has; - kj::String check; - kj::String set; - kj::StringTree readerIsDecl; - kj::StringTree builderIsDecl; - kj::StringTree isDefs; - }; - - DiscriminantChecks makeDiscriminantChecks(kj::StringPtr scope, - kj::StringPtr memberName, - StructSchema containingStruct, - int indent) { - auto discrimOffset = containingStruct.getProto().getStruct().getDiscriminantOffset(); - - kj::String titleCase = toTitleCase(memberName); - kj::String upperCase = toUpperCase(memberName); - - return DiscriminantChecks { - kj::str( - " if (which() != ", scope, upperCase, ") return false;\n"), - kj::str( - " KJ_IREQUIRE(which() == ", scope, upperCase, ",\n" - " \"Must check which() before get()ing a union member.\");\n"), - kj::str( - " _builder.setDataField<", scope, "Which>(\n" - " ", discrimOffset, " * ::capnp::ELEMENTS, ", - scope, upperCase, ");\n"), - kj::strTree(spaces(indent), " public boolean is", titleCase, "() {\n", - spaces(indent), " return which() == ", scope, "Which.", upperCase,";\n", - spaces(indent), " }\n"), - kj::strTree(spaces(indent), " public boolean is", titleCase, "();\n"), - kj::strTree( - "inline boolean ", scope, "Reader::is", titleCase, "() const {\n" - " return which() == ", scope, upperCase, ";\n" - "}\n" - "inline boolean ", scope, "Builder::is", titleCase, "() {\n" - " return which() == ", scope, upperCase, ";\n" - "}\n") - }; - } - - // ----------------------------------------------------------------- - - struct FieldText { - kj::StringTree readerMethodDecls; - kj::StringTree builderMethodDecls; - kj::StringTree pipelineMethodDecls; - kj::StringTree inlineMethodDefs; - }; - - enum class FieldKind { - PRIMITIVE, - BLOB, - STRUCT, - LIST, - INTERFACE, - ANY_POINTER - }; - - FieldText makeFieldText(kj::StringPtr scope, StructSchema::Field field, int indent) { - auto proto = field.getProto(); - kj::String titleCase = toTitleCase(proto.getName()); - - DiscriminantChecks unionDiscrim; - if (hasDiscriminantValue(proto)) { - unionDiscrim = makeDiscriminantChecks(scope, proto.getName(), field.getContainingStruct(), indent); - } - - switch (proto.which()) { - case schema::Field::SLOT: - // Continue below. - break; - - case schema::Field::GROUP: { - auto slots = getSortedSlots(schemaLoader.get( - field.getProto().getGroup().getTypeId()).asStruct()); - return FieldText { - kj::strTree( - kj::mv(unionDiscrim.readerIsDecl), - spaces(indent), " public ", titleCase, ".Reader get", titleCase, "() {\n", - spaces(indent), " return new ", scope, titleCase, ".Reader(_reader);\n", - spaces(indent), " }\n", - "\n"), - - kj::strTree( - kj::mv(unionDiscrim.builderIsDecl), - " inline ", titleCase, "::Builder get", titleCase, "();\n" - " inline ", titleCase, "::Builder init", titleCase, "();\n" - "\n"), - - hasDiscriminantValue(proto) ? kj::strTree() : - kj::strTree(" inline ", titleCase, "::Pipeline get", titleCase, "();\n"), - - kj::strTree( - kj::mv(unionDiscrim.isDefs), - "inline ", scope, titleCase, "::Reader ", scope, "Reader::get", titleCase, "() const {\n", - unionDiscrim.check, - " return ", scope, titleCase, "::Reader(_reader);\n" - "}\n" - "inline ", scope, titleCase, "::Builder ", scope, "Builder::get", titleCase, "() {\n", - unionDiscrim.check, - " return ", scope, titleCase, "::Builder(_builder);\n" - "}\n", - hasDiscriminantValue(proto) ? kj::strTree() : kj::strTree( - "inline ", scope, titleCase, "::Pipeline ", scope, "Pipeline::get", titleCase, "() {\n", - " return ", scope, titleCase, "::Pipeline(_typeless.noop());\n" - "}\n"), - "inline ", scope, titleCase, "::Builder ", scope, "Builder::init", titleCase, "() {\n", - unionDiscrim.set, - KJ_MAP(slot, slots) { - switch (sectionFor(slot.whichType)) { - case Section::NONE: - return kj::strTree(); - case Section::DATA: - return kj::strTree( - " _builder.setDataField<", maskType(slot.whichType), ">(", - slot.offset, " * ::capnp::ELEMENTS, 0);\n"); - case Section::POINTERS: - return kj::strTree( - " _builder.getPointerField(", slot.offset, - " * ::capnp::POINTERS).clear();\n"); - } - KJ_UNREACHABLE; - }, - " return ", scope, titleCase, "::Builder(_builder);\n" - "}\n") - }; - } - } - - auto slot = proto.getSlot(); - - FieldKind kind = FieldKind::PRIMITIVE; - kj::String ownedType; - kj::String type = typeName(slot.getType()).flatten(); - kj::StringPtr setterDefault; // only for void - kj::String defaultMask; // primitives only - size_t defaultOffset = 0; // pointers only: offset of the default value within the schema. - size_t defaultSize = 0; // blobs only: byte size of the default value. - - auto typeBody = slot.getType(); - auto defaultBody = slot.getDefaultValue(); - switch (typeBody.which()) { - case schema::Type::VOID: - kind = FieldKind::PRIMITIVE; - setterDefault = " = ::capnp::VOID"; - break; - -#define HANDLE_PRIMITIVE(discrim, typeName, defaultName, suffix) \ - case schema::Type::discrim: \ - kind = FieldKind::PRIMITIVE; \ - if (defaultBody.get##defaultName() != 0) { \ - defaultMask = kj::str(defaultBody.get##defaultName(), #suffix); \ - } \ - break; - - HANDLE_PRIMITIVE(BOOL, bool, Bool, ); - HANDLE_PRIMITIVE(INT8 , ::int8_t , Int8 , ); - HANDLE_PRIMITIVE(INT16, ::int16_t, Int16, ); - HANDLE_PRIMITIVE(INT32, ::int32_t, Int32, ); - HANDLE_PRIMITIVE(INT64, ::int64_t, Int64, ll); - HANDLE_PRIMITIVE(UINT8 , ::uint8_t , Uint8 , u); - HANDLE_PRIMITIVE(UINT16, ::uint16_t, Uint16, u); - HANDLE_PRIMITIVE(UINT32, ::uint32_t, Uint32, u); - HANDLE_PRIMITIVE(UINT64, ::uint64_t, Uint64, ull); -#undef HANDLE_PRIMITIVE - - case schema::Type::FLOAT32: - kind = FieldKind::PRIMITIVE; - if (defaultBody.getFloat32() != 0) { - uint32_t mask; - float value = defaultBody.getFloat32(); - static_assert(sizeof(mask) == sizeof(value), "bug"); - memcpy(&mask, &value, sizeof(mask)); - defaultMask = kj::str(mask, "u"); - } - break; - - case schema::Type::FLOAT64: - kind = FieldKind::PRIMITIVE; - if (defaultBody.getFloat64() != 0) { - uint64_t mask; - double value = defaultBody.getFloat64(); - static_assert(sizeof(mask) == sizeof(value), "bug"); - memcpy(&mask, &value, sizeof(mask)); - defaultMask = kj::str(mask, "ull"); - } - break; - - case schema::Type::TEXT: - kind = FieldKind::BLOB; - if (defaultBody.hasText()) { - defaultOffset = field.getDefaultValueSchemaOffset(); - defaultSize = defaultBody.getText().size(); - } - break; - case schema::Type::DATA: - kind = FieldKind::BLOB; - if (defaultBody.hasData()) { - defaultOffset = field.getDefaultValueSchemaOffset(); - defaultSize = defaultBody.getData().size(); - } - break; - - case schema::Type::ENUM: - kind = FieldKind::PRIMITIVE; - if (defaultBody.getEnum() != 0) { - defaultMask = kj::str(defaultBody.getEnum(), "u"); - } - break; - - case schema::Type::STRUCT: - kind = FieldKind::STRUCT; - if (defaultBody.hasStruct()) { - defaultOffset = field.getDefaultValueSchemaOffset(); - } - break; - case schema::Type::LIST: - kind = FieldKind::LIST; - if (defaultBody.hasList()) { - defaultOffset = field.getDefaultValueSchemaOffset(); - } - break; - case schema::Type::INTERFACE: - kind = FieldKind::INTERFACE; - break; - case schema::Type::ANY_POINTER: - kind = FieldKind::ANY_POINTER; - if (defaultBody.hasAnyPointer()) { - defaultOffset = field.getDefaultValueSchemaOffset(); - } - break; - } - - kj::String defaultMaskParam; - if (defaultMask.size() > 0) { - defaultMaskParam = kj::str(", ", defaultMask); - } - - uint offset = slot.getOffset(); - - if (kind == FieldKind::PRIMITIVE) { - return FieldText { - kj::strTree( - kj::mv(unionDiscrim.readerIsDecl), - spaces(indent), " public ", type, " get", titleCase, "() {\n", - spaces(indent), - (typeBody.which() == schema::Type::ENUM ? - kj::strTree(" return ", type, ".values()[_reader.getShortField(", offset, ")];\n") : - (typeBody.which() == schema::Type::VOID ? - kj::strTree(" // nothing to return\n") : - kj::strTree(" return _reader.get",toTitleCase(type),"Field(", offset, ");\n"))), - spaces(indent), " }\n", - "\n"), - - kj::strTree( - kj::mv(unionDiscrim.builderIsDecl), - " inline ", type, " get", titleCase, "();\n" - " inline void set", titleCase, "(", type, " value", setterDefault, ");\n" - "\n"), - - kj::strTree(), - - kj::strTree( - kj::mv(unionDiscrim.isDefs), - "inline ", type, " ", scope, "Reader::get", titleCase, "() const {\n", - unionDiscrim.check, - " return _reader.getDataField<", type, ">(\n" - " ", offset, " * ::capnp::ELEMENTS", defaultMaskParam, ");\n", - "}\n" - "\n" - "inline ", type, " ", scope, "Builder::get", titleCase, "() {\n", - unionDiscrim.check, - " return _builder.getDataField<", type, ">(\n" - " ", offset, " * ::capnp::ELEMENTS", defaultMaskParam, ");\n", - "}\n" - "inline void ", scope, "Builder::set", titleCase, "(", type, " value) {\n", - unionDiscrim.set, - " _builder.setDataField<", type, ">(\n" - " ", offset, " * ::capnp::ELEMENTS, value", defaultMaskParam, ");\n", - "}\n" - "\n") - }; - - } else if (kind == FieldKind::INTERFACE) { - KJ_FAIL_REQUIRE("interfaces unimplemented"); - } else if (kind == FieldKind::ANY_POINTER) { - return FieldText { - kj::strTree( - kj::mv(unionDiscrim.readerIsDecl), - " inline boolean has", titleCase, "() const;\n" - " inline ::capnp::AnyPointer::Reader get", titleCase, "() const;\n" - "\n"), - - kj::strTree( - kj::mv(unionDiscrim.builderIsDecl), - " inline boolean has", titleCase, "();\n" - " inline ::capnp::AnyPointer::Builder get", titleCase, "();\n" - " inline ::capnp::AnyPointer::Builder init", titleCase, "();\n" - "\n"), - - kj::strTree(), - - kj::strTree( - kj::mv(unionDiscrim.isDefs), - "inline boolean ", scope, "Reader::has", titleCase, "() const {\n", - unionDiscrim.has, - " return !_reader.getPointerField(", offset, " * ::capnp::POINTERS).isNull();\n" - "}\n" - "inline boolean ", scope, "Builder::has", titleCase, "() {\n", - unionDiscrim.has, - " return !_builder.getPointerField(", offset, " * ::capnp::POINTERS).isNull();\n" - "}\n" - "inline ::capnp::AnyPointer::Reader ", scope, "Reader::get", titleCase, "() const {\n", - unionDiscrim.check, - " return ::capnp::AnyPointer::Reader(\n" - " _reader.getPointerField(", offset, " * ::capnp::POINTERS));\n" - "}\n" - "inline ::capnp::AnyPointer::Builder ", scope, "Builder::get", titleCase, "() {\n", - unionDiscrim.check, - " return ::capnp::AnyPointer::Builder(\n" - " _builder.getPointerField(", offset, " * ::capnp::POINTERS));\n" - "}\n" - "inline ::capnp::AnyPointer::Builder ", scope, "Builder::init", titleCase, "() {\n", - unionDiscrim.set, - " auto result = ::capnp::AnyPointer::Builder(\n" - " _builder.getPointerField(", offset, " * ::capnp::POINTERS));\n" - " result.clear();\n" - " return result;\n" - "}\n" - "\n") - }; - - } else { - // Blob, struct, or list. These have only minor differences. - - uint64_t typeId = field.getContainingStruct().getProto().getId(); - kj::String defaultParam = defaultOffset == 0 ? kj::str() : kj::str( - ",\n ::capnp::schemas::s_", kj::hex(typeId), ".encodedNode + ", defaultOffset, - defaultSize == 0 ? kj::strTree() : kj::strTree(", ", defaultSize)); - - kj::String elementReaderType; - bool isStructOrCapList = false; - if (kind == FieldKind::LIST) { - bool primitiveElement = false; - bool interface = false; - switch (typeBody.getList().getElementType().which()) { - case schema::Type::VOID: - case schema::Type::BOOL: - case schema::Type::INT8: - case schema::Type::INT16: - case schema::Type::INT32: - case schema::Type::INT64: - case schema::Type::UINT8: - case schema::Type::UINT16: - case schema::Type::UINT32: - case schema::Type::UINT64: - case schema::Type::FLOAT32: - case schema::Type::FLOAT64: - case schema::Type::ENUM: - primitiveElement = true; - break; - - case schema::Type::TEXT: - case schema::Type::DATA: - case schema::Type::LIST: - case schema::Type::ANY_POINTER: - primitiveElement = false; - break; - - case schema::Type::INTERFACE: - isStructOrCapList = true; - primitiveElement = false; - interface = true; - break; - - case schema::Type::STRUCT: - isStructOrCapList = true; - primitiveElement = false; - break; - } - elementReaderType = kj::str( - typeName(typeBody.getList().getElementType()), - primitiveElement ? "" : interface ? "::Client" : ".Reader"); - } - - - return FieldText { - kj::strTree( - kj::mv(unionDiscrim.readerIsDecl), - spaces(indent), " public boolean has", titleCase, "() {\n", - spaces(indent), " return !_reader.getPointerField(", offset, ").isNull();\n", - spaces(indent), " }\n", - - spaces(indent), " public ", type, ".Reader", - (kind == FieldKind::LIST ? - kj::strTree("<", elementReaderType, ">") : - kj::strTree() - ), - " get", titleCase, "() {\n", - (kind == FieldKind::LIST ? - kj::strTree(spaces(indent), - " return new ", type, ".Reader<", - elementReaderType, - ">(_reader.getPointerField(", - offset, ").getList(", - - // XXX what about lists of non-structs? - typeName(typeBody.getList().getElementType()),".STRUCT_SIZE.preferredListEncoding), ", - elementReaderType, ".factory);\n") : - (kind == FieldKind::BLOB ? - kj::strTree(spaces(indent), " return _reader.getPointerField(", - offset,").getText();\n") : - kj::strTree(spaces(indent), "Struct\n"))), // XXX - spaces(indent), " }\n", - "\n"), - - kj::strTree( - kj::mv(unionDiscrim.builderIsDecl), - " inline boolean has", titleCase, "();\n" - " inline ", type, "::Builder get", titleCase, "();\n" - " inline void set", titleCase, "(", type, "::Reader value);\n", - kind == FieldKind::LIST && !isStructOrCapList - ? kj::strTree( - " inline void set", titleCase, "(::kj::ArrayPtr value);\n") - : kj::strTree(), - kind == FieldKind::STRUCT - ? kj::strTree( - " inline ", type, "::Builder init", titleCase, "();\n") - : kj::strTree( - " inline ", type, "::Builder init", titleCase, "(unsigned int size);\n"), - " inline void adopt", titleCase, "(::capnp::Orphan<", type, ">&& value);\n" - " inline ::capnp::Orphan<", type, "> disown", titleCase, "();\n" - "\n"), - - kj::strTree( - kind == FieldKind::STRUCT && !hasDiscriminantValue(proto) - ? kj::strTree( - " inline ", type, "::Pipeline get", titleCase, "();\n") - : kj::strTree()), - - kj::strTree( - kj::mv(unionDiscrim.isDefs), - "inline bool ", scope, "Reader::has", titleCase, "() const {\n", - unionDiscrim.has, - " return !_reader.getPointerField(", offset, " * ::capnp::POINTERS).isNull();\n" - "}\n" - "inline bool ", scope, "Builder::has", titleCase, "() {\n", - unionDiscrim.has, - " return !_builder.getPointerField(", offset, " * ::capnp::POINTERS).isNull();\n" - "}\n" - "inline ", type, "::Reader ", scope, "Reader::get", titleCase, "() const {\n", - unionDiscrim.check, - " return ::capnp::_::PointerHelpers<", type, ">::get(\n" - " _reader.getPointerField(", offset, " * ::capnp::POINTERS)", defaultParam, ");\n" - "}\n" - "inline ", type, "::Builder ", scope, "Builder::get", titleCase, "() {\n", - unionDiscrim.check, - " return ::capnp::_::PointerHelpers<", type, ">::get(\n" - " _builder.getPointerField(", offset, " * ::capnp::POINTERS)", defaultParam, ");\n" - "}\n", - kind == FieldKind::STRUCT && !hasDiscriminantValue(proto) - ? kj::strTree( - "inline ", type, "::Pipeline ", scope, "Pipeline::get", titleCase, "() {\n", - " return ", type, "::Pipeline(_typeless.getPointerField(", offset, "));\n" - "}\n") - : kj::strTree(), - "inline void ", scope, "Builder::set", titleCase, "(", type, "::Reader value) {\n", - unionDiscrim.set, - " ::capnp::_::PointerHelpers<", type, ">::set(\n" - " _builder.getPointerField(", offset, " * ::capnp::POINTERS), value);\n" - "}\n", - kind == FieldKind::LIST && !isStructOrCapList - ? kj::strTree( - "inline void ", scope, "Builder::set", titleCase, "(::kj::ArrayPtr value) {\n", - unionDiscrim.set, - " ::capnp::_::PointerHelpers<", type, ">::set(\n" - " _builder.getPointerField(", offset, " * ::capnp::POINTERS), value);\n" - "}\n") - : kj::strTree(), - kind == FieldKind::STRUCT - ? kj::strTree( - "inline ", type, "::Builder ", scope, "Builder::init", titleCase, "() {\n", - unionDiscrim.set, - " return ::capnp::_::PointerHelpers<", type, ">::init(\n" - " _builder.getPointerField(", offset, " * ::capnp::POINTERS));\n" - "}\n") - : kj::strTree( - "inline ", type, "::Builder ", scope, "Builder::init", titleCase, "(unsigned int size) {\n", - unionDiscrim.set, - " return ::capnp::_::PointerHelpers<", type, ">::init(\n" - " _builder.getPointerField(", offset, " * ::capnp::POINTERS), size);\n" - "}\n"), - "inline void ", scope, "Builder::adopt", titleCase, "(\n" - " ::capnp::Orphan<", type, ">&& value) {\n", - unionDiscrim.set, - " ::capnp::_::PointerHelpers<", type, ">::adopt(\n" - " _builder.getPointerField(", offset, " * ::capnp::POINTERS), kj::mv(value));\n" - "}\n" - "inline ::capnp::Orphan<", type, "> ", scope, "Builder::disown", titleCase, "() {\n", - unionDiscrim.check, - " return ::capnp::_::PointerHelpers<", type, ">::disown(\n" - " _builder.getPointerField(", offset, " * ::capnp::POINTERS));\n" - "}\n" - "\n") - }; - } - } - - // ----------------------------------------------------------------- - - struct StructText { - kj::StringTree outerTypeDecl; - kj::StringTree outerTypeDef; - kj::StringTree readerBuilderDefs; - kj::StringTree inlineMethodDefs; - }; - - kj::StringTree makeReaderDef(kj::StringPtr fullName, kj::StringPtr unqualifiedParentType, - bool isUnion, uint discriminantOffset, kj::Array&& methodDecls, - int indent) { - return kj::strTree( - spaces(indent), "public static final class Reader {\n", - spaces(indent), - " public static class Factory implements org.capnproto.FromStructReader {\n", - spaces(indent), - " public final Reader fromStructReader(org.capnproto.StructReader reader) {\n", - spaces(indent), " return new Reader(reader);\n", - spaces(indent), " }\n", - spaces(indent), " }\n", - spaces(indent), " public static final Factory factory = new Factory();\n", - spaces(indent), " public Reader(org.capnproto.StructReader base){ this._reader = base; }\n", - "\n", - (isUnion ? - kj::strTree(spaces(indent), " public Which which() {\n", - spaces(indent), " return Which.values()[_reader.getShortField(", - discriminantOffset, ")];\n", - spaces(indent), " }\n") - : kj::strTree()), - kj::mv(methodDecls), - spaces(indent), " public org.capnproto.StructReader _reader;\n", - spaces(indent), "}\n" - "\n"); - } - - kj::StringTree makeBuilderDef(kj::StringPtr fullName, kj::StringPtr unqualifiedParentType, - schema::Node::Struct::Reader structNode, - kj::Array&& methodDecls, - int indent) { - bool isUnion = structNode.getDiscriminantCount() != 0; - return kj::strTree( - spaces(indent), "public static final class Builder {\n", - spaces(indent), " public static class Factory implements org.capnproto.FromStructBuilder {\n", - spaces(indent), " public final Builder fromStructBuilder(org.capnproto.StructBuilder builder) {\n", - spaces(indent), " return new Builder(builder);\n", - spaces(indent), " }\n", - spaces(indent), " public final org.capnproto.StructSize structSize() {\n", - spaces(indent), " return ", fullName, ".STRUCT_SIZE;\n", - spaces(indent), " }\n", - spaces(indent), " }\n", - spaces(indent), " public static final Factory factory = new Factory();\n", - spaces(indent), " public Builder(org.capnproto.StructBuilder base){ this._builder = base; }\n", - spaces(indent), " public org.capnproto.StructBuilder _builder;\n", - spaces(indent), "}\n", - "\n"); - } - - StructText makeStructText(kj::StringPtr scope, kj::StringPtr name, StructSchema schema, - kj::Array nestedTypeDecls, int indent) { - auto proto = schema.getProto(); - auto fullName = kj::str(scope, name); - auto subScope = kj::str(fullName, "."); - auto fieldTexts = KJ_MAP(f, schema.getFields()) { return makeFieldText(subScope, f, indent + 1); }; - - auto structNode = proto.getStruct(); - uint discrimOffset = structNode.getDiscriminantOffset(); - structNode.getPointerCount(); - - return StructText { - kj::strTree( - " struct ", name, ";\n"), - - kj::strTree( - spaces(indent), "public static class ", name, " {\n", - kj::strTree( - spaces(indent), " public static final org.capnproto.StructSize STRUCT_SIZE =\n", - spaces(indent), " new org.capnproto.StructSize((short)", structNode.getDataWordCount(), - ",(short)", structNode.getPointerCount(), - ", org.capnproto.FieldSize.", FIELD_SIZE_NAMES[(int)structNode.getPreferredListEncoding()], ");\n"), - - kj::strTree(makeReaderDef(fullName, name, structNode.getDiscriminantCount() != 0, - structNode.getDiscriminantOffset(), - KJ_MAP(f, fieldTexts) { return kj::mv(f.readerMethodDecls); }, - indent + 1), - makeBuilderDef(fullName, name, structNode, - KJ_MAP(f, fieldTexts) { return kj::mv(f.builderMethodDecls); }, - indent + 1)), - - structNode.getDiscriminantCount() == 0 ? - kj::strTree() : - kj::strTree( - spaces(indent), " public enum Which {\n", - KJ_MAP(f, structNode.getFields()) { - if (hasDiscriminantValue(f)) { - return kj::strTree(spaces(indent), " ", toUpperCase(f.getName()), ",\n"); - } else { - return kj::strTree(); - } - }, - spaces(indent), " }\n"), - KJ_MAP(n, nestedTypeDecls) { return kj::mv(n); }, - spaces(indent), "}\n" - "\n", - "\n"), - - kj::strTree(), - kj::strTree() - }; - } - - - // ----------------------------------------------------------------- - - struct ConstText { - bool needsSchema; - kj::StringTree decl; - kj::StringTree def; - }; - - ConstText makeConstText(kj::StringPtr scope, kj::StringPtr name, ConstSchema schema) { - auto proto = schema.getProto(); - auto constProto = proto.getConst(); - auto type = constProto.getType(); - auto typeName_ = typeName(type).flatten(); - auto upperCase = toUpperCase(name); - - // Linkage qualifier for non-primitive types. - const char* linkage = scope.size() == 0 ? "extern " : "static "; - - switch (type.which()) { - case schema::Value::VOID: - case schema::Value::BOOL: - case schema::Value::INT8: - case schema::Value::INT16: - case schema::Value::INT32: - case schema::Value::INT64: - case schema::Value::UINT8: - case schema::Value::UINT16: - case schema::Value::UINT32: - case schema::Value::UINT64: - case schema::Value::FLOAT32: - case schema::Value::FLOAT64: - case schema::Value::ENUM: - return ConstText { - false, - kj::strTree("static constexpr ", typeName_, ' ', upperCase, " = ", - literalValue(constProto.getType(), constProto.getValue()), ";\n"), - scope.size() == 0 ? kj::strTree() : kj::strTree( - "constexpr ", typeName_, ' ', scope, upperCase, ";\n") - }; - - case schema::Value::TEXT: { - kj::String constType = kj::strTree( - "::capnp::_::ConstText<", schema.as().size(), ">").flatten(); - return ConstText { - true, - kj::strTree(linkage, "const ", constType, ' ', upperCase, ";\n"), - kj::strTree("const ", constType, ' ', scope, upperCase, "(::capnp::schemas::b_", - kj::hex(proto.getId()), ".words + ", schema.getValueSchemaOffset(), ");\n") - }; - } - - case schema::Value::DATA: { - kj::String constType = kj::strTree( - "::capnp::_::ConstData<", schema.as().size(), ">").flatten(); - return ConstText { - true, - kj::strTree(linkage, "const ", constType, ' ', upperCase, ";\n"), - kj::strTree("const ", constType, ' ', scope, upperCase, "(::capnp::schemas::b_", - kj::hex(proto.getId()), ".words + ", schema.getValueSchemaOffset(), ");\n") - }; - } - - case schema::Value::STRUCT: { - kj::String constType = kj::strTree( - "::capnp::_::ConstStruct<", typeName_, ">").flatten(); - return ConstText { - true, - kj::strTree(linkage, "const ", constType, ' ', upperCase, ";\n"), - kj::strTree("const ", constType, ' ', scope, upperCase, "(::capnp::schemas::b_", - kj::hex(proto.getId()), ".words + ", schema.getValueSchemaOffset(), ");\n") - }; - } - - case schema::Value::LIST: { - kj::String constType = kj::strTree( - "::capnp::_::ConstList<", typeName(type.getList().getElementType()), ">").flatten(); - return ConstText { - true, - kj::strTree(linkage, "const ", constType, ' ', upperCase, ";\n"), - kj::strTree("const ", constType, ' ', scope, upperCase, "(::capnp::schemas::b_", - kj::hex(proto.getId()), ".words + ", schema.getValueSchemaOffset(), ");\n") - }; - } - - case schema::Value::ANY_POINTER: - case schema::Value::INTERFACE: - return ConstText { false, kj::strTree(), kj::strTree() }; - } - - KJ_UNREACHABLE; - } - - // ----------------------------------------------------------------- - - struct NodeText { - kj::StringTree outerTypeDecl; - kj::StringTree outerTypeDef; - kj::StringTree readerBuilderDefs; - kj::StringTree inlineMethodDefs; - kj::StringTree capnpSchemaDecls; - kj::StringTree capnpSchemaDefs; - kj::StringTree capnpPrivateDecls; - kj::StringTree capnpPrivateDefs; - kj::StringTree sourceFileDefs; - }; - - struct NodeTextNoSchema { - kj::StringTree outerTypeDecl; - kj::StringTree outerTypeDef; - kj::StringTree readerBuilderDefs; - kj::StringTree inlineMethodDefs; - kj::StringTree capnpPrivateDecls; - kj::StringTree capnpPrivateDefs; - kj::StringTree sourceFileDefs; - }; - - NodeText makeNodeText(kj::StringPtr namespace_, kj::StringPtr scope, - kj::StringPtr name, Schema schema, - int indent) { - auto proto = schema.getProto(); - auto fullName = kj::str(scope, name); - auto subScope = kj::str(fullName, "."); - auto hexId = kj::hex(proto.getId()); - - // Compute nested nodes, including groups. - kj::Vector nestedTexts(proto.getNestedNodes().size()); - for (auto nested: proto.getNestedNodes()) { - nestedTexts.add(makeNodeText( - namespace_, - subScope, nested.getName(), schemaLoader.get(nested.getId()), indent + 1)); - }; - - if (proto.isStruct()) { - for (auto field: proto.getStruct().getFields()) { - if (field.isGroup()) { - nestedTexts.add(makeNodeText( - namespace_, subScope, toTitleCase(field.getName()), - schemaLoader.get(field.getGroup().getTypeId()), indent + 1)); - } - } - } else if (proto.isInterface()) { - KJ_FAIL_REQUIRE("interfaces not implemented"); - } - - // Convert the encoded schema to a literal byte array. - kj::ArrayPtr rawSchema = schema.asUncheckedMessage(); - auto schemaLiteral = kj::StringTree(KJ_MAP(w, rawSchema) { - const byte* bytes = reinterpret_cast(&w); - - return kj::strTree(KJ_MAP(i, kj::range(0, sizeof(word))) { - auto text = kj::toCharSequence(kj::implicitCast(bytes[i])); - return kj::strTree(kj::repeat(' ', 4 - text.size()), text, ","); - }); - }, "\n "); - - auto schemaDecl = kj::strTree( - "extern const ::capnp::_::RawSchema s_", hexId, ";\n"); - - std::set deps; - enumerateDeps(proto, deps); - - kj::Array membersByName; - kj::Array membersByDiscrim; - switch (proto.which()) { - case schema::Node::STRUCT: { - auto structSchema = schema.asStruct(); - membersByName = makeMembersByName(structSchema.getFields()); - auto builder = kj::heapArrayBuilder(structSchema.getFields().size()); - for (auto field: structSchema.getUnionFields()) { - builder.add(field.getIndex()); - } - for (auto field: structSchema.getNonUnionFields()) { - builder.add(field.getIndex()); - } - membersByDiscrim = builder.finish(); - break; - } - case schema::Node::ENUM: - membersByName = makeMembersByName(schema.asEnum().getEnumerants()); - break; - case schema::Node::INTERFACE: - membersByName = makeMembersByName(schema.asInterface().getMethods()); - break; - default: - break; - } - - auto schemaDef = kj::strTree( - "static const ::capnp::_::AlignedData<", rawSchema.size(), "> b_", hexId, " = {\n" - " {", kj::mv(schemaLiteral), " }\n" - "};\n", - deps.size() == 0 ? kj::strTree() : kj::strTree( - "static const ::capnp::_::RawSchema* const d_", hexId, "[] = {\n", - KJ_MAP(depId, deps) { - return kj::strTree(" &s_", kj::hex(depId), ",\n"); - }, - "};\n"), - membersByName.size() == 0 ? kj::strTree() : kj::strTree( - "static const uint16_t m_", hexId, "[] = {", - kj::StringTree(KJ_MAP(index, membersByName) { return kj::strTree(index); }, ", "), - "};\n"), - membersByDiscrim.size() == 0 ? kj::strTree() : kj::strTree( - "static const uint16_t i_", hexId, "[] = {", - kj::StringTree(KJ_MAP(index, membersByDiscrim) { return kj::strTree(index); }, ", "), - "};\n"), - "const ::capnp::_::RawSchema s_", hexId, " = {\n" - " 0x", hexId, ", b_", hexId, ".words, ", rawSchema.size(), ", ", - deps.size() == 0 ? kj::strTree("nullptr") : kj::strTree("d_", hexId), ", ", - membersByName.size() == 0 ? kj::strTree("nullptr") : kj::strTree("m_", hexId), ",\n", - " ", deps.size(), ", ", membersByName.size(), ", ", - membersByDiscrim.size() == 0 ? kj::strTree("nullptr") : kj::strTree("i_", hexId), - ", nullptr, nullptr\n" - "};\n"); - - NodeTextNoSchema top = makeNodeTextWithoutNested( - namespace_, scope, name, schema, - KJ_MAP(n, nestedTexts) { return kj::mv(n.outerTypeDef); }, indent); - - return NodeText { - kj::mv(top.outerTypeDecl), - - kj::strTree( - kj::mv(top.outerTypeDef), - KJ_MAP(n, nestedTexts) { return kj::mv(n.outerTypeDef); }), - - kj::strTree( - kj::mv(top.readerBuilderDefs), - KJ_MAP(n, nestedTexts) { return kj::mv(n.readerBuilderDefs); }), - - kj::strTree( - kj::mv(top.inlineMethodDefs), - KJ_MAP(n, nestedTexts) { return kj::mv(n.inlineMethodDefs); }), - - kj::strTree( - kj::mv(schemaDecl), - KJ_MAP(n, nestedTexts) { return kj::mv(n.capnpSchemaDecls); }), - - kj::strTree( - kj::mv(schemaDef), - KJ_MAP(n, nestedTexts) { return kj::mv(n.capnpSchemaDefs); }), - - kj::strTree( - kj::mv(top.capnpPrivateDecls), - KJ_MAP(n, nestedTexts) { return kj::mv(n.capnpPrivateDecls); }), - - kj::strTree( - kj::mv(top.capnpPrivateDefs), - KJ_MAP(n, nestedTexts) { return kj::mv(n.capnpPrivateDefs); }), - - kj::strTree( - kj::mv(top.sourceFileDefs), - KJ_MAP(n, nestedTexts) { return kj::mv(n.sourceFileDefs); }), - }; - } - - NodeTextNoSchema makeNodeTextWithoutNested(kj::StringPtr namespace_, kj::StringPtr scope, - kj::StringPtr name, Schema schema, - kj::Array nestedTypeDecls, - int indent) { - auto proto = schema.getProto(); - auto fullName = kj::str(scope, name); - auto hexId = kj::hex(proto.getId()); - - switch (proto.which()) { - case schema::Node::FILE: - KJ_FAIL_REQUIRE("This method shouldn't be called on file nodes."); - - case schema::Node::STRUCT: { - StructText structText = - makeStructText(scope, name, schema.asStruct(), kj::mv(nestedTypeDecls), indent); - auto structNode = proto.getStruct(); - - return NodeTextNoSchema { - kj::mv(structText.outerTypeDecl), - kj::mv(structText.outerTypeDef), - kj::mv(structText.readerBuilderDefs), - kj::mv(structText.inlineMethodDefs), - - kj::strTree(), - kj::strTree(), - - kj::strTree(), - }; - } - - case schema::Node::ENUM: { - auto enumerants = schema.asEnum().getEnumerants(); - - return NodeTextNoSchema { - kj::strTree(), - - kj::strTree( - spaces(indent), "public enum ", name, " {\n", - KJ_MAP(e, enumerants) { - return kj::strTree(spaces(indent), " ", toUpperCase(e.getProto().getName()), ",\n"); - }, - spaces(indent), "}\n" - "\n"), - - kj::strTree(), - kj::strTree(), - - kj::strTree(), - kj::strTree(), - - kj::strTree(), - }; - } - - case schema::Node::INTERFACE: { - hasInterfaces = true; - KJ_FAIL_REQUIRE("unimplemented"); - } - - case schema::Node::CONST: { - auto constText = makeConstText(scope, name, schema.asConst()); - - return NodeTextNoSchema { - scope.size() == 0 ? kj::strTree() : kj::strTree(" ", kj::mv(constText.decl)), - scope.size() > 0 ? kj::strTree() : kj::mv(constText.decl), - kj::strTree(), - kj::strTree(), - - kj::strTree(), - kj::strTree(), - - kj::mv(constText.def), - }; - } - - case schema::Node::ANNOTATION: { - return NodeTextNoSchema { - kj::strTree(), - kj::strTree(), - kj::strTree(), - kj::strTree(), - - kj::strTree(), - kj::strTree(), - - kj::strTree(), - }; - } - } - - KJ_UNREACHABLE; - } - - // ----------------------------------------------------------------- - - struct FileText { - kj::StringTree source; - }; - - FileText makeFileText(Schema schema, - schema::CodeGeneratorRequest::RequestedFile::Reader request) { - usedImports.clear(); - - auto node = schema.getProto(); - auto displayName = node.getDisplayName(); - - kj::Vector> namespaceParts; - kj::String namespacePrefix; - - for (auto annotation: node.getAnnotations()) { - if (annotation.getId() == NAMESPACE_ANNOTATION_ID) { - kj::StringPtr ns = annotation.getValue().getText(); - kj::StringPtr ns2 = ns; - namespacePrefix = kj::str("::", ns); - - for (;;) { - KJ_IF_MAYBE(colonPos, ns.findFirst(':')) { - namespaceParts.add(ns.slice(0, *colonPos)); - ns = ns.slice(*colonPos); - if (!ns.startsWith("::")) { - context.exitError(kj::str(displayName, ": invalid namespace spec: ", ns2)); - } - ns = ns.slice(2); - } else { - namespaceParts.add(ns); - break; - } - } - - break; - } - } - auto nodeTexts = KJ_MAP(nested, node.getNestedNodes()) { - return makeNodeText(namespacePrefix, "", nested.getName(), schemaLoader.get(nested.getId()), 1); - }; - - kj::String separator = kj::str("// ", kj::repeat('=', 87), "\n"); - - kj::Vector includes; - for (auto import: request.getImports()) { - if (usedImports.count(import.getId()) > 0) { - includes.add(import.getName()); - } - } - - kj::StringTree sourceDefs = kj::strTree( - KJ_MAP(n, nodeTexts) { return kj::mv(n.sourceFileDefs); }); - - return FileText { - kj::strTree( - "// Generated by Cap'n Proto compiler, DO NOT EDIT\n" - "// source: ", baseName(displayName), "\n", - "\n", - //"import org.capnproto;\n", - // KJ_MAP(n, namespaceParts) { return kj::strTree("namespace ", n, " {\n"); }, "\n", - "public class ", outerClassName, " {\n", - KJ_MAP(n, nodeTexts) { return kj::mv(n.outerTypeDef); }, - KJ_MAP(n, namespaceParts) { return kj::strTree("}\n"); }, "\n") - }; - } - - // ----------------------------------------------------------------- - - void makeDirectory(kj::StringPtr path) { - KJ_IF_MAYBE(slashpos, path.findLast('/')) { - // Make the parent dir. - makeDirectory(kj::str(path.slice(0, *slashpos))); - } - - if (mkdir(path.cStr(), 0777) < 0) { - int error = errno; - if (error != EEXIST) { - KJ_FAIL_SYSCALL("mkdir(path)", error, path); - } - } - } - - void writeFile(kj::StringPtr filename, const kj::StringTree& text) { - if (!filename.startsWith("/")) { - KJ_IF_MAYBE(slashpos, filename.findLast('/')) { - // Make the parent dir. - makeDirectory(kj::str(filename.slice(0, *slashpos))); - } - } - - int fd; - KJ_SYSCALL(fd = open(filename.cStr(), O_CREAT | O_WRONLY | O_TRUNC, 0666), filename); - kj::FdOutputStream out((kj::AutoCloseFd(fd))); - - text.visit( - [&](kj::ArrayPtr text) { - out.write(text.begin(), text.size()); - }); - } - - kj::MainBuilder::Validity run() { - ReaderOptions options; - options.traversalLimitInWords = 1 << 30; // Don't limit. - StreamFdMessageReader reader(STDIN_FILENO, options); - auto request = reader.getRoot(); - - for (auto node: request.getNodes()) { - schemaLoader.load(node); - } - - kj::FdOutputStream rawOut(STDOUT_FILENO); - kj::BufferedOutputStreamWrapper out(rawOut); - - for (auto requestedFile: request.getRequestedFiles()) { - auto schema = schemaLoader.get(requestedFile.getId()); - - auto filename = requestedFile.getFilename(); - size_t stemstart = 0; - size_t stemend = filename.size(); - KJ_IF_MAYBE(slashpos, filename.findLast('/')) { - stemstart = *slashpos + 1; - } - KJ_IF_MAYBE(dotpos, filename.findLast('.')) { - stemend = *dotpos; - } - outerClassName = toTitleCase(kj::str(filename.slice(stemstart, stemend))); - - auto genFileName = kj::str(filename.slice(0, stemstart), outerClassName, ".java"); - - auto fileText = makeFileText(schema, requestedFile); - - writeFile(genFileName, fileText.source); - } - - return true; - } -}; - -} // namespace -} // namespace capnp - -KJ_MAIN(capnp::CapnpcCppMain);