├── .github └── workflows │ ├── conformance.yml │ ├── maven.yml │ └── release.yml ├── .gitignore ├── LICENSE ├── README.md ├── benchmarks ├── README.md ├── pom.xml └── src │ ├── main │ └── java │ │ ├── protos │ │ └── benchmarks │ │ │ └── flatbuffers │ │ │ └── fb │ │ │ ├── Bar.java │ │ │ ├── Enum.java │ │ │ ├── Foo.java │ │ │ ├── FooBar.java │ │ │ └── FooBarContainer.java │ │ └── us │ │ └── hebi │ │ └── quickbuf │ │ └── benchmarks │ │ ├── PrintMemoryLayout.java │ │ ├── UnsafeUtil.java │ │ ├── comparison │ │ ├── PackedDoublesBenchmark.java │ │ ├── SbeBenchmark.java │ │ ├── SbeThroughputBenchmarkProtobuf.java │ │ └── SbeThroughputBenchmarkQuickbuf.java │ │ ├── encoding │ │ ├── DecodingBenchmark.java │ │ ├── JsonBenchmark.java │ │ ├── PrimitiveWriteBenchmark.java │ │ ├── RepeatedWriteBenchmark.java │ │ ├── SerializationBenchmarkProtobuf.java │ │ ├── SerializationBenchmarkQuickbuf.java │ │ ├── TagEncodeBenchmark.java │ │ ├── Utf8ToStringBenchmark.java │ │ ├── Varint32Benchmark.java │ │ └── Varint64Benchmark.java │ │ ├── flatbuffers │ │ ├── BenchRunner.java │ │ ├── FlatBuffersBench.java │ │ └── QuickBuffersBench.java │ │ ├── jdk │ │ └── JdkMethodsBenchmark.java │ │ ├── json │ │ ├── JsonSinkBenchmark.java │ │ └── JsonSourceBenchmark.java │ │ └── wrapper │ │ ├── SequentialIterationBenchmark.java │ │ └── SourceWrappers.java │ └── test │ ├── java │ └── us │ │ └── hebi │ │ └── quickbuf │ │ └── benchmarks │ │ └── tests │ │ └── Java8FeaturesTest.java │ └── resources │ └── protos │ ├── fb-bench.proto │ ├── sbe-car.proto │ └── sbe-fix-messages.proto ├── conformance ├── README.md ├── pom.xml └── src │ ├── main │ ├── java │ │ └── us │ │ │ └── hebi │ │ │ └── quickbuf │ │ │ └── conformance │ │ │ └── ConformanceQuickbuf.java │ ├── proto2 │ │ ├── test_messages_proto2.proto │ │ ├── unittest.proto │ │ ├── unittest_import.proto │ │ └── unittest_import_public.proto │ └── proto3 │ │ ├── conformance.proto │ │ ├── google │ │ └── protobuf │ │ │ ├── any.proto │ │ │ ├── duration.proto │ │ │ ├── field_mask.proto │ │ │ ├── struct.proto │ │ │ ├── timestamp.proto │ │ │ └── wrappers.proto │ │ └── test_messages_proto3.proto │ └── test │ └── java │ └── us │ └── hebi │ └── quickbuf │ └── conformance │ └── ConformanceQuickbufTest.java ├── conveyor-ci.conf ├── conveyor.conf ├── docs ├── download.html └── icon.png ├── order.md ├── pom.xml ├── proto3.md ├── protoc-gen-quickbuf ├── Readme.md ├── pom.xml └── src │ ├── main │ ├── deploy │ │ ├── apple.cer │ │ └── icons │ │ │ ├── icon-rounded-1024.png │ │ │ ├── icon-rounded-128.png │ │ │ ├── icon-rounded-256.png │ │ │ ├── icon-rounded-512.png │ │ │ ├── icon-rounded-64.png │ │ │ ├── icon-rounded.svg │ │ │ ├── icon-square-1024.png │ │ │ ├── icon-square-128.png │ │ │ ├── icon-square-16.png │ │ │ ├── icon-square-256.png │ │ │ ├── icon-square-32.png │ │ │ ├── icon-square-44.png │ │ │ ├── icon-square-512.png │ │ │ ├── icon-square-64.png │ │ │ └── icon-square.svg │ ├── java │ │ └── us │ │ │ └── hebi │ │ │ └── quickbuf │ │ │ └── generator │ │ │ ├── BitField.java │ │ │ ├── DescriptorGenerator.java │ │ │ ├── EnumGenerator.java │ │ │ ├── FieldGenerator.java │ │ │ ├── FieldUtil.java │ │ │ ├── GeneratorException.java │ │ │ ├── Javadoc.java │ │ │ ├── MessageGenerator.java │ │ │ ├── NamingUtil.java │ │ │ ├── OneOfGenerator.java │ │ │ ├── PluginOptions.java │ │ │ ├── Preconditions.java │ │ │ ├── QuickbufPlugin.java │ │ │ ├── RequestInfo.java │ │ │ ├── RuntimeClasses.java │ │ │ ├── SourceLocations.java │ │ │ └── TypeRegistry.java │ ├── resources │ │ └── META-INF │ │ │ └── native-image │ │ │ ├── jni-config.json │ │ │ └── reflect-config.json │ └── scripts │ │ ├── unix.sh │ │ └── windows.bat │ └── test │ ├── java │ └── us │ │ └── hebi │ │ └── quickbuf │ │ └── generator │ │ ├── QuickbufPluginTest.java │ │ ├── SourceLocationTests.java │ │ ├── TestRequestLoader.java │ │ └── TypeRegistryTest.java │ └── resources │ └── protos │ └── unsupported │ ├── extension.proto │ ├── map.proto │ ├── proto3.proto │ └── recursion.proto ├── protoc-gen-request ├── pom.xml └── src │ ├── main │ ├── java │ │ └── us │ │ │ └── hebi │ │ │ └── quickbuf │ │ │ └── parser │ │ │ ├── ParserUtil.java │ │ │ └── SaveRequestPlugin.java │ ├── resources │ │ └── META-INF │ │ │ └── native-image │ │ │ ├── jni-config.json │ │ │ └── reflect-config.json │ └── scripts │ │ ├── unix.sh │ │ └── windows.bat │ └── test │ └── java │ └── us │ └── hebi │ └── quickbuf │ └── parser │ └── ParserUtilTest.java ├── quickbuf-compat ├── pom.xml └── src │ ├── main │ └── java │ │ └── us │ │ └── hebi │ │ └── quickbuf │ │ └── compat │ │ ├── GsonSink.java │ │ ├── GsonSource.java │ │ ├── JacksonSink.java │ │ └── JacksonSource.java │ └── test │ └── java │ └── us │ └── hebi │ └── quickbuf │ └── compat │ ├── GsonSinkTest.java │ ├── GsonSourceTest.java │ ├── JacksonSinkTest.java │ └── JacksonSourceTest.java ├── quickbuf-runtime ├── pom.xml └── src │ ├── java9 │ ├── JdkMethods.class │ ├── JdkMethods.java │ └── compile.bat │ ├── main │ ├── java │ │ └── us │ │ │ └── hebi │ │ │ └── quickbuf │ │ │ ├── ArraySink.java │ │ │ ├── ArraySource.java │ │ │ ├── Base64.java │ │ │ ├── ByteUtil.java │ │ │ ├── Descriptors.java │ │ │ ├── FieldName.java │ │ │ ├── InvalidJsonException.java │ │ │ ├── InvalidProtocolBufferException.java │ │ │ ├── JdkMath.java │ │ │ ├── JdkMethods.java │ │ │ ├── JsonDecoding.java │ │ │ ├── JsonEncoding.java │ │ │ ├── JsonSink.java │ │ │ ├── JsonSource.java │ │ │ ├── MessageFactory.java │ │ │ ├── ProtoEnum.java │ │ │ ├── ProtoMessage.java │ │ │ ├── ProtoSink.java │ │ │ ├── ProtoSource.java │ │ │ ├── ProtoUtil.java │ │ │ ├── RepeatedBytes.java │ │ │ ├── RepeatedEnum.java │ │ │ ├── RepeatedField.java │ │ │ ├── RepeatedFloat.java │ │ │ ├── RepeatedMessage.java │ │ │ ├── RepeatedObject.java │ │ │ ├── RepeatedString.java │ │ │ ├── Schubfach.java │ │ │ ├── UninitializedMessageException.java │ │ │ ├── UnsafeAccess.java │ │ │ ├── Utf8.java │ │ │ ├── Utf8Decoder.java │ │ │ ├── Utf8String.java │ │ │ └── WireFormat.java │ └── resources │ │ └── META-INF │ │ ├── native-image │ │ └── reflect-config.json │ │ └── proguard │ │ └── quickbuf-runtime.pro │ └── test │ ├── java │ └── us │ │ └── hebi │ │ └── quickbuf │ │ ├── Base64Test.java │ │ ├── CompatibilityTest.java │ │ ├── JsonEncodingTest.java │ │ ├── JsonSinkTest.java │ │ ├── JsonSourceTest.java │ │ ├── NumericTypesTest.java │ │ ├── ProtoFailTests.java │ │ ├── ProtoTests.java │ │ └── UnsafeTest.java │ └── resources │ ├── concat │ └── RepeatedByte.txt │ ├── lazy │ ├── all_types_lazy.proto │ └── struct.proto │ └── protos │ ├── namespaces.proto │ ├── namespaces_default_package.proto │ ├── namespaces_import.proto │ ├── unittest_all_types.proto │ ├── unittest_default_package_imports.proto │ ├── unittest_field_order.proto │ ├── unittest_repeated_packables.proto │ └── unittest_required.proto └── settings.xml /.github/workflows/conformance.yml: -------------------------------------------------------------------------------- 1 | name: Protobuf Conformance Tests 2 | 3 | on: 4 | push: 5 | branches: [ main, develop ] 6 | pull_request: 7 | branches: [ main, develop ] 8 | workflow_dispatch: 9 | inputs: 10 | 11 | jobs: 12 | conformance: 13 | runs-on: ubuntu-20.04 14 | timeout-minutes: 20 15 | steps: 16 | - uses: actions/checkout@v3 17 | - uses: graalvm/setup-graalvm@v1 18 | with: 19 | version: 'latest' 20 | java-version: '21' 21 | set-java-home: 'true' 22 | components: 'native-image' 23 | cache: '' 24 | github-token: ${{ secrets.GITHUB_TOKEN }} 25 | 26 | - name: Build protoc plugins 27 | run: mvn clean package --projects protoc-gen-request,protoc-gen-quickbuf -am -PmakeNative,useNative 28 | 29 | - name: Build conformance executable 30 | run: | 31 | mvn clean package --projects quickbuf-runtime,quickbuf-compat,conformance -am -PmakeNative,useNative 32 | chmod +x conformance/target/ConformanceQuickbuf.exe 33 | 34 | - name: Conformance 3.20.2 35 | run: | 36 | # download pre-built binary because the tester takes 20+ minutes to compile 37 | wget -O conformance_test_runner https://github.com/HebiRobotics/QuickBuffers/releases/download/1.0-rc1/protoc_conformance_test_runner-3.20.2-linux-x86_64.exe 38 | chmod +x conformance_test_runner 39 | ./conformance_test_runner --enforce_recommended conformance/target/ConformanceQuickbuf.exe 40 | 41 | - name: Conformance 3.21.4 42 | run: | 43 | # download pre-built binary because the tester takes 20+ minutes to compile 44 | wget -O conformance_test_runner https://github.com/HebiRobotics/QuickBuffers/releases/download/1.0-rc1/protoc_conformance_test_runner-3.21.4.0-linux-x86_64.exe 45 | sudo wget -O /usr/lib/libjsoncpp.so.24 https://github.com/HebiRobotics/QuickBuffers/releases/download/1.0-rc1/libjsoncpp.so.1.9.4 46 | chmod +x conformance_test_runner 47 | ./conformance_test_runner --enforce_recommended conformance/target/ConformanceQuickbuf.exe -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | name: Java CI with Maven 2 | 3 | on: 4 | push: 5 | branches: [ main, develop ] 6 | pull_request: 7 | branches: [ main, develop ] 8 | workflow_dispatch: 9 | inputs: 10 | 11 | jobs: 12 | package: 13 | strategy: 14 | matrix: 15 | os: [ubuntu-latest, windows-latest, macos-latest] 16 | jdk: [1.8] 17 | 18 | runs-on: ${{ matrix.os }} 19 | continue-on-error: true 20 | steps: 21 | - uses: actions/checkout@v2 22 | - name: Set up JDK 23 | uses: actions/setup-java@v1 24 | with: 25 | java-version: ${{ matrix.jdk }} 26 | 27 | - name: Build with Maven 28 | run: mvn package 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | pom.xml.tag 3 | pom.xml.releaseBackup 4 | pom.xml.versionsBackup 5 | pom.xml.next 6 | release.properties 7 | dependency-reduced-pom.xml 8 | buildNumber.properties 9 | .mvn/timing.properties 10 | 11 | # Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) 12 | !/.mvn/wrapper/maven-wrapper.jar 13 | protoc-3.9.0-win64/ 14 | .idea/ 15 | .protoc/ 16 | *.iml 17 | generator/native-release/bin/ 18 | generator/native-release/output/ 19 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/protos/benchmarks/flatbuffers/fb/Bar.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-benchmarks 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | // automatically generated by the FlatBuffers compiler, do not modify 22 | 23 | package protos.benchmarks.flatbuffers.fb; 24 | 25 | import java.nio.*; 26 | import java.lang.*; 27 | import java.util.*; 28 | import com.google.flatbuffers.*; 29 | 30 | @SuppressWarnings("unused") 31 | public final class Bar extends Struct { 32 | public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); } 33 | public Bar __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } 34 | 35 | public protos.benchmarks.flatbuffers.fb.Foo parent() { return parent(new protos.benchmarks.flatbuffers.fb.Foo()); } 36 | public protos.benchmarks.flatbuffers.fb.Foo parent(protos.benchmarks.flatbuffers.fb.Foo obj) { return obj.__assign(bb_pos + 0, bb); } 37 | public int time() { return bb.getInt(bb_pos + 16); } 38 | public float ratio() { return bb.getFloat(bb_pos + 20); } 39 | public int size() { return bb.getShort(bb_pos + 24) & 0xFFFF; } 40 | 41 | public static int createBar(FlatBufferBuilder builder, long parent_id, short parent_count, byte parent_prefix, long parent_length, int time, float ratio, int size) { 42 | builder.prep(8, 32); 43 | builder.pad(6); 44 | builder.putShort((short)size); 45 | builder.putFloat(ratio); 46 | builder.putInt(time); 47 | builder.prep(8, 16); 48 | builder.putInt((int)parent_length); 49 | builder.pad(1); 50 | builder.putByte(parent_prefix); 51 | builder.putShort(parent_count); 52 | builder.putLong(parent_id); 53 | return builder.offset(); 54 | } 55 | 56 | public static final class Vector extends BaseVector { 57 | public Vector __assign(int _vector, int _element_size, ByteBuffer _bb) { __reset(_vector, _element_size, _bb); return this; } 58 | 59 | public Bar get(int j) { return get(new Bar(), j); } 60 | public Bar get(Bar obj, int j) { return obj.__assign(__element(j), bb); } 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/protos/benchmarks/flatbuffers/fb/Enum.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-benchmarks 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | // automatically generated by the FlatBuffers compiler, do not modify 22 | 23 | package protos.benchmarks.flatbuffers.fb; 24 | 25 | public final class Enum { 26 | private Enum() { } 27 | public static final short Apples = 0; 28 | public static final short Pears = 1; 29 | public static final short Bananas = 2; 30 | 31 | public static final String[] names = { "Apples", "Pears", "Bananas", }; 32 | 33 | public static String name(int e) { return names[e]; } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/protos/benchmarks/flatbuffers/fb/Foo.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-benchmarks 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | // automatically generated by the FlatBuffers compiler, do not modify 22 | 23 | package protos.benchmarks.flatbuffers.fb; 24 | 25 | import java.nio.*; 26 | import java.lang.*; 27 | import java.util.*; 28 | import com.google.flatbuffers.*; 29 | 30 | @SuppressWarnings("unused") 31 | public final class Foo extends Struct { 32 | public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); } 33 | public Foo __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } 34 | 35 | public long id() { return bb.getLong(bb_pos + 0); } 36 | public short count() { return bb.getShort(bb_pos + 8); } 37 | public byte prefix() { return bb.get(bb_pos + 10); } 38 | public long length() { return (long)bb.getInt(bb_pos + 12) & 0xFFFFFFFFL; } 39 | 40 | public static int createFoo(FlatBufferBuilder builder, long id, short count, byte prefix, long length) { 41 | builder.prep(8, 16); 42 | builder.putInt((int)length); 43 | builder.pad(1); 44 | builder.putByte(prefix); 45 | builder.putShort(count); 46 | builder.putLong(id); 47 | return builder.offset(); 48 | } 49 | 50 | public static final class Vector extends BaseVector { 51 | public Vector __assign(int _vector, int _element_size, ByteBuffer _bb) { __reset(_vector, _element_size, _bb); return this; } 52 | 53 | public Foo get(int j) { return get(new Foo(), j); } 54 | public Foo get(Foo obj, int j) { return obj.__assign(__element(j), bb); } 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/protos/benchmarks/flatbuffers/fb/FooBar.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-benchmarks 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | // automatically generated by the FlatBuffers compiler, do not modify 22 | 23 | package protos.benchmarks.flatbuffers.fb; 24 | 25 | import java.nio.*; 26 | import java.lang.*; 27 | import java.util.*; 28 | import com.google.flatbuffers.*; 29 | 30 | @SuppressWarnings("unused") 31 | public final class FooBar extends Table { 32 | public static void ValidateVersion() { Constants.FLATBUFFERS_2_0_0(); } 33 | public static FooBar getRootAsFooBar(ByteBuffer _bb) { return getRootAsFooBar(_bb, new FooBar()); } 34 | public static FooBar getRootAsFooBar(ByteBuffer _bb, FooBar obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); } 35 | public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); } 36 | public FooBar __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } 37 | 38 | public protos.benchmarks.flatbuffers.fb.Bar sibling() { return sibling(new protos.benchmarks.flatbuffers.fb.Bar()); } 39 | public protos.benchmarks.flatbuffers.fb.Bar sibling(protos.benchmarks.flatbuffers.fb.Bar obj) { int o = __offset(4); return o != 0 ? obj.__assign(o + bb_pos, bb) : null; } 40 | public String name() { int o = __offset(6); return o != 0 ? __string(o + bb_pos) : null; } 41 | public ByteBuffer nameAsByteBuffer() { return __vector_as_bytebuffer(6, 1); } 42 | public ByteBuffer nameInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 6, 1); } 43 | public double rating() { int o = __offset(8); return o != 0 ? bb.getDouble(o + bb_pos) : 0.0; } 44 | public int postfix() { int o = __offset(10); return o != 0 ? bb.get(o + bb_pos) & 0xFF : 0; } 45 | 46 | public static void startFooBar(FlatBufferBuilder builder) { builder.startTable(4); } 47 | public static void addSibling(FlatBufferBuilder builder, int siblingOffset) { builder.addStruct(0, siblingOffset, 0); } 48 | public static void addName(FlatBufferBuilder builder, int nameOffset) { builder.addOffset(1, nameOffset, 0); } 49 | public static void addRating(FlatBufferBuilder builder, double rating) { builder.addDouble(2, rating, 0.0); } 50 | public static void addPostfix(FlatBufferBuilder builder, int postfix) { builder.addByte(3, (byte)postfix, (byte)0); } 51 | public static int endFooBar(FlatBufferBuilder builder) { 52 | int o = builder.endTable(); 53 | return o; 54 | } 55 | 56 | public static final class Vector extends BaseVector { 57 | public Vector __assign(int _vector, int _element_size, ByteBuffer _bb) { __reset(_vector, _element_size, _bb); return this; } 58 | 59 | public FooBar get(int j) { return get(new FooBar(), j); } 60 | public FooBar get(FooBar obj, int j) { return obj.__assign(__indirect(__element(j), bb), bb); } 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/protos/benchmarks/flatbuffers/fb/FooBarContainer.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-benchmarks 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | // automatically generated by the FlatBuffers compiler, do not modify 22 | 23 | package protos.benchmarks.flatbuffers.fb; 24 | 25 | import java.nio.*; 26 | import java.lang.*; 27 | import java.util.*; 28 | import com.google.flatbuffers.*; 29 | 30 | @SuppressWarnings("unused") 31 | public final class FooBarContainer extends Table { 32 | public static void ValidateVersion() { Constants.FLATBUFFERS_2_0_0(); } 33 | public static FooBarContainer getRootAsFooBarContainer(ByteBuffer _bb) { return getRootAsFooBarContainer(_bb, new FooBarContainer()); } 34 | public static FooBarContainer getRootAsFooBarContainer(ByteBuffer _bb, FooBarContainer obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); } 35 | public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); } 36 | public FooBarContainer __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } 37 | 38 | public protos.benchmarks.flatbuffers.fb.FooBar list(int j) { return list(new protos.benchmarks.flatbuffers.fb.FooBar(), j); } 39 | public protos.benchmarks.flatbuffers.fb.FooBar list(protos.benchmarks.flatbuffers.fb.FooBar obj, int j) { int o = __offset(4); return o != 0 ? obj.__assign(__indirect(__vector(o) + j * 4), bb) : null; } 40 | public int listLength() { int o = __offset(4); return o != 0 ? __vector_len(o) : 0; } 41 | public protos.benchmarks.flatbuffers.fb.FooBar.Vector listVector() { return listVector(new protos.benchmarks.flatbuffers.fb.FooBar.Vector()); } 42 | public protos.benchmarks.flatbuffers.fb.FooBar.Vector listVector(protos.benchmarks.flatbuffers.fb.FooBar.Vector obj) { int o = __offset(4); return o != 0 ? obj.__assign(__vector(o), 4, bb) : null; } 43 | public boolean initialized() { int o = __offset(6); return o != 0 ? 0!=bb.get(o + bb_pos) : false; } 44 | public short fruit() { int o = __offset(8); return o != 0 ? bb.getShort(o + bb_pos) : 0; } 45 | public String location() { int o = __offset(10); return o != 0 ? __string(o + bb_pos) : null; } 46 | public ByteBuffer locationAsByteBuffer() { return __vector_as_bytebuffer(10, 1); } 47 | public ByteBuffer locationInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 10, 1); } 48 | 49 | public static int createFooBarContainer(FlatBufferBuilder builder, 50 | int listOffset, 51 | boolean initialized, 52 | short fruit, 53 | int locationOffset) { 54 | builder.startTable(4); 55 | FooBarContainer.addLocation(builder, locationOffset); 56 | FooBarContainer.addList(builder, listOffset); 57 | FooBarContainer.addFruit(builder, fruit); 58 | FooBarContainer.addInitialized(builder, initialized); 59 | return FooBarContainer.endFooBarContainer(builder); 60 | } 61 | 62 | public static void startFooBarContainer(FlatBufferBuilder builder) { builder.startTable(4); } 63 | public static void addList(FlatBufferBuilder builder, int listOffset) { builder.addOffset(0, listOffset, 0); } 64 | public static int createListVector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); } 65 | public static void startListVector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); } 66 | public static void addInitialized(FlatBufferBuilder builder, boolean initialized) { builder.addBoolean(1, initialized, false); } 67 | public static void addFruit(FlatBufferBuilder builder, short fruit) { builder.addShort(2, fruit, 0); } 68 | public static void addLocation(FlatBufferBuilder builder, int locationOffset) { builder.addOffset(3, locationOffset, 0); } 69 | public static int endFooBarContainer(FlatBufferBuilder builder) { 70 | int o = builder.endTable(); 71 | return o; 72 | } 73 | public static void finishFooBarContainerBuffer(FlatBufferBuilder builder, int offset) { builder.finish(offset); } 74 | public static void finishSizePrefixedFooBarContainerBuffer(FlatBufferBuilder builder, int offset) { builder.finishSizePrefixed(offset); } 75 | 76 | public static final class Vector extends BaseVector { 77 | public Vector __assign(int _vector, int _element_size, ByteBuffer _bb) { __reset(_vector, _element_size, _bb); return this; } 78 | 79 | public FooBarContainer get(int j) { return get(new FooBarContainer(), j); } 80 | public FooBarContainer get(FooBarContainer obj, int j) { return obj.__assign(__indirect(__element(j), bb), bb); } 81 | } 82 | } 83 | 84 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/us/hebi/quickbuf/benchmarks/PrintMemoryLayout.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * benchmarks 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf.benchmarks; 22 | 23 | import org.openjdk.jol.info.ClassLayout; 24 | import org.openjdk.jol.info.FieldLayout; 25 | import org.openjdk.jol.info.GraphLayout; 26 | import org.openjdk.jol.vm.VM; 27 | import org.openjdk.jol.vm.VirtualMachine; 28 | import us.hebi.quickbuf.ProtoMessage; 29 | import protos.test.quickbuf.TestAllTypes; 30 | 31 | import java.io.IOException; 32 | import java.lang.reflect.Field; 33 | import java.lang.reflect.Modifier; 34 | import java.util.ArrayList; 35 | import java.util.HashMap; 36 | import java.util.List; 37 | import java.util.stream.Stream; 38 | 39 | /** 40 | * @author Florian Enner 41 | * @since 16 Aug 2019 42 | */ 43 | public class PrintMemoryLayout { 44 | 45 | public static void main(String[] args) throws IllegalAccessException, IOException { 46 | Class clazz = protos.test.quickbuf.TestAllTypes.class; 47 | ClassLayout layout = ClassLayout.parseClass(clazz); 48 | FieldOffsetMap offsetMap = new FieldOffsetMap(layout); 49 | 50 | System.out.println("---- Full Summary ---- "); 51 | System.out.println(layout.toPrintable()); 52 | 53 | System.out.println("---- Order of declared fields ---- "); 54 | System.out.println("[index => offset (cacheLine)] name"); 55 | List fields = getInstanceFields(clazz); 56 | int i = 0; 57 | for (Field field : fields) { 58 | long offset = offsetMap.getOffset(field); 59 | long cacheLine = offset / CACHE_LINE_SIZE; // assumes alignment with cache line boundary, which may not be true 60 | String string = String.format("[%3d => %3d (%1d)] %s", (i++), offset, cacheLine, field.getName()); 61 | System.out.println(string); 62 | } 63 | 64 | System.out.println("---- Object Graph ---- "); 65 | ProtoMessage msg = TestAllTypes.newInstance(); 66 | System.out.println(GraphLayout.parseInstance(msg).toPrintable()); 67 | 68 | System.out.println("---- Offsets of Nested Messages ---- "); 69 | printNestedOffsets(msg); 70 | 71 | } 72 | 73 | private static void printNestedOffsets(ProtoMessage message) throws IllegalAccessException { 74 | printNestedOffsets(null, message.getClass().getSimpleName(), message, 0); 75 | } 76 | 77 | /** 78 | * running it causes allocations and mess with results. unreliable 79 | */ 80 | private static void printNestedOffsets(ProtoMessage parent, String name, ProtoMessage message, int indents) throws IllegalAccessException { 81 | for (int i = 0; i < indents; i++) { 82 | System.out.print(" "); 83 | } 84 | 85 | long endOfParent = parent == null ? vm.addressOf(message) : vm.addressOf(parent) + vm.sizeOf(parent); 86 | long start = vm.addressOf(message) - endOfParent; 87 | long end = start + vm.sizeOf(message); 88 | System.out.println(String.format("%d-%d : %s", start, end, name)); 89 | 90 | for (Field field : message.getClass().getDeclaredFields()) { 91 | field.setAccessible(true); 92 | 93 | Object value = field.get(message); 94 | if (value instanceof ProtoMessage) { 95 | printNestedOffsets(message, field.getName(), (ProtoMessage) value, indents + 2); 96 | } 97 | 98 | } 99 | } 100 | 101 | private static List getInstanceFields(Class clazz) { 102 | List fields = new ArrayList<>(); 103 | if (clazz.getSuperclass() != null) { 104 | fields.addAll(getInstanceFields(clazz.getSuperclass())); 105 | } 106 | Stream.of(clazz.getDeclaredFields()) 107 | .filter(f -> !Modifier.isStatic(f.getModifiers())) 108 | .forEach(fields::add); 109 | return fields; 110 | } 111 | 112 | private static class FieldOffsetMap { 113 | 114 | FieldOffsetMap(ClassLayout layout) { 115 | this.layout = layout; 116 | for (FieldLayout field : layout.fields()) { 117 | map.put(field.name(), field); 118 | } 119 | } 120 | 121 | public long getOffset(Field field) { 122 | return map.get(field.getName()).offset(); 123 | } 124 | 125 | final ClassLayout layout; 126 | final HashMap map = new HashMap<>(); 127 | 128 | } 129 | 130 | private static final int CACHE_LINE_SIZE = 64; 131 | private static VirtualMachine vm = VM.current(); 132 | 133 | } 134 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/us/hebi/quickbuf/benchmarks/UnsafeUtil.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * benchmarks 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf.benchmarks; 22 | 23 | import sun.misc.Unsafe; 24 | import sun.nio.ch.DirectBuffer; 25 | 26 | import java.lang.reflect.Field; 27 | import java.nio.ByteBuffer; 28 | import java.security.AccessController; 29 | import java.security.PrivilegedExceptionAction; 30 | 31 | /** 32 | * @author Florian Enner 33 | * @since 31 Jul 2019 34 | */ 35 | public class UnsafeUtil { 36 | 37 | public static final Unsafe UNSAFE; 38 | public static final long BYTE_ARRAY_OFFSET; 39 | 40 | static { 41 | try { 42 | final PrivilegedExceptionAction action = 43 | new PrivilegedExceptionAction() { 44 | @Override 45 | public Unsafe run() throws Exception { 46 | final Field f = Unsafe.class.getDeclaredField("theUnsafe"); 47 | f.setAccessible(true); 48 | return (Unsafe) f.get(null); 49 | } 50 | }; 51 | UNSAFE = AccessController.doPrivileged(action); 52 | BYTE_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(byte[].class); 53 | 54 | } catch (final Exception ex) { 55 | throw new AssertionError("Unsafe not available"); 56 | } 57 | 58 | } 59 | 60 | public static long getDirectAddress(ByteBuffer buffer) { 61 | return ((DirectBuffer) buffer).address(); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/us/hebi/quickbuf/benchmarks/comparison/PackedDoublesBenchmark.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * benchmarks 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf.benchmarks.comparison; 22 | 23 | import com.google.protobuf.CodedOutputStream; 24 | import org.openjdk.jmh.annotations.*; 25 | import org.openjdk.jmh.runner.Runner; 26 | import org.openjdk.jmh.runner.RunnerException; 27 | import org.openjdk.jmh.runner.options.Options; 28 | import org.openjdk.jmh.runner.options.OptionsBuilder; 29 | import org.openjdk.jmh.runner.options.VerboseMode; 30 | import us.hebi.quickbuf.ProtoSink; 31 | import us.hebi.quickbuf.ProtoSource; 32 | import protos.test.quickbuf.RepeatedPackables.Packed; 33 | 34 | import java.io.IOException; 35 | import java.util.concurrent.TimeUnit; 36 | 37 | /** 38 | * Serializes a single massive packed double array. Represents best case scenario. 39 | * Represents the last dataset in the Readme benchmarks. 40 | * 41 | * === Quickbuf rc1 (JDK17) 42 | * Benchmark Mode Cnt Score Error Units 43 | * PackedDoublesBenchmark.readQuick avgt 40 5,836 ± 0,067 ms/op 44 | * PackedDoublesBenchmark.readWriteQuick avgt 40 11,429 ± 0,151 ms/op 45 | * 46 | * === Protobuf-Java 3.21.12 (jdk17) 47 | * Benchmark Mode Cnt Score Error Units 48 | * PackedDoublesBenchmark.readProto avgt 10 68,347 ± 2,500 ms/op 49 | * PackedDoublesBenchmark.readWriteProto avgt 10 108,304 ± 2,519 ms/op 50 | * 51 | * === Protobuf-Javalite 3.19.4 (JDK17) 52 | * Benchmark Mode Cnt Score Error Units 53 | * PackedDoublesBenchmark.readProto avgt 40 63,476 ± 1,040 ms/op 54 | * PackedDoublesBenchmark.readWriteProto avgt 40 102,466 ± 0,800 ms/op 55 | * 56 | * @author Florian Enner 57 | * @since 13 Oct 2019 58 | */ 59 | @BenchmarkMode(Mode.AverageTime) 60 | @OutputTimeUnit(TimeUnit.MILLISECONDS) 61 | @Fork(2) 62 | @Warmup(iterations = 5, time = 250, timeUnit = TimeUnit.MILLISECONDS) 63 | @Measurement(iterations = 5, time = 250, timeUnit = TimeUnit.MILLISECONDS) 64 | @State(Scope.Thread) 65 | public class PackedDoublesBenchmark { 66 | 67 | public static void main(String[] args) throws RunnerException { 68 | Options options = new OptionsBuilder() 69 | .include(".*" + PackedDoublesBenchmark.class.getSimpleName() + ".*") 70 | .verbosity(VerboseMode.NORMAL) 71 | .build(); 72 | new Runner(options).run(); 73 | } 74 | 75 | final byte[] input = Packed.newInstance().addAllDoubles(new double[8 * 1024 * 1024]).toByteArray(); 76 | final byte[] output = new byte[input.length + 100]; 77 | 78 | final ProtoSource source = ProtoSource.newArraySource(); 79 | final ProtoSink sink = ProtoSink.newArraySink(); 80 | 81 | final Packed message = Packed.newInstance(); 82 | 83 | @Benchmark 84 | public Object readQuick() throws IOException { 85 | source.setInput(input); 86 | return message.clear().mergeFrom(source); 87 | } 88 | 89 | @Benchmark 90 | public int readWriteQuick() throws IOException { 91 | message.clear().mergeFrom(source.setInput(input)).writeTo(sink.setOutput(output)); 92 | return sink.getTotalBytesWritten(); 93 | } 94 | 95 | @Benchmark 96 | public Object readProto() throws IOException { 97 | return protos.test.protobuf.RepeatedPackables.Packed.parseFrom(input); 98 | } 99 | 100 | @Benchmark 101 | public int readWriteProto() throws IOException { 102 | CodedOutputStream out = CodedOutputStream.newInstance(output); 103 | protos.test.protobuf.RepeatedPackables.Packed.parseFrom(input) 104 | .writeTo(out); 105 | return out.getTotalBytesWritten(); 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/us/hebi/quickbuf/benchmarks/encoding/PrimitiveWriteBenchmark.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * benchmarks 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf.benchmarks.encoding; 22 | 23 | import org.openjdk.jmh.annotations.*; 24 | import org.openjdk.jmh.runner.Runner; 25 | import org.openjdk.jmh.runner.RunnerException; 26 | import org.openjdk.jmh.runner.options.Options; 27 | import org.openjdk.jmh.runner.options.OptionsBuilder; 28 | import org.openjdk.jmh.runner.options.VerboseMode; 29 | import us.hebi.quickbuf.ProtoSink; 30 | import protos.test.quickbuf.TestAllTypes; 31 | 32 | import java.io.IOException; 33 | import java.util.Random; 34 | import java.util.concurrent.TimeUnit; 35 | 36 | /** 37 | * Benchmark Mode Cnt Score Error Units 38 | * PrimitiveWriteBenchmark.writeRepeatedDouble64 avgt 10 3.362 ± 0.045 us/op (x512) 39 | * PrimitiveWriteBenchmark.writeRepeatedInt32 avgt 10 3.344 ± 0.030 us/op (x512) 40 | * 41 | * PrimitiveWriteBenchmark.writeDouble64 avgt 10 0.026 ± 0.001 us/op 42 | * PrimitiveWriteBenchmark.writeFloat32 avgt 10 0.024 ± 0.001 us/op 43 | * PrimitiveWriteBenchmark.writeVarint32_1 avgt 10 0.023 ± 0.001 us/op 44 | * PrimitiveWriteBenchmark.writeVarint32_5 avgt 10 0.028 ± 0.001 us/op 45 | * PrimitiveWriteBenchmark.writeVarint64_1 avgt 10 0.022 ± 0.001 us/op 46 | * PrimitiveWriteBenchmark.writeVarint64_10 avgt 10 0.032 ± 0.002 us/op 47 | * 48 | * @author Florian Enner 49 | * @since 16 Aug 2019 50 | */ 51 | @BenchmarkMode(Mode.AverageTime) 52 | @OutputTimeUnit(TimeUnit.MICROSECONDS) 53 | @Fork(2) 54 | @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) 55 | @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) 56 | @State(Scope.Thread) 57 | public class PrimitiveWriteBenchmark { 58 | 59 | public static void main(String[] args) throws RunnerException { 60 | Options options = new OptionsBuilder() 61 | .include(".*" + PrimitiveWriteBenchmark.class.getSimpleName() + ".*Repeated.*") 62 | .verbosity(VerboseMode.NORMAL) 63 | .build(); 64 | new Runner(options).run(); 65 | } 66 | 67 | final Random rnd = new Random(); 68 | final TestAllTypes msg = TestAllTypes.newInstance(); 69 | byte[] outputBuffer = new byte[10 * 1024]; 70 | final ProtoSink sink = ProtoSink.newInstance(outputBuffer); 71 | final double[] doubleArray = new double[512]; 72 | final int[] intArray = new int[512]; 73 | 74 | @Setup(Level.Trial) 75 | public void setupData() { 76 | msg.clear(); 77 | for (int i = 0; i < doubleArray.length; i++) { 78 | doubleArray[i] = rnd.nextDouble(); 79 | intArray[i] = rnd.nextInt(); 80 | } 81 | } 82 | 83 | @Benchmark 84 | public int writeVarint32_1() throws IOException { 85 | return write(msg.setOptionalInt32(42)); 86 | } 87 | 88 | @Benchmark 89 | public int writeVarint32_5() throws IOException { 90 | return write(msg.setOptionalInt32(Integer.MAX_VALUE)); 91 | } 92 | 93 | @Benchmark 94 | public int writeVarint64_1() throws IOException { 95 | return write(msg.setOptionalInt64(42)); 96 | } 97 | 98 | @Benchmark 99 | public int writeVarint64_10() throws IOException { 100 | return write(msg.setOptionalInt64(Long.MAX_VALUE)); 101 | } 102 | 103 | @Benchmark 104 | public int writeFloat32() throws IOException { 105 | return write(msg.setOptionalFloat(42)); 106 | } 107 | 108 | @Benchmark 109 | public int writeDouble64() throws IOException { 110 | return write(msg.setOptionalDouble(42)); 111 | } 112 | 113 | @Benchmark 114 | public int writeRepeatedDouble64() throws IOException { 115 | msg.getMutableRepeatedDouble().copyFrom(doubleArray); 116 | return write(msg); 117 | } 118 | 119 | @Benchmark 120 | public int writeRepeatedInt32() throws IOException { 121 | msg.getMutableRepeatedDouble().copyFrom(doubleArray); 122 | return write(msg); 123 | } 124 | 125 | private int write(TestAllTypes msg) throws IOException { 126 | sink.reset(); 127 | msg.writeTo(sink); 128 | return sink.getTotalBytesWritten(); 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/us/hebi/quickbuf/benchmarks/flatbuffers/FlatBuffersBench.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-benchmarks 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf.benchmarks.flatbuffers; 22 | 23 | import protos.benchmarks.flatbuffers.fb.*; 24 | import com.google.flatbuffers.FlatBufferBuilder; 25 | import org.openjdk.jmh.annotations.Scope; 26 | import org.openjdk.jmh.annotations.State; 27 | import protos.benchmarks.flatbuffers.fb.Enum; 28 | 29 | import java.nio.ByteBuffer; 30 | 31 | /** 32 | * @author Florian Enner 33 | * @since 27 Jan 2015 34 | */ 35 | @State(Scope.Thread) 36 | public class FlatBuffersBench { 37 | 38 | public int encode(ByteBuffer buffer) { 39 | FlatBufferBuilder builder = new FlatBufferBuilder(buffer); 40 | 41 | for (int i = 0; i < vecLen; i++) { 42 | 43 | int name = builder.createString("Hello, World!"); 44 | 45 | FooBar.startFooBar(builder); 46 | FooBar.addName(builder, name); 47 | FooBar.addRating(builder, 3.1415432432445543543 + i); 48 | FooBar.addPostfix(builder, (byte) ('!' + i)); 49 | 50 | int bar = Bar.createBar(builder, 51 | // Foo fields (nested struct) 52 | 0xABADCAFEABADCAFEL + i, 53 | (short) (10000 + i), 54 | (byte) ('@' + i), 55 | 1000000 + i, 56 | // Bar fields 57 | 123456 + i, 58 | 3.14159f + i, 59 | (short) (10000 + i)); 60 | 61 | FooBar.addSibling(builder, bar); 62 | int fooBar = FooBar.endFooBar(builder); 63 | fooBars[i] = fooBar; 64 | 65 | } 66 | 67 | int list = FooBarContainer.createListVector(builder, fooBars); 68 | int loc = builder.createString(location); 69 | 70 | FooBarContainer.startFooBarContainer(builder); 71 | FooBarContainer.addLocation(builder, loc); 72 | FooBarContainer.addInitialized(builder, initialized); 73 | FooBarContainer.addFruit(builder, anEnum); 74 | FooBarContainer.addLocation(builder, loc); 75 | FooBarContainer.addList(builder, list); 76 | int fooBarContainer = FooBarContainer.endFooBarContainer(builder); 77 | builder.finish(fooBarContainer); 78 | 79 | return buffer.position(); 80 | } 81 | 82 | public FooBarContainer decode(ByteBuffer buffer) { 83 | return FooBarContainer.getRootAsFooBarContainer(buffer); 84 | } 85 | 86 | public long traverse(FooBarContainer fooBarContainer) { 87 | 88 | long sum = 0; 89 | sum += fooBarContainer.initialized() ? 1 : 0; 90 | sum += fooBarContainer.location().length(); 91 | sum += fooBarContainer.fruit(); 92 | 93 | int length = fooBarContainer.listLength(); 94 | for (int i = 0; i < length; i++) { 95 | 96 | fooBarContainer.list(fooBar, i); 97 | sum += fooBar.name().length(); 98 | sum += fooBar.postfix(); 99 | sum += (long) fooBar.rating(); 100 | 101 | fooBar.sibling(bar); 102 | sum += bar.size(); 103 | sum += bar.time(); 104 | sum += bar.ratio(); 105 | 106 | bar.parent(foo); 107 | sum += foo.count(); 108 | sum += foo.id(); 109 | sum += foo.length(); 110 | sum += foo.prefix(); 111 | 112 | } 113 | 114 | return sum; 115 | 116 | } 117 | 118 | // reusable read objects 119 | FooBar fooBar = new FooBar(); 120 | Bar bar = new Bar(); 121 | Foo foo = new Foo(); 122 | 123 | private static int vecLen = 3; 124 | private static int[] fooBars = new int[vecLen]; 125 | private static String location = "http://google.com/flatbuffers/"; 126 | private static boolean initialized = true; 127 | private static short anEnum = Enum.Bananas; 128 | 129 | } 130 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/us/hebi/quickbuf/benchmarks/flatbuffers/QuickBuffersBench.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-benchmarks 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf.benchmarks.flatbuffers; 22 | 23 | import org.openjdk.jmh.annotations.Scope; 24 | import org.openjdk.jmh.annotations.State; 25 | import protos.benchmarks.flatbuffers.quickbuf.*; 26 | import us.hebi.quickbuf.ProtoSink; 27 | import us.hebi.quickbuf.ProtoSource; 28 | 29 | import java.io.IOException; 30 | 31 | /** 32 | * @author Florian Enner 33 | * @since 28 Oct 2019 34 | */ 35 | @State(Scope.Thread) 36 | public class QuickBuffersBench { 37 | 38 | static FooBarContainer setData(FooBarContainer fooBarContainer) { 39 | fooBarContainer.clearQuick() 40 | .setFruitValue(anEnum) 41 | .setInitialized(initialized) 42 | .setLocation(location); 43 | 44 | for (int i = 0; i < vecLen; i++) { 45 | 46 | fooBarContainer.getMutableList().next() 47 | .setRating(3.1415432432445543543 + i) 48 | .setPostfix('!' + i) 49 | .setName("Hello, World!") 50 | 51 | .getMutableSibling() 52 | .setRatio(3.14159f + i) 53 | .setTime(123456 + i) 54 | .setSize(10000 + i) 55 | 56 | .getMutableParent() 57 | .setId(0xABADCAFEABADCAFEL + i) 58 | .setCount(10000 + i) 59 | .setPrefix('@' + i) 60 | .setLength(1000000 + i); 61 | 62 | } 63 | 64 | return fooBarContainer; 65 | } 66 | 67 | public int encode() { 68 | try { 69 | sink.setOutput(encodeBuffer); 70 | setData(encodeMsg).writeTo(sink); 71 | return sink.getTotalBytesWritten(); 72 | } catch (IOException e) { 73 | throw new RuntimeException(e.getMessage()); 74 | } 75 | } 76 | 77 | public FooBarContainer decode() { 78 | try { 79 | return decodeMsg.clearQuick().mergeFrom(source.setInput(decodeBuffer)); 80 | } catch (IOException e) { 81 | throw new RuntimeException(e.getMessage()); 82 | } 83 | } 84 | 85 | public long traverse(FooBarContainer fooBarContainer) { 86 | long sum = 0; 87 | sum += fooBarContainer.getInitialized() ? 1 : 0; 88 | sum += fooBarContainer.getLocation().length(); 89 | sum += fooBarContainer.getFruit().getNumber(); 90 | 91 | for (FooBar fooBar : fooBarContainer.getList()) { 92 | 93 | sum += fooBar.getPostfix(); 94 | sum += (long) fooBar.getRating(); 95 | sum += fooBar.getNameBytes().size(); 96 | 97 | Bar bar = fooBar.getSibling(); 98 | sum += bar.getRatio(); 99 | sum += bar.getTime(); 100 | sum += bar.getSize(); 101 | 102 | Foo foo = bar.getParent(); 103 | sum += foo.getId(); 104 | sum += foo.getCount(); 105 | sum += foo.getPrefix(); 106 | sum += foo.getLength(); 107 | 108 | } 109 | 110 | return sum; 111 | 112 | } 113 | 114 | final FooBarContainer encodeMsg = setData(FooBarContainer.newInstance()); 115 | 116 | byte[] encodeBuffer = encodeMsg.toByteArray(); 117 | ProtoSink sink = ProtoSink.newDirectSink().setOutput(encodeBuffer); 118 | 119 | FooBarContainer decodeMsg = FooBarContainer.newInstance(); 120 | byte[] decodeBuffer = encodeBuffer.clone(); 121 | ProtoSource source = ProtoSource.newDirectSource().setInput(decodeBuffer); 122 | 123 | private static int vecLen = 3; 124 | private static String location = "http://google.com/flatbuffers/"; 125 | private static boolean initialized = true; 126 | private static int anEnum = Fruit.Bananas_VALUE; 127 | 128 | } 129 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/us/hebi/quickbuf/benchmarks/jdk/JdkMethodsBenchmark.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-benchmarks 4 | * %% 5 | * Copyright (C) 2019 - 2023 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package us.hebi.quickbuf.benchmarks.jdk; 21 | 22 | import org.openjdk.jmh.annotations.*; 23 | import org.openjdk.jmh.runner.Runner; 24 | import org.openjdk.jmh.runner.RunnerException; 25 | import org.openjdk.jmh.runner.options.Options; 26 | import org.openjdk.jmh.runner.options.OptionsBuilder; 27 | import org.openjdk.jmh.runner.options.VerboseMode; 28 | import us.hebi.quickbuf.JdkMath; 29 | 30 | import java.util.Random; 31 | import java.util.concurrent.TimeUnit; 32 | 33 | /** 34 | * === Zulu 8 === 35 | * Benchmark Mode Cnt Score Error Units 36 | * JdkMethodsBenchmark.testMultiplyHigh_wrapper thrpt 20 572,132 ± 45,258 ops/ms 37 | *

38 | * === Zulu 17 === 39 | * Benchmark Mode Cnt Score Error Units 40 | * JdkMethodsBenchmark.testMultiplyHigh_direct thrpt 20 1848,684 ± 64,099 ops/ms 41 | * JdkMethodsBenchmark.testMultiplyHigh_wrapper thrpt 20 1853,370 ± 46,721 ops/ms 42 | *

43 | * === Graal 17 === 44 | * Benchmark Mode Cnt Score Error Units 45 | * JdkMethodsBenchmark.testMultiplyHigh_direct thrpt 20 417,786 ± 33,152 ops/ms 46 | * JdkMethodsBenchmark.testMultiplyHigh_wrapper thrpt 20 436,781 ± 22,462 ops/ms 47 | * 48 | * @author Florian Enner 49 | * @since 22 Jan 2023 50 | */ 51 | @BenchmarkMode(Mode.Throughput) 52 | @OutputTimeUnit(TimeUnit.MILLISECONDS) 53 | @Fork(2) 54 | @Warmup(iterations = 5, time = 250, timeUnit = TimeUnit.MILLISECONDS) 55 | @Measurement(iterations = 10, time = 250, timeUnit = TimeUnit.MILLISECONDS) 56 | @State(Scope.Thread) 57 | public class JdkMethodsBenchmark { 58 | 59 | public static void main(String[] args) throws RunnerException { 60 | Options options = new OptionsBuilder() 61 | .include(".*" + JdkMethodsBenchmark.class.getSimpleName() + ".*") 62 | .verbosity(VerboseMode.NORMAL) 63 | .build(); 64 | new Runner(options).run(); 65 | } 66 | 67 | final long[] lValues = new long[1024]; 68 | 69 | { 70 | final Random rnd = new Random(0); 71 | for (int i = 0; i < lValues.length; i++) { 72 | lValues[i] = rnd.nextLong(); 73 | } 74 | } 75 | 76 | @Benchmark 77 | public long testMultiplyHigh_wrapper() { 78 | long result = 0; 79 | for (int i = 1; i < lValues.length; i++) { 80 | result |= JdkMath.multiplyHigh(lValues[i - 1], lValues[i]); 81 | } 82 | return result; 83 | } 84 | 85 | /* @Benchmark 86 | public long testMultiplyHigh_direct() { 87 | long result = 0; 88 | for (int i = 1; i < lValues.length; i++) { 89 | result |= java.lang.Math.multiplyHigh(lValues[i - 1], lValues[i]); 90 | } 91 | return result; 92 | }*/ 93 | 94 | } 95 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/us/hebi/quickbuf/benchmarks/json/JsonSinkBenchmark.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-benchmarks 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf.benchmarks.json; 22 | 23 | import org.openjdk.jmh.annotations.*; 24 | import org.openjdk.jmh.runner.Runner; 25 | import org.openjdk.jmh.runner.RunnerException; 26 | import org.openjdk.jmh.runner.options.Options; 27 | import org.openjdk.jmh.runner.options.OptionsBuilder; 28 | import org.openjdk.jmh.runner.options.VerboseMode; 29 | import protos.benchmarks.real_logic.quickbuf.Examples.Car; 30 | import protos.benchmarks.real_logic.quickbuf.Fix.MarketDataIncrementalRefreshTrades; 31 | import us.hebi.quickbuf.JsonSink; 32 | import us.hebi.quickbuf.compat.GsonSink; 33 | import us.hebi.quickbuf.compat.JacksonSink; 34 | 35 | import java.io.IOException; 36 | import java.io.StringWriter; 37 | import java.util.concurrent.TimeUnit; 38 | 39 | import static us.hebi.quickbuf.benchmarks.comparison.SbeThroughputBenchmarkQuickbuf.*; 40 | 41 | /** 42 | * === Quickbuf RC1 (JDK 17) 43 | * Benchmark Mode Cnt Score Error Units 44 | * JsonSinkBenchmark.testGsonCarEncode thrpt 20 252,798 ± 2,027 ops/ms 45 | * JsonSinkBenchmark.testGsonMarketEncode thrpt 20 439,188 ± 3,255 ops/ms 46 | * JsonSinkBenchmark.testJacksonCarEncode thrpt 20 396,907 ± 2,105 ops/ms 47 | * JsonSinkBenchmark.testJacksonMarketEncode thrpt 20 621,604 ± 9,139 ops/ms 48 | * 49 | * JsonSinkBenchmark.testJsonCarEncode thrpt 20 1435,850 ± 40,645 ops/ms 50 | * JsonSinkBenchmark.testJsonMarketEncode thrpt 20 3602,384 ± 142,406 ops/ms 51 | * 52 | * @author Florian Enner 53 | * @since 28 Nov 2019 54 | */ 55 | @BenchmarkMode(Mode.Throughput) 56 | @OutputTimeUnit(TimeUnit.MILLISECONDS) 57 | @Fork(2) 58 | @Warmup(iterations = 5, time = 250, timeUnit = TimeUnit.MILLISECONDS) 59 | @Measurement(iterations = 5, time = 250, timeUnit = TimeUnit.MILLISECONDS) 60 | @State(Scope.Thread) 61 | public class JsonSinkBenchmark { 62 | 63 | public static void main(String[] args) throws RunnerException { 64 | Options options = new OptionsBuilder() 65 | .include(".*" + JsonSinkBenchmark.class.getSimpleName() + ".*") 66 | .verbosity(VerboseMode.NORMAL) 67 | .build(); 68 | new Runner(options).run(); 69 | } 70 | 71 | final JsonSink jsonSink = JsonSink.newInstance().setWriteEnumsAsInts(true).reserve(2048); 72 | final MarketDataIncrementalRefreshTrades marketData = MarketDataIncrementalRefreshTrades.newInstance(); 73 | final Car car = Car.newInstance(); 74 | private final StringWriter encodeString = new StringWriter(); 75 | 76 | @Benchmark 77 | public Object testJsonMarketEncode() throws IOException { 78 | return jsonSink.clear() 79 | .writeMessage(buildMarketData(marketData)) 80 | .getBytes(); 81 | } 82 | 83 | @Benchmark 84 | public Object testJsonCarEncode() throws IOException { 85 | return jsonSink.clear() 86 | .writeMessage(buildCarData(car)) 87 | .getBytes(); 88 | } 89 | 90 | @Benchmark 91 | public Object testGsonMarketEncode() throws IOException { 92 | encodeString.getBuffer().setLength(0); 93 | return GsonSink.newStringWriter(encodeString) 94 | .setWriteEnumsAsInts(true) 95 | .writeMessage(buildMarketData(marketData)) 96 | .getChars(); 97 | } 98 | 99 | @Benchmark 100 | public Object testGsonCarEncode() throws IOException { 101 | encodeString.getBuffer().setLength(0); 102 | return GsonSink.newStringWriter(encodeString) 103 | .setWriteEnumsAsInts(true) 104 | .writeMessage(buildCarData(car)) 105 | .getChars(); 106 | } 107 | 108 | @Benchmark 109 | public Object testJacksonMarketEncode() throws IOException { 110 | encodeString.getBuffer().setLength(0); 111 | return JacksonSink.newStringWriter(encodeString) 112 | .setWriteEnumsAsInts(true) 113 | .writeMessage(buildMarketData(marketData)) 114 | .getChars(); 115 | } 116 | 117 | @Benchmark 118 | public Object testJacksonCarEncode() throws IOException { 119 | encodeString.getBuffer().setLength(0); 120 | return JacksonSink.newStringWriter(encodeString) 121 | .setWriteEnumsAsInts(true) 122 | .writeMessage(buildCarData(car)) 123 | .getChars(); 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/us/hebi/quickbuf/benchmarks/wrapper/SourceWrappers.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * benchmarks 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf.benchmarks.wrapper; 22 | 23 | import static us.hebi.quickbuf.benchmarks.UnsafeUtil.*; 24 | 25 | /** 26 | * @author Florian Enner 27 | * @since 31 Jul 2019 28 | */ 29 | class SourceWrappers { 30 | 31 | static class ArrayWrapper { 32 | 33 | ArrayWrapper(byte[] bytes) { 34 | this.bytes = bytes; 35 | this.remaining = bytes.length; 36 | } 37 | 38 | boolean hasNext() { 39 | return remaining > 0; 40 | } 41 | 42 | boolean hasNext(int numBytes) { 43 | return remaining >= numBytes; 44 | } 45 | 46 | int next() { 47 | try { 48 | return bytes[position++] & 0xFF; 49 | } finally { 50 | remaining--; 51 | } 52 | } 53 | 54 | int nextInt() { 55 | try { 56 | return bytes[position++] << 24 57 | | bytes[position++] << 16 58 | | bytes[position++] << 8 59 | | bytes[position++]; 60 | } finally { 61 | remaining -= 4; 62 | } 63 | 64 | } 65 | 66 | /* int nextInt() { 67 | try { 68 | return UNSAFE.getInt(bytes, BYTE_ARRAY_OFFSET + position); 69 | } finally { 70 | position += 4; 71 | remaining -= 4; 72 | } 73 | }*/ 74 | 75 | final byte[] bytes; 76 | int remaining = 0; 77 | int position = 0; 78 | 79 | } 80 | 81 | static class UnsafeWrapper { 82 | 83 | UnsafeWrapper(byte[] object, long offset, int length) { 84 | this.object = object; 85 | this.position = offset; 86 | this.limit = offset + length; 87 | this.remaining = length; 88 | } 89 | 90 | boolean hasNext() { 91 | return remaining > 0; 92 | } 93 | 94 | boolean hasNext(int numBytes) { 95 | return remaining >= numBytes; 96 | } 97 | 98 | int next() { 99 | try { 100 | return UNSAFE.getByte(object, position) & 0xFF; 101 | } finally { 102 | position++; 103 | remaining--; 104 | } 105 | } 106 | 107 | int nextInt() { 108 | try { 109 | return UNSAFE.getInt(object, position); 110 | } finally { 111 | position += 4; 112 | remaining -= 4; 113 | } 114 | } 115 | 116 | final byte[] object; 117 | final long limit; 118 | long position; 119 | int remaining; 120 | 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /benchmarks/src/test/resources/protos/fb-bench.proto: -------------------------------------------------------------------------------- 1 | // trying to represent a typical mix of datatypes: 2 | // 1 array of 3 elements, each element: 1 string, 3 nested objects, 9 scalars 3 | // root element has the array, additional string and an enum 4 | syntax="proto2"; 5 | 6 | option optimize_for = LITE_RUNTIME; 7 | 8 | package benchpb; 9 | option java_package = "protos.benchmarks.flatbuffers.protobuf"; 10 | option java_outer_classname = "Bench"; 11 | option java_multiple_files = true; 12 | 13 | enum Fruit { Apples = 0; Pears = 1; Bananas = 2; } 14 | 15 | message Foo { 16 | required fixed64 id = 1; /* changed from int64 because it's always 10 (!) bytes */ 17 | required int32 count = 2; 18 | required int32 prefix = 3; 19 | required fixed32 length = 4; 20 | } 21 | 22 | message Bar { 23 | required Foo parent = 1; 24 | required sfixed32 time = 2; /* changed from int32 as it's always 2 bytes */ 25 | required float ratio = 3; 26 | required uint32 size = 4; 27 | } 28 | 29 | message FooBar { 30 | optional Bar sibling = 1; 31 | optional string name = 2; 32 | optional double rating = 3; 33 | optional uint32 postfix = 4; 34 | } 35 | 36 | message FooBarContainer { 37 | repeated FooBar list = 1; // 3 copies of the above 38 | optional bool initialized = 2; 39 | optional Fruit fruit = 3; 40 | optional string location = 4; 41 | } 42 | 43 | 44 | -------------------------------------------------------------------------------- /benchmarks/src/test/resources/protos/sbe-car.proto: -------------------------------------------------------------------------------- 1 | syntax="proto2"; 2 | package uk.co.real_logic.protobuf.examples; 3 | 4 | option java_package = "protos.benchmarks.real_logic.protobuf"; 5 | option java_outer_classname = "Examples"; 6 | 7 | message Engine 8 | { 9 | required uint32 capacity = 1; 10 | required uint32 numCylinders = 2; 11 | optional uint32 maxRpm = 3 [default = 9000]; 12 | required string manufacturerCode = 4; 13 | optional string fuel = 5 [default = "Petrol"]; 14 | } 15 | 16 | message FuelFigures 17 | { 18 | required uint32 speed = 1; 19 | required float mpg = 2; 20 | } 21 | 22 | message Acceleration 23 | { 24 | required uint32 mph = 1; 25 | required float seconds = 2; 26 | } 27 | 28 | message PerformanceFigures 29 | { 30 | required uint32 octaneRating = 1; 31 | repeated Acceleration acceleration = 2; 32 | } 33 | 34 | message Car 35 | { 36 | enum Model 37 | { 38 | A = 0; 39 | B = 1; 40 | C = 2; 41 | } 42 | 43 | enum Extras 44 | { 45 | SUN_ROOF = 1; 46 | SPORTS_PACK = 2; 47 | CRUISE_CONTROL = 3; 48 | } 49 | 50 | required uint32 serialNumber = 1; 51 | required uint32 modelYear = 2; 52 | required bool available = 3; 53 | required Model code = 4; 54 | repeated int32 someNumbers = 5 [packed=true]; 55 | required string vehicleCode = 6; 56 | repeated Extras optionalExtras = 7 [packed=true]; 57 | required Engine engine = 8; 58 | repeated FuelFigures fuelFigures = 9; 59 | repeated PerformanceFigures performance = 10; 60 | required string make = 11; 61 | required string model = 12; 62 | } -------------------------------------------------------------------------------- /benchmarks/src/test/resources/protos/sbe-fix-messages.proto: -------------------------------------------------------------------------------- 1 | syntax="proto2"; 2 | package uk.co.real_logic.protobuf.examples; 3 | 4 | option java_package = "protos.benchmarks.real_logic.protobuf"; 5 | option java_outer_classname = "Fix"; 6 | 7 | message Decimal64 8 | { 9 | required int64 mantissa = 1; 10 | optional uint32 exponent = 2 [default = 7]; 11 | } 12 | 13 | message IntQty32 14 | { 15 | required int32 mantissa = 1; 16 | optional uint32 exponent = 2 [default = 0]; 17 | } 18 | 19 | message MdIncGrp 20 | { 21 | enum MdUpdateAction 22 | { 23 | NEW = 0; 24 | CHANGE = 1; 25 | DELETE = 2; 26 | OVERLAY = 5; 27 | } 28 | 29 | enum Side 30 | { 31 | BUY = 1; 32 | SELL = 2; 33 | } 34 | 35 | enum MdEntryType 36 | { 37 | BID = 0; 38 | OFFER = 1; 39 | TRADE = 2; 40 | OPENING_PRICE = 4; 41 | SETTLEMENT_PRICE = 6; 42 | TRADING_SESSION_HIGH_PRICE = 7; 43 | TRADING_SESSION_LOW_PRICE = 8; 44 | } 45 | 46 | required uint64 tradeId = 1; /* better fixed64 */ 47 | required uint64 securityId = 2; /* better fixed64 */ 48 | required Decimal64 mdEntryPx = 3; 49 | required IntQty32 mdEntrySize = 4; 50 | required uint32 numberOfOrders = 5; 51 | required MdUpdateAction mdUpdateAction = 6; 52 | required uint32 repSeq = 7; 53 | required Side aggressorSide = 8; 54 | optional MdEntryType mdEntryType = 9 [default = TRADE]; 55 | } 56 | 57 | message MarketDataIncrementalRefreshTrades 58 | { 59 | enum MatchEventIndicator 60 | { 61 | MID_EVENT = 0; 62 | BEGINNING_EVENT = 1; 63 | END_EVENT = 2; 64 | BEGINNING_AND_END_EVENT = 3; 65 | } 66 | 67 | required uint64 transactTime = 1; /* better fixed64 */ 68 | required uint32 eventTimeDelta = 2; /* better fixed32 */ 69 | required MatchEventIndicator matchEventIndicator = 3; 70 | repeated MdIncGrp mdIncGroup = 4; 71 | } -------------------------------------------------------------------------------- /conformance/README.md: -------------------------------------------------------------------------------- 1 | # Protobuf Conformance Tests 2 | 3 | Google offers a [conformance test suite](https://github.com/protocolbuffers/protobuf/blob/main/conformance/README.md) that contains thousands of automated unit tests to check whether an implementation conforms to the specification. The suite is setup similarly to protoc plugins where a native executable calls the plugin and communicates via `std::in` and `std::out`. Due to [limitations with pipes](https://github.com/protocolbuffers/protobuf/blob/main/conformance/conformance.proto#L38-L55) in Windows and macOS, the tester can currently only be run on Linux. 4 | 5 | QuickBuffers currently passes all required and recommended tests and provides options to produce binary equivalent output to Protobuf-Java. The test implementation is in [ConformanceQuickbuf.java](src/main/java/us/hebi/quickbuf/conformance/ConformanceQuickbuf.java). 6 | 7 | **Compile the QuickBuffers test executable** 8 | 9 | After encountering issues with Java wrapper scripts, we decided to compile the Java code to a native executable. This simultaneously tests GraalVM integration and makes sure that there no accidental runtime reflections. 10 | 11 | ```shell 12 | # 1) build a native image of the generator 13 | mvn clean package --projects "protoc-gen-quickbuf" -am -P"makeNative,useNative" 14 | 15 | # 2) test the native generator and build the conformance executable 16 | mvn clean package --projects quickbuf-runtime,conformance -am -P"makeNative,useNative" 17 | 18 | # (note) native compilation without any prior packaging 19 | mvn native:compile-no-fork -pl conformance -PmakeNative 20 | ``` 21 | 22 | The generated executable is in `${quickbufDir}/conformance/target/ConformanceQuickbuf.exe` 23 | 24 | **Compile the native C++ runner+** 25 | 26 | The `conformance_test_runner` executable needs to be compiled on Linux using the commands below. Depending on the CPU this can take tens of minutes. 27 | 28 | ```shell 29 | git clone https://github.com/protocolbuffers/protobuf.git 30 | cd protobuf 31 | git submodule update --init --recursive 32 | cmake . -Dprotobuf_BUILD_CONFORMANCE=ON && cmake --build . 33 | ``` 34 | 35 | **Execute the conformance_test_runner** 36 | 37 | ```shell 38 | cd ${protobufDir} 39 | cp ${quickbufDir}/conformance/target/ConformanceQuickbuf.exe ${protobufDir}/ 40 | chmod +x ConformanceQuickbuf.exe 41 | ./conformance_test_runner --enforce_recommended ConformanceQuickbuf.exe 42 | ``` 43 | 44 | The output should list 0 failures. Unsupported features such as the text format and some Google internal formats are skipped. 45 | 46 | ```text 47 | user:~/protobuf$ ./conformance_test_runner --enforce_recommended ConformanceQuickbuf.exe 48 | WARNING: All log messages before absl::InitializeLog() is called are written to STDERR 49 | I0000 00:00:1675465291.622071 18024 conformance_test_runner.cc:315] ConformanceQuickbuf.exe 50 | 51 | CONFORMANCE TEST BEGIN ==================================== 52 | 53 | CONFORMANCE SUITE PASSED: 653 successes, 1376 skipped, 0 expected failures, 0 unexpected failures. 54 | 55 | WARNING: All log messages before absl::InitializeLog() is called are written to STDERR 56 | I0000 00:00:1675465292.115120 22087 conformance_test_runner.cc:315] ConformanceQuickbuf.exe 57 | 58 | CONFORMANCE TEST BEGIN ==================================== 59 | 60 | CONFORMANCE SUITE PASSED: 0 successes, 120 skipped, 0 expected failures, 0 unexpected failures. 61 | 62 | ConformanceQuickbuf: received EOF from test runner after 120 tests. Bytes read: 12581, Bytes written: 1216 63 | ConformanceQuickbuf: received EOF from test runner after 2030 tests. Bytes read: 166171, Bytes written: 55441 64 | ``` -------------------------------------------------------------------------------- /conformance/src/main/proto2/unittest_import.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | // Author: kenton@google.com (Kenton Varda) 32 | // Based on original Protocol Buffers design by 33 | // Sanjay Ghemawat, Jeff Dean, and others. 34 | // 35 | // A proto file which is imported by unittest.proto to test importing. 36 | 37 | syntax = "proto2"; 38 | 39 | // We don't put this in a package within proto2 because we need to make sure 40 | // that the generated code doesn't depend on being in the proto2 namespace. 41 | // In test_util.h we do 42 | // "using namespace unittest_import = protobuf_unittest_import". 43 | package protobuf_unittest_import; 44 | 45 | option optimize_for = SPEED; 46 | option cc_enable_arenas = true; 47 | 48 | // Exercise the java_package option. 49 | option java_package = "com.google.protobuf.test"; 50 | 51 | // Do not set a java_outer_classname here to verify that Proto2 works without 52 | // one. 53 | 54 | // Test public import 55 | import public "unittest_import_public.proto"; 56 | 57 | message ImportMessage { 58 | optional int32 d = 1; 59 | } 60 | 61 | enum ImportEnum { 62 | IMPORT_FOO = 7; 63 | IMPORT_BAR = 8; 64 | IMPORT_BAZ = 9; 65 | } 66 | 67 | // To use an enum in a map, it must has the first value as 0. 68 | enum ImportEnumForMap { 69 | UNKNOWN = 0; 70 | FOO = 1; 71 | BAR = 2; 72 | } 73 | -------------------------------------------------------------------------------- /conformance/src/main/proto2/unittest_import_public.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | // Author: liujisi@google.com (Pherl Liu) 32 | 33 | syntax = "proto2"; 34 | 35 | package protobuf_unittest_import; 36 | 37 | option java_package = "com.google.protobuf.test"; 38 | 39 | message PublicImportMessage { 40 | optional int32 e = 1; 41 | } 42 | -------------------------------------------------------------------------------- /conformance/src/main/proto3/google/protobuf/struct.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option cc_enable_arenas = true; 37 | option go_package = "google.golang.org/protobuf/types/known/structpb"; 38 | option java_package = "com.google.protobuf"; 39 | option java_outer_classname = "StructProto"; 40 | option java_multiple_files = true; 41 | option objc_class_prefix = "GPB"; 42 | 43 | // `Struct` represents a structured data value, consisting of fields 44 | // which map to dynamically typed values. In some languages, `Struct` 45 | // might be supported by a native representation. For example, in 46 | // scripting languages like JS a struct is represented as an 47 | // object. The details of that representation are described together 48 | // with the proto support for the language. 49 | // 50 | // The JSON representation for `Struct` is JSON object. 51 | message Struct { 52 | // Unordered map of dynamically typed values. 53 | map fields = 1; 54 | } 55 | 56 | // `Value` represents a dynamically typed value which can be either 57 | // null, a number, a string, a boolean, a recursive struct value, or a 58 | // list of values. A producer of value is expected to set one of these 59 | // variants. Absence of any variant indicates an error. 60 | // 61 | // The JSON representation for `Value` is JSON value. 62 | message Value { 63 | // The kind of value. 64 | oneof kind { 65 | // Represents a null value. 66 | NullValue null_value = 1; 67 | // Represents a double value. 68 | double number_value = 2; 69 | // Represents a string value. 70 | string string_value = 3; 71 | // Represents a boolean value. 72 | bool bool_value = 4; 73 | // Represents a structured value. 74 | Struct struct_value = 5; 75 | // Represents a repeated `Value`. 76 | ListValue list_value = 6; 77 | } 78 | } 79 | 80 | // `NullValue` is a singleton enumeration to represent the null value for the 81 | // `Value` type union. 82 | // 83 | // The JSON representation for `NullValue` is JSON `null`. 84 | enum NullValue { 85 | // Null value. 86 | NULL_VALUE = 0; 87 | } 88 | 89 | // `ListValue` is a wrapper around a repeated field of values. 90 | // 91 | // The JSON representation for `ListValue` is JSON array. 92 | message ListValue { 93 | // Repeated field of dynamically typed values. 94 | repeated Value values = 1; 95 | } 96 | -------------------------------------------------------------------------------- /conformance/src/main/proto3/google/protobuf/wrappers.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | // Wrappers for primitive (non-message) types. These types are useful 32 | // for embedding primitives in the `google.protobuf.Any` type and for places 33 | // where we need to distinguish between the absence of a primitive 34 | // typed field and its default value. 35 | // 36 | // These wrappers have no meaningful use within repeated fields as they lack 37 | // the ability to detect presence on individual elements. 38 | // These wrappers have no meaningful use within a map or a oneof since 39 | // individual entries of a map or fields of a oneof can already detect presence. 40 | 41 | syntax = "proto3"; 42 | 43 | package google.protobuf; 44 | 45 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 46 | option cc_enable_arenas = true; 47 | option go_package = "google.golang.org/protobuf/types/known/wrapperspb"; 48 | option java_package = "com.google.protobuf"; 49 | option java_outer_classname = "WrappersProto"; 50 | option java_multiple_files = true; 51 | option objc_class_prefix = "GPB"; 52 | 53 | // Wrapper message for `double`. 54 | // 55 | // The JSON representation for `DoubleValue` is JSON number. 56 | message DoubleValue { 57 | // The double value. 58 | double value = 1; 59 | } 60 | 61 | // Wrapper message for `float`. 62 | // 63 | // The JSON representation for `FloatValue` is JSON number. 64 | message FloatValue { 65 | // The float value. 66 | float value = 1; 67 | } 68 | 69 | // Wrapper message for `int64`. 70 | // 71 | // The JSON representation for `Int64Value` is JSON string. 72 | message Int64Value { 73 | // The int64 value. 74 | int64 value = 1; 75 | } 76 | 77 | // Wrapper message for `uint64`. 78 | // 79 | // The JSON representation for `UInt64Value` is JSON string. 80 | message UInt64Value { 81 | // The uint64 value. 82 | uint64 value = 1; 83 | } 84 | 85 | // Wrapper message for `int32`. 86 | // 87 | // The JSON representation for `Int32Value` is JSON number. 88 | message Int32Value { 89 | // The int32 value. 90 | int32 value = 1; 91 | } 92 | 93 | // Wrapper message for `uint32`. 94 | // 95 | // The JSON representation for `UInt32Value` is JSON number. 96 | message UInt32Value { 97 | // The uint32 value. 98 | uint32 value = 1; 99 | } 100 | 101 | // Wrapper message for `bool`. 102 | // 103 | // The JSON representation for `BoolValue` is JSON `true` and `false`. 104 | message BoolValue { 105 | // The bool value. 106 | bool value = 1; 107 | } 108 | 109 | // Wrapper message for `string`. 110 | // 111 | // The JSON representation for `StringValue` is JSON string. 112 | message StringValue { 113 | // The string value. 114 | string value = 1; 115 | } 116 | 117 | // Wrapper message for `bytes`. 118 | // 119 | // The JSON representation for `BytesValue` is JSON string. 120 | message BytesValue { 121 | // The bytes value. 122 | bytes value = 1; 123 | } 124 | -------------------------------------------------------------------------------- /conveyor-ci.conf: -------------------------------------------------------------------------------- 1 | include required("conveyor.conf") 2 | 3 | app { 4 | 5 | sign = true 6 | signing-key = ${env.SIGNING_KEY} 7 | 8 | # Credentials needed for the macOS app approval process. 9 | mac { 10 | certificate = "protoc-gen-quickbuf/src/main/deploy/apple.cer" 11 | notarization { 12 | apple-id = ${env.APPLE_APP_ID} 13 | team-id = ${env.APPLE_APP_TEAM_ID} 14 | app-specific-password = ${env.APPLE_APP_PASSWORD} 15 | } 16 | } 17 | 18 | windows { 19 | signing-key { 20 | digi-cert-one { 21 | api-key = ${env.DIGICERT_API_KEY} 22 | auth-certificate = ${env.DIGICERT_AUTH_CERT} 23 | password = ${env.DIGICERT_AUTH_PW} 24 | } 25 | } 26 | signing-key-alias = ${env.DIGICERT_SIGNING_KEY_ALIAS} 27 | } 28 | 29 | linux { 30 | compression-level = high 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /conveyor.conf: -------------------------------------------------------------------------------- 1 | include required("/stdlib/jdk/21/openjdk.conf") 2 | include required("/stdlib/jvm/default-gui.conf") 3 | conveyor.compatibility-level = 11 4 | app.mac.info-plist.LSMinimumSystemVersion = 14.0 // graal executable 5 | 6 | include "#!=protoc.version mvn -q org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=protobuf.version -DforceStdout" 7 | include "#!=project.version mvn -q org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -DforceStdout" 8 | 9 | protoc.name = "protoc-quickbuf" 10 | 11 | // Artifacts need to be built on different operating systems and then be combined before packaging: 12 | // * mvn clean package --projects protoc-gen-request,protoc-gen-quickbuf -am -PmakeNative,useNative 13 | // * mvn clean package --projects quickbuf-runtime,quickbuf-compat -am -PuseNative 14 | 15 | app { 16 | 17 | // App information 18 | vendor = "HEBI Robotics" 19 | display-name = "QuickBuffers Plugin" 20 | description = "Plugin for ProtocolBuffers" 21 | fsname = protoc-gen-quickbuf 22 | long-fsname = protoc-gen-quickbuf 23 | rdns-name = us.hebi.protoc-gen-quickbuf 24 | version = 1.4.1 25 | revision = 0 26 | 27 | // Icons 28 | icons = "protoc-gen-quickbuf/src/main/deploy/icons/icon-rounded-*.png" 29 | windows.icons = "protoc-gen-quickbuf/src/main/deploy/icons/icon-square-*.png" 30 | windows.manifests.msix.background-color = "#2a3b43" 31 | 32 | // Target machines 33 | machines = [ windows.amd64, linux.amd64.glibc, linux.aarch64.glibc, mac.amd64, mac.aarch64 ] 34 | 35 | // Update only on manual request 36 | updates = none 37 | mac.deltas = 0 38 | 39 | inputs += pom.xml 40 | 41 | // Native executables 42 | windows.amd64 { 43 | inputs += protoc-gen-request/target/protoc-gen-request-${project.version}-windows-x86_64.exe -> protoc-gen-request.exe 44 | inputs += protoc-gen-quickbuf/target/protoc-gen-quickbuf-${project.version}-windows-x86_64.exe -> protoc-gen-quickbuf.exe 45 | inputs += protoc-gen-quickbuf/target/protoc/protoc-${protoc.version}-windows-x86_64.exe -> ${protoc.name}.exe 46 | } 47 | mac.amd64 { 48 | bundle-extras += protoc-gen-request/target/protoc-gen-request-${project.version}-osx-x86_64.exe -> MacOS/protoc-gen-request 49 | bundle-extras += protoc-gen-quickbuf/target/protoc-gen-quickbuf-${project.version}-osx-x86_64.exe -> MacOS/protoc-gen-quickbuf 50 | bundle-extras += protoc-gen-quickbuf/target/protoc/protoc-${protoc.version}-osx-x86_64.exe -> MacOS/${protoc.name} 51 | } 52 | mac.aarch64 { 53 | bundle-extras += protoc-gen-request/target/protoc-gen-request-${project.version}-osx-aarch_64.exe -> MacOS/protoc-gen-request 54 | bundle-extras += protoc-gen-quickbuf/target/protoc-gen-quickbuf-${project.version}-osx-aarch_64.exe -> MacOS/protoc-gen-quickbuf 55 | bundle-extras += protoc-gen-quickbuf/target/protoc/protoc-${protoc.version}-osx-aarch_64.exe -> MacOS/${protoc.name} 56 | } 57 | linux.amd64.glibc { 58 | inputs += protoc-gen-request/target/protoc-gen-request-${project.version}-linux-x86_64.exe -> protoc-gen-request 59 | inputs += protoc-gen-quickbuf/target/protoc-gen-quickbuf-${project.version}-linux-x86_64.exe -> protoc-gen-quickbuf 60 | inputs += protoc-gen-quickbuf/target/protoc/protoc-${protoc.version}-linux-x86_64.exe -> ${protoc.name} 61 | } 62 | linux.aarch64.glibc { 63 | inputs += protoc-gen-request/target/protoc-gen-request-${project.version}-linux-aarch_64.exe -> protoc-gen-request 64 | inputs += protoc-gen-quickbuf/target/protoc-gen-quickbuf-${project.version}-linux-aarch_64.exe -> protoc-gen-quickbuf 65 | inputs += protoc-gen-quickbuf/target/protoc/protoc-${protoc.version}-linux-aarch_64.exe -> ${protoc.name} 66 | } 67 | linux.symlinks = [ 68 | ${app.linux.prefix}/bin/protoc-gen-request -> ${app.linux.install-path}/lib/app/protoc-gen-request 69 | ${app.linux.prefix}/bin/protoc-gen-quickbuf -> ${app.linux.install-path}/lib/app/protoc-gen-quickbuf 70 | ${app.linux.prefix}/bin/${protoc.name} -> ${app.linux.install-path}/lib/app/${protoc.name} 71 | ] 72 | 73 | // Release using GitHub Releases 74 | site { 75 | base-url = github.com/HebiRobotics/QuickBuffers/releases/latest/download 76 | consistency-checks = warn 77 | } 78 | vcs-url = github.com/HebiRobotics/QuickBuffers 79 | license = Apache 2 80 | 81 | } -------------------------------------------------------------------------------- /docs/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HebiRobotics/QuickBuffers/b254ce1cf379581ad72d03f095bdf9b9d133cb9c/docs/icon.png -------------------------------------------------------------------------------- /proto3.md: -------------------------------------------------------------------------------- 1 | ## Why Protobuf v2 instead of the newer v3? 2 | 3 | Both proto2 and proto3 use the same wire format, so the messages are binary compatible and only differ in semantics. Unfortunately, there were some major issues with the initial proto3 design, and the protobuf team ended up adding several workarounds that reproduce the proto2 semantics. They have stated that they will keep supporting both versions indefinitely, so we recommend sticking with proto2 whenever possible. Google's internal protobuf communication was still [96% based on proto2](https://dl.acm.org/doi/pdf/10.1145/3466752.3480051) 5 years after the proto3 release. 4 | 5 | For comparison, the main changes were 6 | 7 | * No field presence 8 | 9 | Field presence checks and non-zero defaults were originally removed to simplify implementing protobufs as [plain structs](https://stackoverflow.com/a/33229024/3574093) in languages without accessors. Unfortunately, not having field presence turned out to be a major design flaw (e.g. [#272](https://github.com/protocolbuffers/protobuf/issues/272), [#1606](https://github.com/protocolbuffers/protobuf/issues/1606)). 10 | 11 | It was initially addressed by adding [slow wrapper types](https://github.com/protocolbuffers/protobuf/blob/f75fd051d68136ce366c464cea4f3074158cd141/src/google/protobuf/wrappers.proto) with special semantics, and more recently by adding [synthetic oneof fields](https://github.com/protocolbuffers/protobuf/blob/f75fd051d68136ce366c464cea4f3074158cd141/docs/implementing_proto3_presence.md) that add [explicit presence](https://github.com/protocolbuffers/protobuf/blob/main/docs/field_presence.md) as in proto2. As a result, even though proto3 was supposed to simplify 3rd party implementations, supporting the required workarounds actually makes it more complex than proto2. 12 | 13 | * No non-zero defaults 14 | 15 | Not having useful defaults requires field presence checks like `return hasValue ? getValue() : nan`, which was part of the reason why not having field presence turned out to be such a big issue. 16 | 17 | * No zero values on the wire 18 | 19 | Not sending default values was done to save space on the wire, but it further exacerbates the problem of field presence and lack of defaults. In the original design there is no way to tell whether something reported a valid value of zero or doesn't even know about the protocol field. This made proto3 absolutely unusable for many use cases (e.g. [#359](https://github.com/protocolbuffers/protobuf/issues/359#issuecomment-497746377)). 20 | 21 | If needed, the same benefits could be achieved by adding generator flags or a method that clears the has bits of all fields that are set to their default values. 22 | 23 | * No unknown field retention 24 | 25 | This also turned out to be a major flaw and was reverted to proto2 behavior in [version 3.5](https://developers.google.com/protocol-buffers/docs/proto3#unknowns). 26 | 27 | * Any instead of Extensions 28 | 29 | The [Any](https://github.com/protocolbuffers/protobuf/blob/f75fd051d68136ce366c464cea4f3074158cd141/src/google/protobuf/any.proto) type is essentially a binary blob with a type identifier. It seems simpler to implement and use than extensions, but we don't have a use case for either one and therefore can't compare. 30 | 31 | * No required fields 32 | 33 | This is a just formalization of what has already been recommended practice in proto2. -------------------------------------------------------------------------------- /protoc-gen-quickbuf/Readme.md: -------------------------------------------------------------------------------- 1 | # Deploying binary plugin artifacts 2 | 3 | In order to support the `pluginArtifact` parameter (`"us.hebi.quickbuf:protoc-gen-quickbuf:${version}"`) of the [protoc-jar-maven-plugin](https://github.com/os72/protoc-jar-maven-plugin), we need to upload native executables to Maven Central and match the naming convention of [protoc](https://repo1.maven.org/maven2/com/google/protobuf/protoc/3.20.0/) and the [protoc-gen-grpc-java](https://repo1.maven.org/maven2/io/grpc/protoc-gen-grpc-java/1.9.1/) plugin. 4 | 5 | The Java bytecode can be compiled to a standalone native executable using [GraalVM](https://www.graalvm.org/). This also gets rid of requiring an installed Java runtime and significantly speeds up execution due to ahead of time compilation and faster startup time. The caveat is that the images need to be compiled on each supported platform, which currently requires a self-hosted runner for linux-aarch64. 6 | 7 | Releasing to Maven Central as well as Conveyor packaging happen automatically in a Github action. It can be triggered manually in the action interface. 8 | 9 | ### Release procedure 10 | 11 | * Update version 12 | * `mvn versions:set -DprocessAllModules -DnewVersion=${NEW_VERSION}` 13 | * update `app.version` in `../conveyor.conf` 14 | * update version in `../Readme.md` 15 | * Create a tag 16 | * [Trigger Github Action](https://github.com/HebiRobotics/QuickBuffers/actions) 17 | * Upload `conveyor-site` contents to a Github release 18 | * Copy the `icon.png` and `download.html` site to `../docs/` 19 | 20 | ### Local setup for creating native executables 21 | 22 | You can setup a suitable GraalVM environment locally by following the steps below: 23 | 24 | * download [GRAALVM]([GraalVM](https://www.graalvm.org/22.3/docs/getting-started/macos/)) and a GRAALVM_HOME environment variable 25 | * build native images `mvn clean package --projects protoc-gen-quickbuf -am -P"makeNative,useNative" 26 | * test the native images `mvn clean package --projects quickbuf-compat -am -PuseNative 27 | -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/deploy/apple.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HebiRobotics/QuickBuffers/b254ce1cf379581ad72d03f095bdf9b9d133cb9c/protoc-gen-quickbuf/src/main/deploy/apple.cer -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/deploy/icons/icon-rounded-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HebiRobotics/QuickBuffers/b254ce1cf379581ad72d03f095bdf9b9d133cb9c/protoc-gen-quickbuf/src/main/deploy/icons/icon-rounded-1024.png -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/deploy/icons/icon-rounded-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HebiRobotics/QuickBuffers/b254ce1cf379581ad72d03f095bdf9b9d133cb9c/protoc-gen-quickbuf/src/main/deploy/icons/icon-rounded-128.png -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/deploy/icons/icon-rounded-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HebiRobotics/QuickBuffers/b254ce1cf379581ad72d03f095bdf9b9d133cb9c/protoc-gen-quickbuf/src/main/deploy/icons/icon-rounded-256.png -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/deploy/icons/icon-rounded-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HebiRobotics/QuickBuffers/b254ce1cf379581ad72d03f095bdf9b9d133cb9c/protoc-gen-quickbuf/src/main/deploy/icons/icon-rounded-512.png -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/deploy/icons/icon-rounded-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HebiRobotics/QuickBuffers/b254ce1cf379581ad72d03f095bdf9b9d133cb9c/protoc-gen-quickbuf/src/main/deploy/icons/icon-rounded-64.png -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/deploy/icons/icon-square-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HebiRobotics/QuickBuffers/b254ce1cf379581ad72d03f095bdf9b9d133cb9c/protoc-gen-quickbuf/src/main/deploy/icons/icon-square-1024.png -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/deploy/icons/icon-square-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HebiRobotics/QuickBuffers/b254ce1cf379581ad72d03f095bdf9b9d133cb9c/protoc-gen-quickbuf/src/main/deploy/icons/icon-square-128.png -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/deploy/icons/icon-square-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HebiRobotics/QuickBuffers/b254ce1cf379581ad72d03f095bdf9b9d133cb9c/protoc-gen-quickbuf/src/main/deploy/icons/icon-square-16.png -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/deploy/icons/icon-square-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HebiRobotics/QuickBuffers/b254ce1cf379581ad72d03f095bdf9b9d133cb9c/protoc-gen-quickbuf/src/main/deploy/icons/icon-square-256.png -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/deploy/icons/icon-square-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HebiRobotics/QuickBuffers/b254ce1cf379581ad72d03f095bdf9b9d133cb9c/protoc-gen-quickbuf/src/main/deploy/icons/icon-square-32.png -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/deploy/icons/icon-square-44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HebiRobotics/QuickBuffers/b254ce1cf379581ad72d03f095bdf9b9d133cb9c/protoc-gen-quickbuf/src/main/deploy/icons/icon-square-44.png -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/deploy/icons/icon-square-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HebiRobotics/QuickBuffers/b254ce1cf379581ad72d03f095bdf9b9d133cb9c/protoc-gen-quickbuf/src/main/deploy/icons/icon-square-512.png -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/deploy/icons/icon-square-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HebiRobotics/QuickBuffers/b254ce1cf379581ad72d03f095bdf9b9d133cb9c/protoc-gen-quickbuf/src/main/deploy/icons/icon-square-64.png -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/java/us/hebi/quickbuf/generator/GeneratorException.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-generator 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf.generator; 22 | 23 | /** 24 | * @author Florian Enner 25 | * @since 07 Aug 2019 26 | */ 27 | public class GeneratorException extends RuntimeException { 28 | public GeneratorException(String s) { 29 | super(s); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/java/us/hebi/quickbuf/generator/Javadoc.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-generator 4 | * %% 5 | * Copyright (C) 2019 - 2023 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package us.hebi.quickbuf.generator; 21 | 22 | import com.google.protobuf.DescriptorProtos; 23 | import com.google.protobuf.DescriptorProtos.SourceCodeInfo; 24 | import com.squareup.javapoet.CodeBlock; 25 | 26 | import java.util.HashMap; 27 | import java.util.Locale; 28 | 29 | /** 30 | * Utilities for creating Javadoc comments on methods and fields. 31 | * For the most part similar to Protobuf-Java. 32 | * 33 | * @author Florian Enner 34 | * @since 16 Jun 2023 35 | */ 36 | class Javadoc { 37 | 38 | public static String inherit() { 39 | // Note: JavaDoc automatically adds the superclass doc, 40 | // so we don't need to manually call it out. 41 | // return "{@inheritDoc}"; 42 | return ""; 43 | } 44 | 45 | public static CodeBlock forMessage(RequestInfo.MessageInfo info) { 46 | return forType("type", info); 47 | } 48 | 49 | public static CodeBlock.Builder forMessageField(RequestInfo.FieldInfo info) { 50 | // Fields get called a lot, so we cache the expensive parts 51 | CodeBlock block = cachedFields.get(info.getDescriptor()); 52 | if (block == null) { 53 | block = withComments(info.getSourceLocation()) 54 | .add("$L", getFieldDefinitionLine(info.getDescriptor())) 55 | .build(); 56 | cachedFields.put(info.getDescriptor(), block); 57 | } 58 | return block.toBuilder(); 59 | } 60 | 61 | private static final HashMap cachedFields = new HashMap<>(); 62 | 63 | public static CodeBlock forEnum(RequestInfo.EnumInfo info) { 64 | return forType("enum", info); 65 | } 66 | 67 | public static CodeBlock forEnumValue(RequestInfo.EnumValueInfo info) { 68 | return withComments(info.getSourceLocation()) 69 | .add("$L = $L;", info.getName(), info.getNumber()) 70 | .build(); 71 | } 72 | 73 | public static CodeBlock.Builder withComments(SourceCodeInfo.Location location) { 74 | // Protobuf-java seems to prefer leading comments and only use trailing as a fallback. 75 | // They also remove the first space as well as empty lines, but that' 76 | CodeBlock.Builder builder = CodeBlock.builder(); 77 | String format = "

\n$L
\n\n"; 78 | if (location.hasLeadingComments()) { 79 | builder.add(format, escapeCommentClose(location.getLeadingComments())); 80 | } else if (location.hasTrailingComments()) { 81 | builder.add(format, escapeCommentClose(location.getTrailingComments())); 82 | } 83 | return builder; 84 | } 85 | 86 | private static CodeBlock forType(String name, RequestInfo.TypeInfo info) { 87 | return withComments(info.getSourceLocation()) 88 | .add("Protobuf $L {@code $T}", name, info.getTypeName()) 89 | .build(); 90 | } 91 | 92 | private static String getFieldDefinitionLine(DescriptorProtos.FieldDescriptorProto descriptor) { 93 | // optional int32 my_field = 2 [default = 1]; 94 | final String label = descriptor.getLabel().toString() 95 | .substring("LABEL_".length()) 96 | .toLowerCase(Locale.US); 97 | String type = descriptor.getTypeName(); 98 | if (type.isEmpty()) { 99 | type = descriptor.getType().toString() 100 | .substring("TYPE_".length()) 101 | .toLowerCase(Locale.US); 102 | } 103 | String definition = String.format("%s %s %s = %d", label, type, descriptor.getName(), descriptor.getNumber()); 104 | String options = ""; 105 | if (descriptor.hasDefaultValue()) { 106 | String defaultValue = escapeCommentClose(descriptor.getDefaultValue()); 107 | options = " [default = " + defaultValue + "]"; 108 | } else if (descriptor.getOptions().hasPacked()) { 109 | options = " [packed = " + descriptor.getOptions().getPacked() + "]"; 110 | } 111 | 112 | String line = definition + options + ";"; 113 | return !descriptor.hasExtendee() ? line : "extend {\n " + line + "\n}"; 114 | } 115 | 116 | private static String escapeCommentClose(String string) { 117 | if (string.contains("*/")) { 118 | string = string.replaceAll("\\*/", "*\\\\/"); 119 | } 120 | return string; 121 | } 122 | 123 | private Javadoc() { 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/java/us/hebi/quickbuf/generator/OneOfGenerator.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-generator 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf.generator; 22 | 23 | import com.squareup.javapoet.MethodSpec; 24 | import com.squareup.javapoet.TypeSpec; 25 | import us.hebi.quickbuf.generator.RequestInfo.FieldInfo; 26 | import us.hebi.quickbuf.generator.RequestInfo.OneOfInfo; 27 | 28 | import javax.lang.model.element.Modifier; 29 | import java.util.List; 30 | import java.util.stream.Collectors; 31 | 32 | /** 33 | * @author Florian Enner 34 | * @since 19 Nov 2019 35 | */ 36 | public class OneOfGenerator { 37 | 38 | public OneOfGenerator(OneOfInfo info) { 39 | this.info = info; 40 | this.fields = info.getFields(); 41 | } 42 | 43 | protected void generateMemberMethods(TypeSpec.Builder type) { 44 | // Checks if any has state is true 45 | MethodSpec.Builder has = MethodSpec.methodBuilder(info.getHazzerName()) 46 | .addModifiers(Modifier.PUBLIC) 47 | .returns(boolean.class) 48 | .addStatement("return $L", BitField.hasAnyBit(fields)); 49 | 50 | // Method that clears all fields 51 | MethodSpec.Builder clear = MethodSpec.methodBuilder(info.getClearName()) 52 | .addModifiers(Modifier.PUBLIC) 53 | .returns(info.getParentType()) 54 | .beginControlFlow("if ($L())", info.getHazzerName()); 55 | 56 | for (FieldInfo field : fields) { 57 | clear.addStatement("$N()", field.getClearName()); 58 | } 59 | clear.endControlFlow(); 60 | clear.addStatement("return this"); 61 | 62 | type.addMethod(has.build()); 63 | type.addMethod(clear.build()); 64 | 65 | // Add a utility method that clears all but one fields 66 | if (fields.size() > 1) { 67 | for (FieldInfo field : fields) { 68 | 69 | List otherFields = fields.stream() 70 | .filter(info -> info != field) 71 | .collect(Collectors.toList()); 72 | 73 | MethodSpec.Builder clearOthers = MethodSpec.methodBuilder(field.getClearOtherOneOfName()) 74 | .addModifiers(Modifier.PRIVATE) 75 | .beginControlFlow("if ($L)", BitField.hasAnyBit(otherFields)); 76 | 77 | for (FieldInfo otherField : otherFields) { 78 | clearOthers.addStatement("$N()", otherField.getClearName()); 79 | } 80 | clearOthers.endControlFlow(); 81 | type.addMethod(clearOthers.build()); 82 | 83 | } 84 | } 85 | 86 | } 87 | 88 | final OneOfInfo info; 89 | final List fields; 90 | 91 | } 92 | -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/java/us/hebi/quickbuf/generator/RuntimeClasses.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-generator 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf.generator; 22 | 23 | import com.google.protobuf.DescriptorProtos.FieldDescriptorProto; 24 | import com.squareup.javapoet.ClassName; 25 | 26 | /** 27 | * TypeNames of all API classes that can be referenced from generated code 28 | * 29 | * @author Florian Enner 30 | * @since 07 Aug 2019 31 | */ 32 | class RuntimeClasses { 33 | 34 | private static final String API_PACKAGE = "us.hebi.quickbuf"; 35 | 36 | static final ClassName ProtoSource = ClassName.get(API_PACKAGE, "ProtoSource"); 37 | static final ClassName ProtoSink = ClassName.get(API_PACKAGE, "ProtoSink"); 38 | static final ClassName ProtoUtil = ClassName.get(API_PACKAGE, "ProtoUtil"); 39 | static final ClassName AbstractMessage = ClassName.get(API_PACKAGE, "ProtoMessage"); 40 | static final ClassName MessageFactory = ClassName.get(API_PACKAGE, "MessageFactory"); 41 | static final ClassName StringType = ClassName.get(API_PACKAGE,"Utf8String"); 42 | static final ClassName Utf8Decoder = ClassName.get(API_PACKAGE,"Utf8Decoder"); 43 | static final ClassName BytesType = ClassName.get(API_PACKAGE, "RepeatedByte"); 44 | static final ClassName InvalidProtocolBufferException = ClassName.get(API_PACKAGE, "InvalidProtocolBufferException"); 45 | static final ClassName UninitializedMessageException = ClassName.get(API_PACKAGE, "UninitializedMessageException"); 46 | static final ClassName JsonSink = ClassName.get(API_PACKAGE, "JsonSink"); 47 | static final ClassName JsonSource = ClassName.get(API_PACKAGE, "JsonSource"); 48 | static final ClassName FieldName = ClassName.get(API_PACKAGE, "FieldName"); 49 | static final ClassName ProtoEnum = ClassName.get(API_PACKAGE, "ProtoEnum"); 50 | static final ClassName EnumConverter = ProtoEnum.nestedClass("EnumConverter"); 51 | static final ClassName FileDescriptor = ClassName.get(API_PACKAGE, "Descriptors") 52 | .nestedClass("FileDescriptor"); 53 | static final ClassName MessageDescriptor = ClassName.get(API_PACKAGE, "Descriptors") 54 | .nestedClass("Descriptor"); 55 | 56 | static final String unknownBytesField = "unknownBytes"; 57 | static final String unknownBytesFieldName = "unknownBytesFieldName"; 58 | static final int unknownBytesFieldHash = "[quickbuf.unknown_bytes]".hashCode(); 59 | 60 | private static final ClassName RepeatedDouble = ClassName.get(API_PACKAGE, "RepeatedDouble"); 61 | private static final ClassName RepeatedFloat = ClassName.get(API_PACKAGE, "RepeatedFloat"); 62 | private static final ClassName RepeatedLong = ClassName.get(API_PACKAGE, "RepeatedLong"); 63 | private static final ClassName RepeatedInt = ClassName.get(API_PACKAGE, "RepeatedInt"); 64 | private static final ClassName RepeatedBoolean = ClassName.get(API_PACKAGE, "RepeatedBoolean"); 65 | private static final ClassName RepeatedString = ClassName.get(API_PACKAGE, "RepeatedString"); 66 | private static final ClassName RepeatedBytes = ClassName.get(API_PACKAGE, "RepeatedBytes"); 67 | static final ClassName RepeatedMessage = ClassName.get(API_PACKAGE, "RepeatedMessage"); 68 | static final ClassName RepeatedEnum = ClassName.get(API_PACKAGE, "RepeatedEnum"); 69 | 70 | static ClassName getRepeatedStoreType(FieldDescriptorProto.Type type) { 71 | switch (type) { 72 | 73 | case TYPE_DOUBLE: 74 | return RepeatedDouble; 75 | 76 | case TYPE_FLOAT: 77 | return RepeatedFloat; 78 | 79 | case TYPE_SFIXED64: 80 | case TYPE_FIXED64: 81 | case TYPE_SINT64: 82 | case TYPE_INT64: 83 | case TYPE_UINT64: 84 | return RepeatedLong; 85 | 86 | case TYPE_SFIXED32: 87 | case TYPE_FIXED32: 88 | case TYPE_SINT32: 89 | case TYPE_INT32: 90 | case TYPE_UINT32: 91 | return RepeatedInt; 92 | 93 | case TYPE_BOOL: 94 | return RepeatedBoolean; 95 | 96 | case TYPE_ENUM: 97 | return RepeatedEnum; 98 | 99 | case TYPE_STRING: 100 | return RepeatedString; 101 | 102 | case TYPE_GROUP: 103 | case TYPE_MESSAGE: 104 | return RepeatedMessage; 105 | 106 | case TYPE_BYTES: 107 | return RepeatedBytes; 108 | 109 | default: 110 | throw new IllegalStateException("Unexpected value: " + type); 111 | } 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/resources/META-INF/native-image/jni-config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name":"java.lang.Boolean", 4 | "methods":[{"name":"getBoolean","parameterTypes":["java.lang.String"] }] 5 | }, 6 | { 7 | "name":"java.lang.InternalError", 8 | "methods":[{"name":"","parameterTypes":["java.lang.String"] }] 9 | } 10 | ] 11 | -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/resources/META-INF/native-image/reflect-config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name":"com.google.protobuf.ExtensionRegistry", 4 | "methods":[{"name":"getEmptyRegistry","parameterTypes":[] }] 5 | }, 6 | { 7 | "name":"java.lang.Cloneable", 8 | "allDeclaredClasses":true 9 | }, 10 | { 11 | "name":"java.lang.Object", 12 | "allDeclaredFields":true, 13 | "queryAllDeclaredMethods":true 14 | }, 15 | { 16 | "name":"java.nio.Buffer", 17 | "fields":[{"name":"address"}] 18 | }, 19 | { 20 | "name":"sun.misc.Unsafe", 21 | "allDeclaredFields":true, 22 | "queriedMethods":[ 23 | {"name":"arrayBaseOffset","parameterTypes":["java.lang.Class"] }, 24 | {"name":"arrayIndexScale","parameterTypes":["java.lang.Class"] }, 25 | {"name":"copyMemory","parameterTypes":["long","long","long"] }, 26 | {"name":"copyMemory","parameterTypes":["java.lang.Object","long","java.lang.Object","long","long"] }, 27 | {"name":"getBoolean","parameterTypes":["java.lang.Object","long"] }, 28 | {"name":"getByte","parameterTypes":["long"] }, 29 | {"name":"getByte","parameterTypes":["java.lang.Object","long"] }, 30 | {"name":"getDouble","parameterTypes":["java.lang.Object","long"] }, 31 | {"name":"getFloat","parameterTypes":["java.lang.Object","long"] }, 32 | {"name":"getInt","parameterTypes":["long"] }, 33 | {"name":"getInt","parameterTypes":["java.lang.Object","long"] }, 34 | {"name":"getLong","parameterTypes":["long"] }, 35 | {"name":"getLong","parameterTypes":["java.lang.Object","long"] }, 36 | {"name":"getObject","parameterTypes":["java.lang.Object","long"] }, 37 | {"name":"objectFieldOffset","parameterTypes":["java.lang.reflect.Field"] }, 38 | {"name":"putBoolean","parameterTypes":["java.lang.Object","long","boolean"] }, 39 | {"name":"putByte","parameterTypes":["long","byte"] }, 40 | {"name":"putByte","parameterTypes":["java.lang.Object","long","byte"] }, 41 | {"name":"putDouble","parameterTypes":["java.lang.Object","long","double"] }, 42 | {"name":"putFloat","parameterTypes":["java.lang.Object","long","float"] }, 43 | {"name":"putInt","parameterTypes":["long","int"] }, 44 | {"name":"putInt","parameterTypes":["java.lang.Object","long","int"] }, 45 | {"name":"putLong","parameterTypes":["long","long"] }, 46 | {"name":"putLong","parameterTypes":["java.lang.Object","long","long"] }, 47 | {"name":"putObject","parameterTypes":["java.lang.Object","long","java.lang.Object"] } 48 | ] 49 | } 50 | ] 51 | -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/scripts/unix.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | java -jar "${BASH_SOURCE%/*}/{jarfile}.jar" 3 | -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/main/scripts/windows.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | SET mypath=%~dp0 3 | java -jar "%mypath:~0,-1%\{jarfile}.jar" -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/test/java/us/hebi/quickbuf/generator/SourceLocationTests.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-generator 4 | * %% 5 | * Copyright (C) 2019 - 2023 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package us.hebi.quickbuf.generator; 21 | 22 | import com.google.protobuf.DescriptorProtos; 23 | import com.google.protobuf.compiler.PluginProtos; 24 | import org.junit.Test; 25 | 26 | import java.io.FileNotFoundException; 27 | import java.util.Map; 28 | import java.util.Objects; 29 | 30 | import static org.junit.Assert.*; 31 | 32 | /** 33 | * @author Florian Enner 34 | * @since 16 Jun 2023 35 | */ 36 | public class SourceLocationTests { 37 | 38 | @Test 39 | public void testComments() { 40 | PluginProtos.CodeGeneratorRequest request = TestRequestLoader.getAllTypesEagerRequest(); 41 | DescriptorProtos.FileDescriptorProto descriptor = request.getProtoFileList().stream() 42 | .filter(f -> f.getName().equals("unittest_all_types.proto")) 43 | .findFirst().orElseThrow(() -> new IllegalStateException("file not found")); 44 | 45 | Map map = SourceLocations.createElementMap(descriptor); 46 | // file.getSourceMap().forEach((key, value) -> System.out.println(key)); 47 | 48 | // Message 49 | assertEquals(" comment on message header line 1\n comment on message header line 2\n", map.get(".quickbuf_unittest.TestAllTypes").getLeadingComments()); 50 | assertEquals(" comment post message\n", map.get(".quickbuf_unittest.TestAllTypes").getTrailingComments()); 51 | 52 | // Nested message 53 | assertEquals(" comment on nested message\n", map.get(".quickbuf_unittest.TestAllTypes.NestedMessage").getLeadingComments()); 54 | assertEquals("", map.get(".quickbuf_unittest.TestAllTypes.NestedMessage").getTrailingComments()); 55 | 56 | // Nested group 57 | assertEquals("", map.get(".quickbuf_unittest.TestAllTypes.OptionalGroup").getLeadingComments()); 58 | assertEquals(" comment post group\n", map.get(".quickbuf_unittest.TestAllTypes.OptionalGroup").getTrailingComments()); 59 | 60 | // Message Field 61 | assertEquals(" comment before message field\n", map.get(".quickbuf_unittest.TestAllTypes.NestedMessage.bb").getLeadingComments()); 62 | assertEquals(" comment post message field\n", map.get(".quickbuf_unittest.TestAllTypes.NestedMessage.bb").getTrailingComments()); 63 | 64 | // Nested Enum 65 | assertEquals(" comment on nested enum line 1\n\n comment on nested enum line 3\n", map.get(".quickbuf_unittest.TestAllTypes.NestedEnum").getLeadingComments()); 66 | assertEquals(" comment post enum\n", map.get(".quickbuf_unittest.TestAllTypes.NestedEnum").getTrailingComments()); 67 | 68 | // Enum Field 69 | assertEquals(" comment before enum field\n", map.get(".quickbuf_unittest.TestAllTypes.NestedEnum.FOO").getLeadingComments()); 70 | assertEquals("", map.get(".quickbuf_unittest.TestAllTypes.NestedEnum.FOO").getTrailingComments()); 71 | assertEquals("", map.get(".quickbuf_unittest.TestAllTypes.NestedEnum.BAR").getLeadingComments()); 72 | assertEquals(" comment post enum field\n", map.get(".quickbuf_unittest.TestAllTypes.NestedEnum.BAR").getTrailingComments()); 73 | assertEquals(" comment before enum field 2\n", map.get(".quickbuf_unittest.TestAllTypes.NestedEnum.BAZ").getLeadingComments()); 74 | assertEquals(" comment post enum field 2\n", map.get(".quickbuf_unittest.TestAllTypes.NestedEnum.BAZ").getTrailingComments()); 75 | 76 | } 77 | 78 | 79 | } 80 | -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/test/java/us/hebi/quickbuf/generator/TestRequestLoader.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-generator 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf.generator; 22 | 23 | import com.google.protobuf.compiler.PluginProtos.CodeGeneratorRequest; 24 | import org.junit.Test; 25 | 26 | import java.io.IOException; 27 | import java.io.InputStream; 28 | 29 | import static us.hebi.quickbuf.generator.Preconditions.*; 30 | 31 | /** 32 | * @author Florian Enner 33 | * @since 06 Aug 2019 34 | */ 35 | public class TestRequestLoader { 36 | 37 | @Test 38 | public void testAllAvailable() { 39 | getRequiredRequest(); 40 | getImportRequest(); 41 | getAllTypesEagerRequest(); 42 | getAllTypesLazyRequest(); 43 | getRepeatedPackablesRequest(); 44 | getUnsupportedMapRequest(); 45 | getUnsupportedExtensionRequest(); 46 | getUnsupportedRecursionRequest(); 47 | getUnsupportedProto3Request(); 48 | } 49 | 50 | public static CodeGeneratorRequest getRequiredRequest() { 51 | return getRequest("required"); 52 | } 53 | 54 | public static CodeGeneratorRequest getImportRequest() { 55 | return getRequest("import"); 56 | } 57 | 58 | public static CodeGeneratorRequest getAllTypesEagerRequest() { 59 | return getRequest("allTypes_eager"); 60 | } 61 | 62 | public static CodeGeneratorRequest getAllTypesLazyRequest() { 63 | return getRequest("allTypes_lazy"); 64 | } 65 | 66 | public static CodeGeneratorRequest getRepeatedPackablesRequest() { 67 | return getRequest("repeatedPackables"); 68 | } 69 | 70 | public static CodeGeneratorRequest getUnsupportedMapRequest() { 71 | return getRequest("unsupported_map"); 72 | } 73 | 74 | public static CodeGeneratorRequest getUnsupportedExtensionRequest() { 75 | return getRequest("unsupported_extension"); 76 | } 77 | 78 | public static CodeGeneratorRequest getUnsupportedRecursionRequest() { 79 | return getRequest("unsupported_recursion"); 80 | } 81 | 82 | public static CodeGeneratorRequest getLazyRecursionRequest() { 83 | return getRequest("lazy_recursion"); 84 | } 85 | 86 | public static CodeGeneratorRequest getUnsupportedProto3Request() { 87 | return getRequest("unsupported_proto3"); 88 | } 89 | 90 | private static CodeGeneratorRequest getRequest(String name) { 91 | try { 92 | InputStream is = TestRequestLoader.class.getResourceAsStream(name + ".request"); 93 | return CodeGeneratorRequest.parseFrom(checkNotNull(is)); 94 | } catch (IOException ioe) { 95 | throw new RuntimeException(ioe); 96 | } 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/test/resources/protos/unsupported/extension.proto: -------------------------------------------------------------------------------- 1 | // Adapted from Google's javanano unit tests 2 | 3 | syntax = "proto2"; 4 | package quickbuf_unsupported; 5 | 6 | option java_package = "protos.test.protobuf.unsupported"; 7 | option java_outer_classname = "Extension"; 8 | option java_multiple_files = false; 9 | 10 | message MainMessage { 11 | optional int32 value = 1; 12 | extensions 100 to 199; 13 | } 14 | 15 | message ExtendingMessage { 16 | optional int32 value = 1; 17 | } 18 | 19 | extend quickbuf_unsupported.MainMessage { 20 | optional int32 extended_value = 100; 21 | optional ExtendingMessage extended_message = 101; 22 | } -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/test/resources/protos/unsupported/map.proto: -------------------------------------------------------------------------------- 1 | // Adapted from Google's javanano unit tests 2 | 3 | syntax = "proto2"; 4 | package quickbuf_unsupported; 5 | 6 | option java_package = "protos.test.protobuf.unsupported"; 7 | option java_outer_classname = "Map"; 8 | option java_multiple_files = false; 9 | 10 | message TestMap { 11 | 12 | map string_to_message_map = 1; 13 | map int_to_double_map = 2; 14 | 15 | } 16 | 17 | message NestedMessage { 18 | optional int32 value = 1; 19 | } -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/test/resources/protos/unsupported/proto3.proto: -------------------------------------------------------------------------------- 1 | // Adapted from Google's javanano unit tests 2 | 3 | syntax = "proto3"; 4 | package quickbuf_unsupported; 5 | 6 | option java_package = "protos.test.protobuf.unsupported"; 7 | option java_outer_classname = "Proto3"; 8 | option java_multiple_files = false; 9 | 10 | message RootMessage3 { 11 | int32 optional3_field = 1; 12 | optional int32 optional2_field = 2; 13 | repeated int32 repeated_field = 3; 14 | repeated NestedMessage3 repeated_message = 4; 15 | 16 | oneof oneof_value_field { 17 | float oneof_float_value = 5; 18 | double oneof_double_value = 6; 19 | } 20 | 21 | } 22 | 23 | message NestedMessage3 { 24 | optional float value = 1; 25 | } -------------------------------------------------------------------------------- /protoc-gen-quickbuf/src/test/resources/protos/unsupported/recursion.proto: -------------------------------------------------------------------------------- 1 | // Adapted from Google's javanano unit tests 2 | 3 | syntax = "proto2"; 4 | package quickbuf_unsupported; 5 | 6 | option java_package = "protos.test.protobuf.unsupported"; 7 | option java_outer_classname = "Recursion"; 8 | option java_multiple_files = false; 9 | 10 | message MainMessage { 11 | optional NestedMessage nested = 1; 12 | } 13 | 14 | message NestedMessage { 15 | optional InnerNestedMessage inner = 1; 16 | } 17 | 18 | message InnerNestedMessage { 19 | required MainMessage main = 1; 20 | } -------------------------------------------------------------------------------- /protoc-gen-request/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | quickbuf-parent 7 | us.hebi.quickbuf 8 | 1.4.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | protoc-gen-request 13 | 14 | 15 | ${project.artifactId} 16 | us.hebi.quickbuf.parser 17 | us.hebi.quickbuf.parser.SaveRequestPlugin 18 | 19 | 20 | 21 | 22 | com.google.protobuf 23 | protobuf-java 24 | 25 | 26 | junit 27 | junit 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | org.apache.maven.plugins 37 | maven-shade-plugin 38 | 39 | 40 | 41 | 42 | org.apache.maven.plugins 43 | maven-antrun-plugin 44 | 45 | 46 | 47 | 48 | org.codehaus.mojo 49 | build-helper-maven-plugin 50 | 51 | 52 | attach-artifacts 53 | package 54 | 55 | attach-artifact 56 | 57 | 58 | 59 | 60 | ${project.build.directory}/${finalName}-linux-x86_64.exe 61 | linux-x86_64 62 | exe 63 | 64 | 65 | ${project.build.directory}/${finalName}-linux-aarch_64.exe 66 | linux-aarch_64 67 | exe 68 | 69 | 70 | ${project.build.directory}/${finalName}-osx-x86_64.exe 71 | osx-x86_64 72 | exe 73 | 74 | 75 | ${project.build.directory}/${finalName}-osx-aarch_64.exe 76 | osx-aarch_64 77 | exe 78 | 79 | 80 | ${project.build.directory}/${finalName}-windows-x86_64.exe 81 | windows-x86_64 82 | exe 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | makeNative 97 | 98 | 99 | 100 | org.graalvm.buildtools 101 | native-maven-plugin 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /protoc-gen-request/src/main/java/us/hebi/quickbuf/parser/ParserUtil.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-parser 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf.parser; 22 | 23 | import com.google.protobuf.compiler.PluginProtos.CodeGeneratorRequest; 24 | import com.google.protobuf.compiler.PluginProtos.CodeGeneratorResponse; 25 | 26 | import java.io.ByteArrayOutputStream; 27 | import java.io.PrintStream; 28 | import java.io.UnsupportedEncodingException; 29 | import java.nio.charset.StandardCharsets; 30 | import java.util.Collections; 31 | import java.util.HashMap; 32 | import java.util.Map; 33 | 34 | /** 35 | * @author Florian Enner 36 | * @since 06 Aug 2019 37 | */ 38 | public class ParserUtil { 39 | 40 | public static Map getGeneratorParameters(CodeGeneratorRequest request) { 41 | if (!request.hasParameter()) 42 | return Collections.emptyMap(); 43 | return parseGeneratorParameters(request.getParameter()); 44 | } 45 | 46 | /** 47 | * Returns a map of input arguments added before the proto path, e.g., 48 | *

49 | * PROTOC INPUT: "--GEN_out=option1=value1,option2=value2,optionFlag3:./my-output-directory" 50 | * PARAMETER STRING: "option1=value1,option2=value2,optionFlag3" 51 | * 52 | * @param parameter parameter string input into protoc 53 | * @return map 54 | */ 55 | public static Map parseGeneratorParameters(String parameter) { 56 | if (parameter == null || parameter.isEmpty()) 57 | return Collections.emptyMap(); 58 | 59 | HashMap map = new HashMap<>(); 60 | String[] parts = parameter.split(","); 61 | for (String part : parts) { 62 | 63 | int equalsIndex = part.indexOf("="); 64 | if (equalsIndex == -1) { 65 | map.put(part, ""); 66 | } else { 67 | String key = part.substring(0, equalsIndex); 68 | String value = part.substring(equalsIndex + 1); 69 | map.put(key, value); 70 | } 71 | 72 | } 73 | return map; 74 | } 75 | 76 | public static CodeGeneratorResponse asErrorWithStackTrace(Exception e) { 77 | // Print error with StackTrace 78 | final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 79 | try (PrintStream ps = new PrintStream(baos, true, "UTF-8")) { 80 | e.printStackTrace(ps); 81 | } catch (UnsupportedEncodingException ex) { 82 | throw new AssertionError("UTF-8 encoding not supported"); 83 | } 84 | String errorWithStackTrace = new String(baos.toByteArray(), StandardCharsets.UTF_8); 85 | return CodeGeneratorResponse.newBuilder().setError(errorWithStackTrace).build(); 86 | } 87 | 88 | public static CodeGeneratorResponse asError(String errorMessage) { 89 | return CodeGeneratorResponse.newBuilder().setError(errorMessage).build(); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /protoc-gen-request/src/main/java/us/hebi/quickbuf/parser/SaveRequestPlugin.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-parser 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf.parser; 22 | 23 | import com.google.protobuf.compiler.PluginProtos.CodeGeneratorRequest; 24 | import com.google.protobuf.compiler.PluginProtos.CodeGeneratorResponse; 25 | import com.google.protobuf.compiler.PluginProtos.CodeGeneratorResponse.Feature; 26 | 27 | import java.io.IOException; 28 | import java.io.InputStream; 29 | import java.util.Map; 30 | 31 | /** 32 | * @author Florian Enner 33 | * @since 05 Aug 2019 34 | */ 35 | public class SaveRequestPlugin { 36 | 37 | /** 38 | * A protoc-gen-plugin that communicates with protoc via messages on System.in and System.out 39 | * 40 | * @param args 41 | * @throws IOException 42 | */ 43 | public static void main(String[] args) throws IOException { 44 | handleRequest(System.in).writeTo(System.out); 45 | } 46 | 47 | public static CodeGeneratorResponse handleRequest(InputStream input) throws IOException { 48 | try { 49 | 50 | // Compile files 51 | CodeGeneratorRequest request = CodeGeneratorRequest.parseFrom(input); 52 | return handleRequest(request); 53 | 54 | } catch (Exception e) { 55 | return ParserUtil.asErrorWithStackTrace(e); 56 | } 57 | } 58 | 59 | public static CodeGeneratorResponse handleRequest(CodeGeneratorRequest request) throws IOException { 60 | CodeGeneratorResponse.Builder response = CodeGeneratorResponse.newBuilder(); 61 | 62 | // Signal proto3 optional support bit 63 | // see https://github.com/protocolbuffers/protobuf/blob/f75fd051d68136ce366c464cea4f3074158cd141/docs/implementing_proto3_presence.md#signaling-that-your-code-generator-supports-proto3-optional 64 | response.setSupportedFeatures(Feature.FEATURE_PROTO3_OPTIONAL_VALUE); 65 | 66 | // Figure out file name 67 | Map parameters = ParserUtil.getGeneratorParameters(request); 68 | String fileName = parameters.get("request_file"); 69 | if (fileName == null) 70 | return ParserUtil.asError("parameter 'request_file' is not set"); 71 | 72 | // Add content 73 | response.addFile(CodeGeneratorResponse.File.newBuilder() 74 | .setContentBytes(request.toByteString()) 75 | .setName(fileName)); 76 | 77 | return response.build(); 78 | 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /protoc-gen-request/src/main/resources/META-INF/native-image/jni-config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name":"java.lang.Boolean", 4 | "methods":[{"name":"getBoolean","parameterTypes":["java.lang.String"] }] 5 | }, 6 | { 7 | "name":"java.lang.InternalError", 8 | "methods":[{"name":"","parameterTypes":["java.lang.String"] }] 9 | } 10 | ] 11 | -------------------------------------------------------------------------------- /protoc-gen-request/src/main/resources/META-INF/native-image/reflect-config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name":"com.google.protobuf.ExtensionRegistry", 4 | "methods":[{"name":"getEmptyRegistry","parameterTypes":[] }] 5 | }, 6 | { 7 | "name":"java.lang.Cloneable", 8 | "allDeclaredClasses":true 9 | }, 10 | { 11 | "name":"java.lang.Object", 12 | "allDeclaredFields":true, 13 | "queryAllDeclaredMethods":true 14 | }, 15 | { 16 | "name":"java.nio.Buffer", 17 | "fields":[{"name":"address"}] 18 | }, 19 | { 20 | "name":"sun.misc.Unsafe", 21 | "allDeclaredFields":true, 22 | "queriedMethods":[ 23 | {"name":"arrayBaseOffset","parameterTypes":["java.lang.Class"] }, 24 | {"name":"arrayIndexScale","parameterTypes":["java.lang.Class"] }, 25 | {"name":"copyMemory","parameterTypes":["long","long","long"] }, 26 | {"name":"copyMemory","parameterTypes":["java.lang.Object","long","java.lang.Object","long","long"] }, 27 | {"name":"getBoolean","parameterTypes":["java.lang.Object","long"] }, 28 | {"name":"getByte","parameterTypes":["long"] }, 29 | {"name":"getByte","parameterTypes":["java.lang.Object","long"] }, 30 | {"name":"getDouble","parameterTypes":["java.lang.Object","long"] }, 31 | {"name":"getFloat","parameterTypes":["java.lang.Object","long"] }, 32 | {"name":"getInt","parameterTypes":["long"] }, 33 | {"name":"getInt","parameterTypes":["java.lang.Object","long"] }, 34 | {"name":"getLong","parameterTypes":["long"] }, 35 | {"name":"getLong","parameterTypes":["java.lang.Object","long"] }, 36 | {"name":"getObject","parameterTypes":["java.lang.Object","long"] }, 37 | {"name":"objectFieldOffset","parameterTypes":["java.lang.reflect.Field"] }, 38 | {"name":"putBoolean","parameterTypes":["java.lang.Object","long","boolean"] }, 39 | {"name":"putByte","parameterTypes":["long","byte"] }, 40 | {"name":"putByte","parameterTypes":["java.lang.Object","long","byte"] }, 41 | {"name":"putDouble","parameterTypes":["java.lang.Object","long","double"] }, 42 | {"name":"putFloat","parameterTypes":["java.lang.Object","long","float"] }, 43 | {"name":"putInt","parameterTypes":["long","int"] }, 44 | {"name":"putInt","parameterTypes":["java.lang.Object","long","int"] }, 45 | {"name":"putLong","parameterTypes":["long","long"] }, 46 | {"name":"putLong","parameterTypes":["java.lang.Object","long","long"] }, 47 | {"name":"putObject","parameterTypes":["java.lang.Object","long","java.lang.Object"] } 48 | ] 49 | } 50 | ] 51 | -------------------------------------------------------------------------------- /protoc-gen-request/src/main/scripts/unix.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | java -jar "${BASH_SOURCE%/*}/{jarfile}.jar" 3 | -------------------------------------------------------------------------------- /protoc-gen-request/src/main/scripts/windows.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | SET mypath=%~dp0 3 | java -jar %mypath:~0,-1%\{jarfile}.jar -------------------------------------------------------------------------------- /protoc-gen-request/src/test/java/us/hebi/quickbuf/parser/ParserUtilTest.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-parser 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf.parser; 22 | 23 | import org.junit.Test; 24 | 25 | import java.util.Map; 26 | 27 | import static org.junit.Assert.*; 28 | 29 | /** 30 | * @author Florian Enner 31 | * @since 06 Aug 2019 32 | */ 33 | public class ParserUtilTest { 34 | 35 | @Test 36 | public void parseEmptyParameters() { 37 | assertTrue(ParserUtil.parseGeneratorParameters("").isEmpty()); 38 | } 39 | 40 | @Test 41 | public void parseSingleParameter() { 42 | assertEquals("value",ParserUtil.parseGeneratorParameters("key=value").get("key")); 43 | assertEquals("",ParserUtil.parseGeneratorParameters("key").get("key")); 44 | } 45 | 46 | @Test 47 | public void parseMultiParameter() { 48 | Map params = ParserUtil.parseGeneratorParameters("key1=value1,key2=value2,key3"); 49 | assertEquals("value1",params.get("key1")); 50 | assertEquals("value2",params.get("key2")); 51 | assertEquals("",params.get("key3")); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /quickbuf-compat/src/main/java/us/hebi/quickbuf/compat/GsonSource.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-benchmarks 4 | * %% 5 | * Copyright (C) 2019 - 2020 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf.compat; 22 | 23 | import com.google.gson.stream.JsonReader; 24 | import com.google.gson.stream.JsonToken; 25 | import us.hebi.quickbuf.*; 26 | 27 | import java.io.IOException; 28 | import java.io.Reader; 29 | import java.io.StringReader; 30 | 31 | /** 32 | * Implementation of a JsonSource using GSON. 33 | *

34 | * Warning: this implementation has not been tested extensively against bad inputs. 35 | * 36 | * @author Florian Enner 37 | * @since 07 Sep 2020 38 | */ 39 | public class GsonSource extends JsonSource { 40 | 41 | public GsonSource(String string) { 42 | this(new StringReader(string)); 43 | } 44 | 45 | public GsonSource(Reader reader) { 46 | this(new JsonReader(reader)); 47 | this.reader.setLenient(true); // allow nan/infinity 48 | } 49 | 50 | /** 51 | * @param jsonReader custom json reader. Should be lenient to allow nan/infinity 52 | */ 53 | public GsonSource(JsonReader jsonReader) { 54 | this.reader = jsonReader; 55 | } 56 | 57 | final JsonReader reader; 58 | 59 | public GsonSource setIgnoreUnknownFields(final boolean ignoreUnknownFields) { 60 | super.setIgnoreUnknownFields(ignoreUnknownFields); 61 | return this; 62 | } 63 | 64 | @Override 65 | public double readDouble() throws IOException { 66 | return reader.nextDouble(); 67 | } 68 | 69 | @Override 70 | public int readInt32() throws IOException { 71 | return reader.nextInt(); 72 | } 73 | 74 | @Override 75 | public long readInt64() throws IOException { 76 | return reader.nextLong(); 77 | } 78 | 79 | @Override 80 | public boolean readBool() throws IOException { 81 | return reader.nextBoolean(); 82 | } 83 | 84 | @Override 85 | public > T readEnum(ProtoEnum.EnumConverter converter) throws IOException { 86 | if (reader.peek() == JsonToken.NUMBER) { 87 | return converter.forNumber(reader.nextInt()); 88 | } else { 89 | return converter.forName(reader.nextString()); 90 | } 91 | } 92 | 93 | @Override 94 | public void readString(Utf8String store) throws IOException { 95 | store.copyFrom(reader.nextString()); 96 | } 97 | 98 | @Override 99 | public void readBytes(RepeatedByte store) throws IOException { 100 | decodeBase64(reader.nextString(), store.clear()); 101 | } 102 | 103 | @Override 104 | public ProtoSource readBytesAsSource() throws IOException { 105 | RepeatedByte store = RepeatedByte.newEmptyInstance(); 106 | decodeBase64(reader.nextString(), store); 107 | return ProtoSource.newInstance(store); 108 | } 109 | 110 | @Override 111 | public void skipValue() throws IOException { 112 | reader.skipValue(); 113 | } 114 | 115 | @Override 116 | public boolean beginObject() throws IOException { 117 | reader.beginObject(); 118 | return true; 119 | } 120 | 121 | @Override 122 | public void endObject() throws IOException { 123 | reader.endObject(); 124 | } 125 | 126 | @Override 127 | public void beginArray() throws IOException { 128 | reader.beginArray(); 129 | } 130 | 131 | @Override 132 | public void endArray() throws IOException { 133 | reader.endArray(); 134 | } 135 | 136 | @Override 137 | public boolean isAtEnd() throws IOException { 138 | return !reader.hasNext(); 139 | } 140 | 141 | @Override 142 | protected boolean isAtNull() throws IOException { 143 | return reader.peek() == JsonToken.NULL; 144 | } 145 | 146 | @Override 147 | protected CharSequence readFieldName() throws IOException { 148 | return reader.nextName(); 149 | } 150 | 151 | @Override 152 | public void close() throws IOException { 153 | reader.close(); 154 | } 155 | 156 | } 157 | -------------------------------------------------------------------------------- /quickbuf-compat/src/test/java/us/hebi/quickbuf/compat/GsonSourceTest.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-benchmarks 4 | * %% 5 | * Copyright (C) 2019 - 2020 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf.compat; 22 | 23 | import org.junit.Test; 24 | import us.hebi.quickbuf.CompatibilityTest; 25 | import us.hebi.quickbuf.JsonSink; 26 | import us.hebi.quickbuf.JsonSource; 27 | import us.hebi.quickbuf.JsonSourceTest; 28 | 29 | import java.io.IOException; 30 | import java.io.StringReader; 31 | 32 | import static org.junit.Assert.*; 33 | 34 | /** 35 | * @author Florian Enner 36 | * @since 07 Sep 2020 37 | */ 38 | public class GsonSourceTest extends JsonSourceTest { 39 | 40 | @Test 41 | public void testBadInputs() { 42 | testError(CompatibilityTest.JSON_NULL, "Expected BEGIN_OBJECT but was NULL at line 1 column 5 path $"); 43 | testError(CompatibilityTest.JSON_LIST_EMPTY, "Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $"); 44 | testError(CompatibilityTest.JSON_REPEATED_BYTES_NULL_VALUE, "Expected a string but was NULL at line 1 column 24 path $.repeatedBytes[0]"); 45 | testError(CompatibilityTest.JSON_REPEATED_MSG_NULL_VALUE, "Expected BEGIN_OBJECT but was NULL at line 1 column 33 path $.repeatedForeignMessage[0]"); 46 | testError(CompatibilityTest.JSON_BAD_BOOLEAN, "Expected a boolean but was STRING at line 1 column 18 path $.optionalBool"); 47 | testError(CompatibilityTest.JSON_UNKNOWN_FIELD, "Encountered unknown field: 'unknownField'"); 48 | testError(CompatibilityTest.JSON_UNKNOWN_FIELD_NULL, "Encountered unknown field: 'unknownField'"); 49 | } 50 | 51 | @Override 52 | protected JsonSource newJsonSource(String json) { 53 | return new GsonSource(json); 54 | } 55 | 56 | @Override 57 | protected JsonSource newJsonSource(JsonSink sink) { 58 | return new GsonSource(new StringReader(sink.toString())); 59 | } 60 | 61 | @Override 62 | protected void testError(String input, String error) { 63 | try { 64 | parseJson(input); 65 | fail("expected error: " + error); 66 | } catch (IOException ioe) { 67 | assertEquals(error, ioe.getMessage()); 68 | } catch (IllegalStateException stateEx) { 69 | // TODO: wrap IllegalStateException? 70 | assertEquals(error, stateEx.getMessage()); 71 | } 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /quickbuf-compat/src/test/java/us/hebi/quickbuf/compat/JacksonSinkTest.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-runtime 4 | * %% 5 | * Copyright (C) 2019 - 2022 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf.compat; 22 | 23 | import us.hebi.quickbuf.JsonSink; 24 | import us.hebi.quickbuf.JsonSource; 25 | 26 | import java.io.IOException; 27 | import java.io.StringReader; 28 | 29 | /** 30 | * @author Florian Enner 31 | * @since 25 Feb 2022 32 | */ 33 | public class JacksonSinkTest extends GsonSinkTest { 34 | 35 | public JsonSink newJsonSink() { 36 | return JacksonSink.newStringWriter(); 37 | } 38 | 39 | public JsonSource newJsonSource(String json) throws IOException { 40 | return new JacksonSource(new StringReader(json)); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /quickbuf-compat/src/test/java/us/hebi/quickbuf/compat/JacksonSourceTest.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-benchmarks 4 | * %% 5 | * Copyright (C) 2019 - 2020 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf.compat; 22 | 23 | import org.junit.Test; 24 | import us.hebi.quickbuf.CompatibilityTest; 25 | import us.hebi.quickbuf.JsonSink; 26 | import us.hebi.quickbuf.JsonSource; 27 | import us.hebi.quickbuf.JsonSourceTest; 28 | 29 | import java.io.IOException; 30 | import java.io.StringReader; 31 | 32 | /** 33 | * @author Florian Enner 34 | * @since 07 Sep 2020 35 | */ 36 | public class JacksonSourceTest extends JsonSourceTest { 37 | 38 | @Test 39 | public void testBadInputs() { 40 | testError(CompatibilityTest.JSON_NULL, "Expected { but was VALUE_NULL\n" + 41 | " at [Source: (StringReader); line: 1, column: 1]"); 42 | testError(CompatibilityTest.JSON_LIST_EMPTY, "Expected { but was START_ARRAY\n" + 43 | " at [Source: (StringReader); line: 1, column: 1]"); 44 | testError(CompatibilityTest.JSON_REPEATED_BYTES_NULL_VALUE, "Current token (VALUE_NULL) not VALUE_STRING or VALUE_EMBEDDED_OBJECT, can not access as binary\n" + 45 | " at [Source: (StringReader); line: 1, column: 24]"); 46 | testError(CompatibilityTest.JSON_REPEATED_MSG_NULL_VALUE, "Expected { but was VALUE_NULL\n" + 47 | " at [Source: (StringReader); line: 1, column: 29]"); 48 | testError(CompatibilityTest.JSON_BAD_BOOLEAN, "Unrecognized token 'fals': was expecting (JSON String, Number (or 'NaN'/'INF'/'+INF'), Array, Object or token 'null', 'true' or 'false')\n" + 49 | " at [Source: (StringReader); line: 1, column: 22]"); 50 | testError(CompatibilityTest.JSON_UNKNOWN_FIELD, "Encountered unknown field: 'unknownField'"); 51 | testError(CompatibilityTest.JSON_UNKNOWN_FIELD_NULL, "Encountered unknown field: 'unknownField'"); 52 | } 53 | 54 | @Override 55 | protected JsonSource newJsonSource(String json) throws IOException { 56 | return new JacksonSource(json); 57 | } 58 | 59 | @Override 60 | protected JsonSource newJsonSource(JsonSink sink) throws IOException { 61 | return new JacksonSource(new StringReader(sink.toString())); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/java9/JdkMethods.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HebiRobotics/QuickBuffers/b254ce1cf379581ad72d03f095bdf9b9d133cb9c/quickbuf-runtime/src/java9/JdkMethods.class -------------------------------------------------------------------------------- /quickbuf-runtime/src/java9/JdkMethods.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-runtime 4 | * %% 5 | * Copyright (C) 2019 - 2023 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package us.hebi.quickbuf; 21 | 22 | /** 23 | * This class calls JDK methods that were added in future versions. 24 | * The real class file gets compiled separately with a newer JDK and 25 | * a Java 6 source/target level, so it can be loaded with older JDKs. 26 | *

27 | * When called from older JDKs, the methods will throw a NoSuchMethod 28 | * Exception. This allows using intrinsics without the overhead of 29 | * reflections. The effect is similar to creating a multi-release (MR) 30 | * jar, but is better supported by tooling and bytecode analyzers for 31 | * obfuscation or native images. 32 | * 33 | * @author Florian Enner 34 | * @since 14 Jan 2023 35 | */ 36 | class JdkMethods { 37 | 38 | public static long multiplyHigh(long x, long y) { 39 | return java.lang.Math.multiplyHigh(x, y); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/java9/compile.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | SET mypath=%~dp0 3 | "%JAVA11%/bin/javac" -source 6 -target 6 %mypath:~0,-1%/*.java -------------------------------------------------------------------------------- /quickbuf-runtime/src/main/java/us/hebi/quickbuf/Descriptors.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-runtime 4 | * %% 5 | * Copyright (C) 2019 - 2023 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package us.hebi.quickbuf; 21 | 22 | import java.util.ArrayList; 23 | import java.util.Arrays; 24 | import java.util.Collections; 25 | import java.util.List; 26 | 27 | /** 28 | * Contains classes that describe the protocol message types. 29 | * 30 | * @author Florian Enner 31 | * @since 20 Sep 2023 32 | */ 33 | public final class Descriptors { 34 | 35 | public abstract static class GenericDescriptor { 36 | 37 | public byte[] toProtoBytes() { 38 | return Arrays.copyOfRange(bytes.array, offset, offset + length); 39 | } 40 | 41 | public String getName() { 42 | return name; 43 | } 44 | 45 | public String getFullName() { 46 | return fullName; 47 | } 48 | 49 | public abstract FileDescriptor getFile(); 50 | 51 | // Private constructor to prevent subclasses outside this package 52 | private GenericDescriptor(String fullName, String name, RepeatedByte bytes, int offset, int length) { 53 | this.fullName = fullName; 54 | this.name = name; 55 | this.bytes = bytes; 56 | this.offset = offset; 57 | this.length = length; 58 | } 59 | 60 | @Override 61 | public String toString() { 62 | return "descriptor{" + fullName + "}"; 63 | } 64 | 65 | final String fullName; 66 | final String name; 67 | final RepeatedByte bytes; 68 | final int offset; 69 | final int length; 70 | 71 | } 72 | 73 | public static class FileDescriptor extends GenericDescriptor { 74 | 75 | public static FileDescriptor internalBuildGeneratedFileFrom(String name, String protoPackage, RepeatedByte bytes, FileDescriptor... dependencies) { 76 | return new FileDescriptor(name, protoPackage, bytes, Arrays.asList(dependencies)); 77 | } 78 | 79 | public Descriptor internalContainedType(int offset, int length, String name, String fullName) { 80 | Descriptor type = new Descriptor(fullName, name, this, bytes, offset, length); 81 | containedTypes.add(type); 82 | return type; 83 | } 84 | 85 | public String getPackage() { 86 | return protoPackage; 87 | } 88 | 89 | public FileDescriptor getFile() { 90 | return this; 91 | } 92 | 93 | public List getDependencies() { 94 | return Collections.unmodifiableList(dependencies); 95 | } 96 | 97 | /** 98 | * @return descriptors for all message and nested types contained in this file 99 | */ 100 | public List getAllContainedTypes() { 101 | return Collections.unmodifiableList(containedTypes); 102 | } 103 | 104 | /** 105 | * @return descriptors for all types in this file and its dependencies 106 | */ 107 | public List getAllKnownTypes() { 108 | return getAllKnownTypes(this, new ArrayList()); 109 | } 110 | 111 | private static List getAllKnownTypes(FileDescriptor file, List list) { 112 | for (FileDescriptor dependency : file.dependencies) { 113 | getAllKnownTypes(dependency, list); 114 | } 115 | list.addAll(file.containedTypes); 116 | return list; 117 | } 118 | 119 | private FileDescriptor(String fileName, String protoPackage, RepeatedByte bytes, List dependencies) { 120 | super(fileName, fileName, bytes, 0, bytes.length()); 121 | this.protoPackage = protoPackage; 122 | this.dependencies = dependencies; 123 | } 124 | 125 | final String protoPackage; 126 | final List dependencies; 127 | final List containedTypes = new ArrayList(); 128 | 129 | } 130 | 131 | public static class Descriptor extends GenericDescriptor { 132 | 133 | private Descriptor(String fullName, String name, FileDescriptor file, RepeatedByte bytes, int offset, int length) { 134 | super(fullName, name, bytes, offset, length); 135 | this.file = file; 136 | } 137 | 138 | @Override 139 | public FileDescriptor getFile() { 140 | return file; 141 | } 142 | 143 | final FileDescriptor file; 144 | 145 | } 146 | 147 | private Descriptors() { 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/main/java/us/hebi/quickbuf/FieldName.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-runtime 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf; 22 | 23 | import us.hebi.quickbuf.ProtoUtil.Charsets; 24 | 25 | /** 26 | * Field name for serializing text based output like JSON. It allows 27 | * for caching e.g. the encoded field name while allowing external 28 | * libraries to access what they can consume. 29 | * 30 | * @author Florian Enner 31 | * @since 28 Nov 2019 32 | */ 33 | public final class FieldName { 34 | 35 | public static FieldName forField(String jsonName) { 36 | return new FieldName(jsonName, jsonName); 37 | } 38 | 39 | public static FieldName forField(String jsonName, String protoName) { 40 | return new FieldName(jsonName, protoName); 41 | } 42 | 43 | private FieldName(String jsonName, String protoName) { 44 | this.jsonName = jsonName; 45 | this.protoName = protoName; 46 | } 47 | 48 | public String getJsonName() { 49 | return jsonName; 50 | } 51 | 52 | public String getProtoName() { 53 | return protoName; 54 | } 55 | 56 | /** 57 | * @return utf8 bytes with name quotes and colon 58 | */ 59 | public byte[] getJsonKeyBytes() { 60 | if (jsonKey == null) { 61 | jsonKey = ('"' + jsonName + '"' + ':').getBytes(Charsets.UTF_8); 62 | if (jsonName.equals(protoName)) { 63 | protoKey = jsonKey; 64 | } 65 | } 66 | return jsonKey; 67 | } 68 | 69 | /** 70 | * @return utf8 bytes with name quotes and colon 71 | */ 72 | public byte[] getProtoKeyBytes() { 73 | if (protoKey == null) { 74 | protoKey = ('"' + protoName + '"' + ':').getBytes(Charsets.UTF_8); 75 | if (protoName.equals(jsonName)) { 76 | jsonKey = protoKey; 77 | } 78 | } 79 | return protoKey; 80 | } 81 | 82 | private final String jsonName; 83 | private final String protoName; 84 | 85 | private byte[] jsonKey; 86 | private byte[] protoKey; 87 | 88 | } 89 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/main/java/us/hebi/quickbuf/InvalidJsonException.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-runtime 4 | * %% 5 | * Copyright (C) 2019 - 2022 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf; 22 | 23 | /** 24 | * @author Florian Enner 25 | * @since 18 Mär 2022 26 | */ 27 | public class InvalidJsonException extends InvalidProtocolBufferException { 28 | 29 | private static final long serialVersionUID = 1L; 30 | 31 | public InvalidJsonException(String description) { 32 | super(description); 33 | } 34 | 35 | static InvalidJsonException truncatedMessage() { 36 | return new InvalidJsonException( 37 | "While parsing a protocol message, the input ended unexpectedly " + 38 | "in the middle of a field. This could mean either than the " + 39 | "input has been truncated or that the input is invalid."); 40 | } 41 | 42 | static InvalidJsonException illegalNumberFormat() { 43 | return new InvalidJsonException("Illegal number format."); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/main/java/us/hebi/quickbuf/JdkMath.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-runtime 4 | * %% 5 | * Copyright (C) 2019 - 2023 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package us.hebi.quickbuf; 21 | 22 | /** 23 | * This class dispatches calls to built-in Java methods 24 | * when available, and runs a fallback version when not. 25 | * It allows us to make use of newer features without 26 | * breaking backwards compatibility with oder runtimes. 27 | * 28 | * @author Florian Enner 29 | * @since 14 Jan 2023 30 | */ 31 | public class JdkMath { 32 | 33 | /** 34 | * Returns as a {@code long} the most significant 64 bits of the 128-bit 35 | * product of two 64-bit factors. 36 | * 37 | * @param x the first value 38 | * @param y the second value 39 | * @return the result 40 | * @since 9 41 | */ 42 | public static long multiplyHigh(long x, long y) { 43 | if (HAS_MULTIPLY_HIGH) { 44 | return JdkMethods.multiplyHigh(x, y); 45 | } 46 | if (x < 0 || y < 0) { 47 | // Use technique from section 8-2 of Henry S. Warren, Jr., 48 | // Hacker's Delight (2nd ed.) (Addison Wesley, 2013), 173-174. 49 | long x1 = x >> 32; 50 | long x2 = x & 0xFFFFFFFFL; 51 | long y1 = y >> 32; 52 | long y2 = y & 0xFFFFFFFFL; 53 | long z2 = x2 * y2; 54 | long t = x1 * y2 + (z2 >>> 32); 55 | long z1 = t & 0xFFFFFFFFL; 56 | long z0 = t >> 32; 57 | z1 += x2 * y1; 58 | return x1 * y1 + z0 + (z1 >> 32); 59 | } else { 60 | // Use Karatsuba technique with two base 2^32 digits. 61 | long x1 = x >>> 32; 62 | long y1 = y >>> 32; 63 | long x2 = x & 0xFFFFFFFFL; 64 | long y2 = y & 0xFFFFFFFFL; 65 | long A = x1 * y1; 66 | long B = x2 * y2; 67 | long C = (x1 + x2) * (y1 + y2); 68 | long K = C - A - B; 69 | return (((B >>> 32) + K) >>> 32) + A; 70 | } 71 | } 72 | 73 | private static boolean hasMultiplyHigh0() { 74 | try { 75 | JdkMethods.multiplyHigh(0, 0); 76 | return true; 77 | } catch (NoSuchMethodError oldRuntime) { 78 | return false; 79 | } 80 | } 81 | 82 | static final boolean HAS_MULTIPLY_HIGH = hasMultiplyHigh0(); 83 | 84 | } 85 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/main/java/us/hebi/quickbuf/JdkMethods.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-runtime 4 | * %% 5 | * Copyright (C) 2019 - 2023 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package us.hebi.quickbuf; 21 | 22 | /** 23 | * This class calls JDK methods that were added in future versions. 24 | * The real class file gets compiled separately with a newer JDK and 25 | * a Java 6 source/target level, so it can be loaded with older JDKs. 26 | *

27 | * When called from older JDKs, the methods will throw a NoSuchMethod 28 | * Exception. This allows using intrinsics without the overhead of 29 | * reflections. The effect is similar to creating a multi-release (MR) 30 | * jar, but is better supported by tooling and bytecode analyzers for 31 | * obfuscation or native images. 32 | * 33 | * @author Florian Enner 34 | * @since 14 Jan 2023 35 | */ 36 | class JdkMethods { 37 | 38 | public static long multiplyHigh(long x, long y) { 39 | throw new NoSuchMethodError(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/main/java/us/hebi/quickbuf/MessageFactory.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-runtime 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf; 22 | 23 | /** 24 | * Factory interface for creating messages 25 | * 26 | * @author Florian Enner 27 | * @since 15 Aug 2019 28 | */ 29 | public interface MessageFactory> { 30 | 31 | T create(); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/main/java/us/hebi/quickbuf/ProtoEnum.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-runtime 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf; 22 | 23 | /** 24 | * @author Florian Enner 25 | * @since 17 Nov 2019 26 | */ 27 | public interface ProtoEnum { 28 | 29 | public int getNumber(); 30 | 31 | public String getName(); 32 | 33 | public interface EnumConverter { 34 | 35 | /** 36 | * @param value The numeric wire value of the enum entry. 37 | * @return The enum value associated with the given numeric wire value, or null if unknown. 38 | */ 39 | public E forNumber(int value); 40 | 41 | /** 42 | * 43 | * @param value The text representation of the enum entry 44 | * @return The enum value associated with the given text representation, or null if unknown. 45 | */ 46 | public E forName(CharSequence value); 47 | 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/main/java/us/hebi/quickbuf/RepeatedBytes.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-runtime 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf; 22 | 23 | /** 24 | * @author Florian Enner 25 | * @since 09 Aug 2019 26 | */ 27 | public class RepeatedBytes extends RepeatedObject { 28 | 29 | public static RepeatedBytes newEmptyInstance() { 30 | return new RepeatedBytes(); 31 | } 32 | 33 | private RepeatedBytes() { 34 | } 35 | 36 | @Override 37 | protected void setIndex0(int index, byte[] value) { 38 | array[index].copyFrom(value); 39 | } 40 | 41 | @Override 42 | protected RepeatedByte getIndex0(int index) { 43 | return array[index]; 44 | } 45 | 46 | @Override 47 | protected void copyFrom0(RepeatedByte store, RepeatedByte other) { 48 | store.copyFrom(other); 49 | } 50 | 51 | @Override 52 | protected void clearIndex0(int index) { 53 | array[index].clear(); 54 | } 55 | 56 | @Override 57 | protected RepeatedByte createEmpty() { 58 | return new RepeatedByte(); 59 | } 60 | 61 | @Override 62 | protected RepeatedByte[] allocateArray0(int desiredSize) { 63 | return new RepeatedByte[desiredSize]; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/main/java/us/hebi/quickbuf/RepeatedField.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-runtime 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf; 22 | 23 | import java.util.Iterator; 24 | 25 | /** 26 | * @author Florian Enner 27 | * @since 10 Aug 2019 28 | */ 29 | abstract class RepeatedField implements Iterable { 30 | 31 | public final int length() { 32 | return length; 33 | } 34 | 35 | public final int remainingCapacity() { 36 | return capacity() - length; 37 | } 38 | 39 | protected abstract GenericType getValueAt(int index); 40 | 41 | @Override 42 | public GenericIterator iterator() { 43 | return new GenericIterator(length); 44 | } 45 | 46 | class GenericIterator implements Iterator { 47 | 48 | GenericIterator(int maxLength) { 49 | this.maxLength = maxLength; 50 | } 51 | 52 | @Override 53 | public boolean hasNext() { 54 | return position < maxLength; 55 | } 56 | 57 | @Override 58 | public GenericType next() { 59 | return getValueAt(position++); 60 | } 61 | 62 | private int position = 0; 63 | private final int maxLength; 64 | 65 | } 66 | 67 | /** 68 | * Makes sure that the internal storage capacity has space for 69 | * at least the requested number of entries. This method will 70 | * increase the internal capacity if needed. 71 | * 72 | * @param count number of entries to be added 73 | */ 74 | @SuppressWarnings("unchecked") 75 | public final RepeatedType reserve(int count) { 76 | final int desiredSize = length + count; 77 | if (desiredSize - capacity() > 0) { // overflow-conscious 78 | extendCapacityTo(desiredSize); 79 | } 80 | return (RepeatedType) this; 81 | } 82 | 83 | /** 84 | * Sets the output length to zero and performs any 85 | * necessary cleanup of the content. Does not release 86 | * the internal buffer. 87 | */ 88 | @SuppressWarnings("unchecked") 89 | public RepeatedType clear() { 90 | length = 0; 91 | return (RepeatedType) this; 92 | } 93 | 94 | protected final void checkIndex(int index) { 95 | if (index < 0 || index >= length) { 96 | throw new ArrayIndexOutOfBoundsException(); 97 | } 98 | } 99 | 100 | public abstract void addAll(RepeatedType values); 101 | 102 | public abstract void copyFrom(RepeatedType other); 103 | 104 | public abstract int capacity(); 105 | 106 | protected abstract void extendCapacityTo(int desiredSize); 107 | 108 | protected int length = 0; 109 | 110 | /** 111 | * Repeated fields have no immutable state and should not 112 | * be used in hashing structures. This method returns 113 | * a constant value. 114 | * 115 | * @return 0 116 | */ 117 | @Override 118 | public final int hashCode() { 119 | return 0; 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/main/java/us/hebi/quickbuf/RepeatedMessage.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-runtime 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf; 22 | 23 | /** 24 | * @author Florian Enner 25 | * @since 09 Aug 2019 26 | */ 27 | public final class RepeatedMessage> extends RepeatedObject, MessageType, MessageType, MessageType> { 28 | 29 | @SuppressWarnings("unchecked") 30 | public static > RepeatedMessage newEmptyInstance(MessageFactory factory) { 31 | return new RepeatedMessage(factory); 32 | } 33 | 34 | private RepeatedMessage(MessageFactory factory) { 35 | this.factory = ProtoUtil.checkNotNull(factory); 36 | } 37 | 38 | @Override 39 | @SuppressWarnings("unchecked") 40 | protected final void setIndex0(int index, MessageType value) { 41 | array[index].copyFrom(value); 42 | } 43 | 44 | @Override 45 | protected MessageType getIndex0(int index) { 46 | return array[index]; 47 | } 48 | 49 | @Override 50 | protected final void clearIndex0(int index) { 51 | array[index].clear(); 52 | } 53 | 54 | @Override 55 | protected void copyFrom0(MessageType store, MessageType other) { 56 | store.copyFrom(other); 57 | } 58 | 59 | @Override 60 | @SuppressWarnings("unchecked") 61 | protected final MessageType[] allocateArray0(int desiredSize) { 62 | return (MessageType[]) new ProtoMessage[desiredSize]; 63 | } 64 | 65 | public final RepeatedMessage clearQuick() { 66 | for (int i = 0; i < length; i++) { 67 | array[i].clearQuick(); 68 | } 69 | length = 0; 70 | return this; 71 | } 72 | 73 | /** 74 | * @return true if all contained messages are initialized 75 | */ 76 | public final boolean isInitialized() { 77 | for (int i = 0; i < length; i++) { 78 | if (!array[i].isInitialized()) 79 | return false; 80 | } 81 | return true; 82 | } 83 | 84 | /** 85 | * Helper method to check whether all contained messages are 86 | * initialized, i.e., if all required fields are set. 87 | *

88 | * Message content is not automatically checked after merging 89 | * new data. This method should be called manually as needed. 90 | * 91 | * @return this 92 | * @throws InvalidProtocolBufferException if one or more messages are not initialized. 93 | */ 94 | public RepeatedMessage checkInitialized() throws InvalidProtocolBufferException { 95 | if (!isInitialized()) { 96 | throw new UninitializedMessageException(this).asInvalidProtocolBufferException(); 97 | } 98 | return this; 99 | } 100 | 101 | @Override 102 | protected MessageType createEmpty() { 103 | return factory.create(); 104 | } 105 | 106 | final MessageFactory factory; 107 | 108 | } 109 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/main/java/us/hebi/quickbuf/RepeatedObject.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-runtime 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf; 22 | 23 | import java.util.Arrays; 24 | 25 | /** 26 | * Base class for repeated fields of non-primitive values such as 27 | * messages, bytes, or strings. 28 | * 29 | * @author Florian Enner 30 | * @since 14 Aug 2019 31 | */ 32 | abstract class RepeatedObject, STORE, IN, OUT> extends RepeatedField { 33 | 34 | public final STORE next() { 35 | reserve(1); 36 | return array[length++]; 37 | } 38 | 39 | @Override 40 | protected OUT getValueAt(int index) { 41 | return get(index); 42 | } 43 | 44 | public final OUT get(int index) { 45 | checkIndex(index); 46 | return getIndex0(index); 47 | } 48 | 49 | public final void set(int index, IN value) { 50 | checkIndex(index); 51 | setIndex0(index, value); 52 | } 53 | 54 | public final void addAll(IN[] values) { 55 | addAll(values, 0, values.length); 56 | } 57 | 58 | public final void addAll(IN[] buffer, int offset, int length) { 59 | reserve(length); 60 | for (int i = offset; i < length; i++) { 61 | add(buffer[i]); 62 | } 63 | } 64 | 65 | public final void add(IN value) { 66 | reserve(1); 67 | setIndex0(length++, value); 68 | } 69 | 70 | public final void copyFrom(IN[] buffer) { 71 | copyFrom(buffer, 0, buffer.length); 72 | } 73 | 74 | public final void copyFrom(IN[] buffer, int offset, int length) { 75 | this.length = 0; 76 | addAll(buffer, offset, length); 77 | } 78 | 79 | @Override 80 | public final void copyFrom(SubType other) { 81 | if (other.length > length) { 82 | extendCapacityTo(other.length); 83 | } 84 | length = other.length; 85 | for (int i = 0; i < length; i++) { 86 | copyFrom0(array[i], other.array[i]); 87 | } 88 | } 89 | 90 | @Override 91 | public void addAll(SubType values) { 92 | final int newLength = length + values.length; 93 | extendCapacityTo(newLength); 94 | for (int i = 0; i < values.length; i++) { 95 | copyFrom0(array[length + i], values.array[i]); 96 | } 97 | this.length = newLength; 98 | } 99 | 100 | @Override 101 | public final int capacity() { 102 | return array.length; 103 | } 104 | 105 | @Override 106 | public final String toString() { 107 | return Arrays.toString(Arrays.copyOf(array, length)); 108 | } 109 | 110 | @Override 111 | public final boolean equals(Object o) { 112 | if (this == o) return true; 113 | if (o == null || getClass() != o.getClass()) return false; 114 | RepeatedObject other = (RepeatedObject) o; 115 | 116 | if (length != other.length) 117 | return false; 118 | 119 | for (int i = 0; i < length; i++) { 120 | if (!isEqual(array[i], other.array[i])) 121 | return false; 122 | } 123 | return true; 124 | } 125 | 126 | private boolean isEqual(STORE a, Object b) { 127 | return (a == b) || (a != null && a.equals(b)); 128 | } 129 | 130 | @Override 131 | public final SubType clear() { 132 | for (int i = 0; i < length; i++) { 133 | clearIndex0(i); 134 | } 135 | return super.clear(); 136 | } 137 | 138 | @Override 139 | protected final void extendCapacityTo(int desiredSize) { 140 | final STORE[] newValues = allocateArray0(desiredSize); 141 | System.arraycopy(array, 0, newValues, 0, length); 142 | this.array = newValues; 143 | for (int i = length; i < array.length; i++) { 144 | array[i] = createEmpty(); 145 | } 146 | } 147 | 148 | protected abstract void copyFrom0(STORE store, STORE other); 149 | 150 | protected abstract void clearIndex0(int index); 151 | 152 | protected abstract void setIndex0(int index, IN value); 153 | 154 | protected abstract OUT getIndex0(int index); 155 | 156 | protected abstract STORE createEmpty(); 157 | 158 | protected abstract STORE[] allocateArray0(int desiredSize); 159 | 160 | final STORE[] EMPTY = allocateArray0(0); 161 | protected STORE[] array = EMPTY; 162 | 163 | } 164 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/main/java/us/hebi/quickbuf/RepeatedString.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-runtime 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf; 22 | 23 | /** 24 | * @author Florian Enner 25 | * @since 09 Aug 2019 26 | */ 27 | public final class RepeatedString extends RepeatedObject { 28 | 29 | public static RepeatedString newEmptyInstance() { 30 | return new RepeatedString(); 31 | } 32 | 33 | RepeatedString() { 34 | } 35 | 36 | public String get(final int index, final Utf8Decoder decoder) { 37 | checkIndex(index); 38 | return array[index].getString(decoder); 39 | } 40 | 41 | @Override 42 | protected void setIndex0(int index, CharSequence value) { 43 | array[index].copyFrom(value); 44 | } 45 | 46 | @Override 47 | protected String getIndex0(int index) { 48 | return array[index].getString(); 49 | } 50 | 51 | @Override 52 | protected void clearIndex0(int index) { 53 | array[index].clear(); 54 | } 55 | 56 | @Override 57 | protected void copyFrom0(Utf8String store, Utf8String other) { 58 | store.copyFrom(other); 59 | } 60 | 61 | @Override 62 | protected Utf8String[] allocateArray0(int desiredSize) { 63 | return new Utf8String[desiredSize]; 64 | } 65 | 66 | @Override 67 | protected Utf8String createEmpty() { 68 | return Utf8String.newEmptyInstance(); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/main/java/us/hebi/quickbuf/UninitializedMessageException.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-runtime 4 | * %% 5 | * Copyright (C) 2019 - 2022 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf; 22 | 23 | import java.util.ArrayList; 24 | import java.util.Collections; 25 | import java.util.List; 26 | 27 | /** 28 | * Thrown when attempting to build a protocol message that is missing required fields. This is a 29 | * {@code RuntimeException} because it normally represents a programming error: it happens when some 30 | * code which constructs a message fails to set all the fields. {@code parseFrom()} methods do 31 | * not throw this; they throw an {@link InvalidProtocolBufferException} if required fields are 32 | * missing, because it is not a programming error to receive an incomplete message. In other words, 33 | * {@code UninitializedMessageException} should never be thrown by correct code, but {@code 34 | * InvalidProtocolBufferException} might be. 35 | * 36 | * @author kenton@google.com Kenton Varda 37 | */ 38 | public class UninitializedMessageException extends RuntimeException { 39 | 40 | private static final long serialVersionUID = 0L; 41 | 42 | public UninitializedMessageException(final ProtoMessage message) { 43 | super("Message missing required fields"); 44 | this.origin = message; 45 | } 46 | 47 | public UninitializedMessageException(final RepeatedMessage messageArray) { 48 | super("Message array missing required fields"); 49 | this.missingFields = new ArrayList(); 50 | ProtoMessage.getMissingFields("", "", messageArray, missingFields); 51 | } 52 | 53 | public UninitializedMessageException(final List missingFields) { 54 | super("Message missing required fields"); 55 | this.missingFields = missingFields; 56 | } 57 | 58 | /** set from the base message */ 59 | UninitializedMessageException withParentMessage(ProtoMessage message) { 60 | this.origin = message; 61 | this.description = null; 62 | this.missingFields = null; 63 | return this; 64 | } 65 | 66 | public String getMessage() { 67 | if (description == null) { 68 | if (missingFields == null) { 69 | missingFields = origin.getMissingFields(); 70 | } 71 | description = buildDescription(missingFields); 72 | } 73 | return description; 74 | } 75 | 76 | String description; 77 | private ProtoMessage origin; 78 | private List missingFields; 79 | 80 | /** 81 | * Get a list of human-readable names of required fields missing from this message. Each name is a 82 | * full path to a field, e.g. "foo.bar[5].baz". Returns null if the lite runtime was used, since 83 | * it lacks the ability to find missing fields. 84 | */ 85 | public List getMissingFields() { 86 | if(missingFields == null) { 87 | missingFields = origin.getMissingFields(); 88 | } 89 | return Collections.unmodifiableList(missingFields); 90 | } 91 | 92 | /** 93 | * Converts this exception to an {@link InvalidProtocolBufferException}. When a parsed message is 94 | * missing required fields, this should be thrown instead of {@code UninitializedMessageException}. 95 | */ 96 | public InvalidProtocolBufferException asInvalidProtocolBufferException() { 97 | return new InvalidProtocolBufferException(this); 98 | } 99 | 100 | /** Construct the description string for this exception. */ 101 | private static String buildDescription(final List missingFields) { 102 | final StringBuilder description = new StringBuilder("Message missing required fields: "); 103 | boolean first = true; 104 | for (final String field : missingFields) { 105 | if (first) { 106 | first = false; 107 | } else { 108 | description.append(", "); 109 | } 110 | description.append(field); 111 | } 112 | return description.toString(); 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/main/java/us/hebi/quickbuf/Utf8Decoder.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-runtime 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf; 22 | 23 | /** 24 | * Decoder for parsing utf8 bytes into Strings 25 | * 26 | * @author Florian Enner 27 | * @since 26 Nov 2019 28 | */ 29 | public interface Utf8Decoder { 30 | 31 | public String decode(byte[] bytes, int offset, int length); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/main/java/us/hebi/quickbuf/WireFormat.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-runtime 4 | * %% 5 | * Copyright (C) 2019 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | // Protocol Buffers - Google's data interchange format 22 | // Copyright 2013 Google Inc. All rights reserved. 23 | // https://developers.google.com/protocol-buffers/ 24 | // 25 | // Redistribution and use in source and binary forms, with or without 26 | // modification, are permitted provided that the following conditions are 27 | // met: 28 | // 29 | // * Redistributions of source code must retain the above copyright 30 | // notice, this list of conditions and the following disclaimer. 31 | // * Redistributions in binary form must reproduce the above 32 | // copyright notice, this list of conditions and the following disclaimer 33 | // in the documentation and/or other materials provided with the 34 | // distribution. 35 | // * Neither the name of Google Inc. nor the names of its 36 | // contributors may be used to endorse or promote products derived from 37 | // this software without specific prior written permission. 38 | // 39 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 40 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 41 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 42 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 43 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 45 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 46 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 47 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 48 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 49 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 50 | 51 | package us.hebi.quickbuf; 52 | 53 | /** 54 | * This class is used internally by the Protocol Buffer library and generated 55 | * message implementations. It is public only because those generated messages 56 | * do not reside in the {@code protobuf} package. Others should not use this 57 | * class directly. 58 | *

59 | * This class contains constants and helper functions useful for dealing with 60 | * the Protocol Buffer wire format. 61 | * 62 | * @author kenton@google.com Kenton Varda 63 | */ 64 | final class WireFormat { 65 | 66 | // Do not allow instantiation. 67 | private WireFormat() { 68 | } 69 | 70 | static final int WIRETYPE_VARINT = 0; 71 | static final int WIRETYPE_FIXED64 = 1; 72 | static final int WIRETYPE_LENGTH_DELIMITED = 2; 73 | static final int WIRETYPE_START_GROUP = 3; 74 | static final int WIRETYPE_END_GROUP = 4; 75 | static final int WIRETYPE_FIXED32 = 5; 76 | 77 | static final int TAG_TYPE_BITS = 3; 78 | static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1; 79 | 80 | static final int MIN_BOOL_SIZE = 1; 81 | static final int FIXED_16_SIZE = 2; 82 | static final int FIXED_32_SIZE = 4; 83 | static final int FIXED_64_SIZE = 8; 84 | static final int MAX_VARINT32_SIZE = 5; 85 | static final int MAX_VARINT64_SIZE = 10; 86 | static final int MAX_VARINT_SIZE = 10; 87 | 88 | /** Given a tag value, determines the wire type (the lower 3 bits). */ 89 | static int getTagWireType(final int tag) { 90 | return tag & TAG_TYPE_MASK; 91 | } 92 | 93 | /** Given a tag value, determines the field number (the upper 29 bits). */ 94 | static int getTagFieldNumber(final int tag) { 95 | return tag >>> TAG_TYPE_BITS; 96 | } 97 | 98 | /** Makes a tag value given a field number and wire type. */ 99 | static int makeTag(final int fieldNumber, final int wireType) { 100 | return (fieldNumber << TAG_TYPE_BITS) | wireType; 101 | } 102 | 103 | /** 104 | * Count of the number of fixed64 elements that fit within the size. The value 105 | * is rounded up to match behavior and exceptions to match reading while 106 | * getBytesUntilLimit() > 0. 107 | */ 108 | static int roundedCount64(int length) { 109 | return (length + 7) / FIXED_64_SIZE; 110 | } 111 | 112 | /** 113 | * Count of the number of fixed32 elements that fit within the size. The value 114 | * is rounded up to match behavior and exceptions to match reading while 115 | * getBytesUntilLimit() > 0. 116 | */ 117 | static int roundedCount32(int length) { 118 | return (length + 3) / FIXED_32_SIZE; 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/main/resources/META-INF/native-image/reflect-config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name":"java.nio.Buffer", 4 | "fields":[{"name":"address"}] 5 | }, 6 | { 7 | "name":"java.nio.ByteBuffer", 8 | "fields":[ 9 | {"name":"hb"}, 10 | {"name":"offset"} 11 | ] 12 | }, 13 | { 14 | "name":"sun.misc.Unsafe", 15 | "allDeclaredFields":true, 16 | "queriedMethods":[ 17 | {"name":"arrayBaseOffset","parameterTypes":["java.lang.Class"] }, 18 | {"name":"arrayIndexScale","parameterTypes":["java.lang.Class"] }, 19 | {"name":"copyMemory","parameterTypes":["long","long","long"] }, 20 | {"name":"copyMemory","parameterTypes":["java.lang.Object","long","java.lang.Object","long","long"] }, 21 | {"name":"getBoolean","parameterTypes":["java.lang.Object","long"] }, 22 | {"name":"getByte","parameterTypes":["long"] }, 23 | {"name":"getByte","parameterTypes":["java.lang.Object","long"] }, 24 | {"name":"getDouble","parameterTypes":["java.lang.Object","long"] }, 25 | {"name":"getFloat","parameterTypes":["java.lang.Object","long"] }, 26 | {"name":"getInt","parameterTypes":["long"] }, 27 | {"name":"getInt","parameterTypes":["java.lang.Object","long"] }, 28 | {"name":"getLong","parameterTypes":["long"] }, 29 | {"name":"getLong","parameterTypes":["java.lang.Object","long"] }, 30 | {"name":"getObject","parameterTypes":["java.lang.Object","long"] }, 31 | {"name":"objectFieldOffset","parameterTypes":["java.lang.reflect.Field"] }, 32 | {"name":"putBoolean","parameterTypes":["java.lang.Object","long","boolean"] }, 33 | {"name":"putByte","parameterTypes":["long","byte"] }, 34 | {"name":"putByte","parameterTypes":["java.lang.Object","long","byte"] }, 35 | {"name":"putDouble","parameterTypes":["java.lang.Object","long","double"] }, 36 | {"name":"putFloat","parameterTypes":["java.lang.Object","long","float"] }, 37 | {"name":"putInt","parameterTypes":["long","int"] }, 38 | {"name":"putInt","parameterTypes":["java.lang.Object","long","int"] }, 39 | {"name":"putLong","parameterTypes":["long","long"] }, 40 | {"name":"putLong","parameterTypes":["java.lang.Object","long","long"] }, 41 | {"name":"putObject","parameterTypes":["java.lang.Object","long","java.lang.Object"] } 42 | ] 43 | } 44 | ] 45 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/main/resources/META-INF/proguard/quickbuf-runtime.pro: -------------------------------------------------------------------------------- 1 | # QuickBuffers intentionally links against newer JDK methods and provides fallbacks for older runtimes 2 | -dontwarn us.hebi.quickbuf.JdkMethods -------------------------------------------------------------------------------- /quickbuf-runtime/src/test/java/us/hebi/quickbuf/Base64Test.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * quickbuf-runtime 4 | * %% 5 | * Copyright (C) 2019 - 2020 HEBI Robotics 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | 21 | package us.hebi.quickbuf; 22 | 23 | import org.junit.Test; 24 | 25 | import java.util.ArrayList; 26 | import java.util.Base64; 27 | import java.util.List; 28 | import java.util.Random; 29 | 30 | import static org.junit.Assert.*; 31 | 32 | /** 33 | * @author Florian Enner 34 | * @since 09 Sep 2020 35 | */ 36 | public class Base64Test { 37 | 38 | @Test 39 | public void testDecodeBase64() throws Exception { 40 | for (byte[] sample : randomSamples) { 41 | String input = Base64.getEncoder().encodeToString(sample); 42 | assertArrayEquals(sample, decodeBase64(input)); 43 | } 44 | } 45 | 46 | @Test 47 | public void testDecodeBase64_noPadding() throws Exception { 48 | for (byte[] sample : randomSamples) { 49 | String input = Base64.getEncoder().encodeToString(sample).replaceAll("=", ""); 50 | assertArrayEquals(sample, decodeBase64(input)); 51 | } 52 | } 53 | 54 | @Test 55 | public void testDecodeBase64_url() throws Exception { 56 | for (byte[] sample : randomSamples) { 57 | String input = Base64.getUrlEncoder().encodeToString(sample); 58 | assertArrayEquals(sample, decodeBase64(input)); 59 | } 60 | } 61 | 62 | @Test 63 | public void testDecodeBase64_url_noPadding() throws Exception { 64 | for (byte[] sample : randomSamples) { 65 | String input = Base64.getUrlEncoder().encodeToString(sample).replaceAll("=", ""); 66 | assertArrayEquals(sample, decodeBase64(input)); 67 | } 68 | } 69 | 70 | private byte[] decodeBase64(CharSequence input) { 71 | return us.hebi.quickbuf.Base64.decodeFast(input.toString()); 72 | } 73 | 74 | 75 | private static List generateRandomSamples() { 76 | int n = 50; 77 | List samples = new ArrayList(n); 78 | Random rnd = new Random(0); 79 | for (int i = 0; i < n; i++) { 80 | byte[] bytes = new byte[i]; 81 | rnd.nextBytes(bytes); 82 | samples.add(bytes); 83 | } 84 | return samples; 85 | } 86 | 87 | private final RepeatedByte tmp = RepeatedByte.newEmptyInstance(); 88 | private static final List randomSamples = generateRandomSamples(); 89 | 90 | } 91 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/test/resources/concat/RepeatedByte.txt: -------------------------------------------------------------------------------- 1 | public RepeatedByte writeTo(ProtoSink sink) throws java.io.IOException { 2 | sink.writeRawBytes(array, 0, length); 3 | return this; 4 | } 5 | 6 | public RepeatedByte writeTo(java.io.OutputStream outputStream) throws java.io.IOException { 7 | outputStream.write(array, 0, length); 8 | return this; 9 | } 10 | 11 | public RepeatedByte writeTo(java.nio.ByteBuffer buffer) { 12 | buffer.put(array, 0, length); 13 | return this; 14 | } 15 | 16 | } // RepeatedByte -------------------------------------------------------------------------------- /quickbuf-runtime/src/test/resources/lazy/all_types_lazy.proto: -------------------------------------------------------------------------------- 1 | // Adapted from Google's javanano unit tests 2 | 3 | syntax = "proto2"; 4 | package quickbuf_unittest; 5 | 6 | option java_package = "protos.test.protobuf"; 7 | option java_outer_classname = "LazyTypes"; 8 | option java_multiple_files = false; 9 | 10 | message LazyMessage { 11 | 12 | message NestedMessage { 13 | optional int32 bb = 1; 14 | required LazyMessage recursive_message = 2; 15 | } 16 | 17 | enum NestedEnum { 18 | FOO = 1; 19 | BAR = 2; 20 | BAZ = 3; 21 | } 22 | 23 | // Singular 24 | optional string optional_string = 14; 25 | optional bytes optional_bytes = 15; 26 | 27 | optional group OptionalGroup = 16 { 28 | optional int32 a = 17; 29 | } 30 | 31 | optional NestedMessage optional_nested_message = 18; 32 | 33 | // Repeated 34 | repeated int32 repeated_int32 = 31; 35 | repeated int64 repeated_int64 = 32; 36 | repeated uint32 repeated_uint32 = 33; 37 | repeated uint64 repeated_uint64 = 34; 38 | repeated sint32 repeated_sint32 = 35; 39 | repeated sint64 repeated_sint64 = 36; 40 | repeated fixed32 repeated_fixed32 = 37; 41 | repeated fixed64 repeated_fixed64 = 38; 42 | repeated sfixed32 repeated_sfixed32 = 39; 43 | repeated sfixed64 repeated_sfixed64 = 40; 44 | repeated float repeated_float = 41; 45 | repeated double repeated_double = 42; 46 | repeated bool repeated_bool = 43; 47 | repeated string repeated_string = 44; 48 | repeated bytes repeated_bytes = 45; 49 | 50 | repeated group RepeatedGroup = 46 { 51 | optional int32 a = 47; 52 | } 53 | 54 | repeated NestedMessage repeated_nested_message = 48; 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/test/resources/lazy/struct.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option cc_enable_arenas = true; 36 | option go_package = "google.golang.org/protobuf/types/known/structpb"; 37 | option java_package = "com.google.protobuf"; 38 | option java_outer_classname = "StructProto"; 39 | option java_multiple_files = true; 40 | option objc_class_prefix = "GPB"; 41 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 42 | 43 | // `Struct` represents a structured data value, consisting of fields 44 | // which map to dynamically typed values. In some languages, `Struct` 45 | // might be supported by a native representation. For example, in 46 | // scripting languages like JS a struct is represented as an 47 | // object. The details of that representation are described together 48 | // with the proto support for the language. 49 | // 50 | // The JSON representation for `Struct` is JSON object. 51 | message Struct { 52 | // Unordered map of dynamically typed values. 53 | map fields = 1; 54 | } 55 | 56 | // `Value` represents a dynamically typed value which can be either 57 | // null, a number, a string, a boolean, a recursive struct value, or a 58 | // list of values. A producer of value is expected to set one of these 59 | // variants. Absence of any variant indicates an error. 60 | // 61 | // The JSON representation for `Value` is JSON value. 62 | message Value { 63 | // The kind of value. 64 | oneof kind { 65 | // Represents a null value. 66 | NullValue null_value = 1; 67 | // Represents a double value. 68 | double number_value = 2; 69 | // Represents a string value. 70 | string string_value = 3; 71 | // Represents a boolean value. 72 | bool bool_value = 4; 73 | // Represents a structured value. 74 | Struct struct_value = 5; 75 | // Represents a repeated `Value`. 76 | ListValue list_value = 6; 77 | } 78 | } 79 | 80 | // `NullValue` is a singleton enumeration to represent the null value for the 81 | // `Value` type union. 82 | // 83 | // The JSON representation for `NullValue` is JSON `null`. 84 | enum NullValue { 85 | // Null value. 86 | NULL_VALUE = 0; 87 | } 88 | 89 | // `ListValue` is a wrapper around a repeated field of values. 90 | // 91 | // The JSON representation for `ListValue` is JSON array. 92 | message ListValue { 93 | // Repeated field of dynamically typed values. 94 | repeated Value values = 1; 95 | } 96 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/test/resources/protos/namespaces.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | package quickbuf_unittest_import; 3 | 4 | option java_package = "protos.test.protobuf.external"; 5 | option java_outer_classname = "NamespacesOuterClass"; 6 | option java_multiple_files = true; 7 | 8 | message ImportMessage { 9 | optional int32 d = 1; 10 | 11 | message NestedImportMessage { 12 | optional int32 e = 1; 13 | } 14 | 15 | } 16 | 17 | enum ImportEnum { 18 | IMPORT_FOO = 7; 19 | IMPORT_BAR = 8; 20 | IMPORT_BAZ = 9; 21 | } -------------------------------------------------------------------------------- /quickbuf-runtime/src/test/resources/protos/namespaces_default_package.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | option java_package = "protos.test.protobuf.nopackage"; 4 | 5 | message NoPackageImportMessage { 6 | optional int32 d = 1; 7 | 8 | message NoPackageNestedImportMessage { 9 | optional int32 e = 1; 10 | } 11 | 12 | } 13 | 14 | message ImportingMessage { 15 | optional NoPackageImportMessage import_message = 1; 16 | optional .NoPackageImportMessage.NoPackageNestedImportMessage nested_import_message = 2; 17 | } 18 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/test/resources/protos/namespaces_import.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | package quickbuf_unittest; 3 | 4 | import "namespaces.proto"; 5 | 6 | option java_package = "protos.test.protobuf"; 7 | option java_outer_classname = "ImportingOuterClass"; 8 | option java_multiple_files = true; 9 | 10 | message ContainerMessage { 11 | 12 | message NestedMessage { 13 | optional int32 bb = 1; 14 | } 15 | 16 | enum NestedEnum { 17 | FOO = 1; 18 | BAR = 2; 19 | BAZ = 100; 20 | } 21 | 22 | // Defined inside message 23 | optional NestedMessage optional_nested_message = 1; 24 | optional NestedEnum optional_nested_enum = 2; 25 | 26 | // Defined in this file 27 | optional ForeignMessage optional_foreign_message = 3; 28 | optional ForeignEnum optional_foreign_enum = 4; 29 | 30 | // Defined in a different file and in a different namespace 31 | optional quickbuf_unittest_import.ImportMessage optional_import_message = 5; 32 | optional quickbuf_unittest_import.ImportEnum optional_import_enum = 6; 33 | 34 | // Defined in a different file as a nested message 35 | optional quickbuf_unittest_import.ImportMessage.NestedImportMessage optional_nested_import_message = 7; 36 | 37 | } 38 | 39 | message ForeignMessage { 40 | optional int32 c = 1; 41 | } 42 | 43 | enum ForeignEnum { 44 | FOREIGN_FOO = 4; 45 | FOREIGN_BAR = 5; 46 | FOREIGN_BAZ = 6; 47 | } -------------------------------------------------------------------------------- /quickbuf-runtime/src/test/resources/protos/unittest_default_package_imports.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package unittest_packages; 4 | import "namespaces_default_package.proto"; 5 | 6 | option java_package = "protos.test.protobuf.nopackage"; 7 | option java_outer_classname = "ImportingOuterClass"; 8 | option java_multiple_files = false; 9 | 10 | message ForeignDefaultPackageImport { 11 | optional NoPackageImportMessage import_message = 1; 12 | optional .NoPackageImportMessage.NoPackageNestedImportMessage nested_import_message = 2; 13 | } -------------------------------------------------------------------------------- /quickbuf-runtime/src/test/resources/protos/unittest_field_order.proto: -------------------------------------------------------------------------------- 1 | // A message with all types in random order and randomized ids 2 | // to check how Google orders items 3 | 4 | syntax = "proto2"; 5 | package quickbuf_unittest; 6 | 7 | option java_package = "protos.test.protobuf"; 8 | option java_multiple_files = false; 9 | 10 | message ExampleMessage { 11 | optional int32 field1 = 1; 12 | optional int32 field2 = 3; 13 | optional string field3 = 4; 14 | optional double field4 = 2; 15 | optional int64 field5 = 5; 16 | } 17 | 18 | message TestFieldOrder { 19 | 20 | message NestedMessage { 21 | optional int32 bb = 1; 22 | } 23 | 24 | enum NestedEnum { 25 | FOO = 1; 26 | BAR = 2; 27 | BAZ = 3; 28 | } 29 | 30 | repeated int32 field_01_id31 = 31; 31 | repeated int64 field_02_id32 = 32; 32 | optional double field_03_id12 = 12; 33 | repeated NestedMessage field_04_id48 = 48; 34 | optional int32 field_05_id01 = 1; 35 | optional NestedMessage field_06_id18 = 18; 36 | repeated float field_07_id41 = 41; 37 | optional int64 field_08_id02 = 2; 38 | repeated sint64 field_09_id36 = 36; 39 | repeated NestedEnum field_10_id51 = 51; 40 | repeated sfixed32 field_11_id39 = 39; 41 | repeated uint32 field_12_id33 = 33; 42 | optional uint32 field_13_id03 = 3; 43 | optional uint64 field_14_id04 = 4; 44 | optional NestedEnum field_15_id21 = 21; 45 | repeated sint32 field_16_id35 = 35; 46 | optional sint32 field_17_id05 = 5; 47 | optional sint64 field_18_id06 = 6; 48 | optional fixed32 field_19_id07 = 7; 49 | repeated int32 field_20_id87 = 87 [packed = true]; 50 | optional bytes field_21_id15 = 15; 51 | optional fixed64 field_22_id08 = 8; 52 | repeated fixed64 field_23_id38 = 38; 53 | optional sfixed32 field_24_id09 = 9; 54 | repeated sfixed64 field_25_id88 = 88 [packed = true]; 55 | optional sfixed64 field_26_id10 = 10; 56 | repeated bool field_27_id43 = 43; 57 | repeated fixed32 field_28_id37 = 37; 58 | repeated sfixed64 field_29_id40 = 40; 59 | repeated uint64 field_30_id34 = 34; 60 | optional float field_31_id11 = 11; 61 | repeated bytes field_32_id45 = 45; 62 | repeated string field_33_id44 = 44; 63 | repeated double field_34_id42 = 42; 64 | optional bool field_35_id13 = 13; 65 | optional string field_36_id14 = 14; 66 | 67 | } 68 | 69 | message MessageWithMultibyteNumbers { 70 | 71 | optional int32 tag_size_1 = 1; // 2^1 72 | optional int32 tag_size_2 = 16; // 2^3 73 | optional int32 tag_size_3 = 2048; // 2^10 74 | optional int32 tag_size_4 = 262144; // 2^17 75 | optional int32 tag_size_5 = 33554432; // 2^24 76 | optional int32 tag_size_max = 536870911; // 2^29 - 1 (highest allowed field id) 77 | 78 | } -------------------------------------------------------------------------------- /quickbuf-runtime/src/test/resources/protos/unittest_repeated_packables.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | // Author: maxtroy@google.com (Max Cai) 32 | 33 | syntax = "proto2"; 34 | package protobuf_unittest; 35 | 36 | option java_package = "protos.test.protobuf"; 37 | option java_outer_classname = "RepeatedPackables"; 38 | 39 | enum Enum { 40 | OPTION_ONE = 1; 41 | OPTION_TWO = 2; 42 | } 43 | 44 | // Two almost identical messages with all packable repeated field types. 45 | // One with none marked as packed and the other all packed. For 46 | // compatibility, they should be able to parse each other's serialized 47 | // forms. 48 | 49 | message NonPacked { 50 | 51 | // All packable types, none marked as packed. 52 | 53 | repeated int32 int32s = 1; 54 | repeated int64 int64s = 2; 55 | repeated uint32 uint32s = 3; 56 | repeated uint64 uint64s = 4; 57 | repeated sint32 sint32s = 5; 58 | repeated sint64 sint64s = 6; 59 | repeated fixed32 fixed32s = 7; 60 | repeated fixed64 fixed64s = 8; 61 | repeated sfixed32 sfixed32s = 9; 62 | repeated sfixed64 sfixed64s = 10; 63 | repeated float floats = 11; 64 | repeated double doubles = 12; 65 | repeated bool bools = 13; 66 | repeated Enum enums = 14; 67 | 68 | // Noise for testing merged deserialization. 69 | optional int32 noise = 15; 70 | 71 | } 72 | 73 | message Packed { 74 | 75 | // All packable types, all matching the field numbers in NonPacked, 76 | // all marked as packed. 77 | 78 | repeated int32 int32s = 1 [ packed = true ]; 79 | repeated int64 int64s = 2 [ packed = true ]; 80 | repeated uint32 uint32s = 3 [ packed = true ]; 81 | repeated uint64 uint64s = 4 [ packed = true ]; 82 | repeated sint32 sint32s = 5 [ packed = true ]; 83 | repeated sint64 sint64s = 6 [ packed = true ]; 84 | repeated fixed32 fixed32s = 7 [ packed = true ]; 85 | repeated fixed64 fixed64s = 8 [ packed = true ]; 86 | repeated sfixed32 sfixed32s = 9 [ packed = true ]; 87 | repeated sfixed64 sfixed64s = 10 [ packed = true ]; 88 | repeated float floats = 11 [ packed = true ]; 89 | repeated double doubles = 12 [ packed = true ]; 90 | repeated bool bools = 13 [ packed = true ]; 91 | repeated Enum enums = 14 [ packed = true ]; 92 | 93 | // Noise for testing merged deserialization. 94 | optional int32 noise = 15; 95 | 96 | } 97 | -------------------------------------------------------------------------------- /quickbuf-runtime/src/test/resources/protos/unittest_required.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | // Author: maxtroy@google.com (Max Cai) 32 | 33 | syntax = "proto2"; 34 | package quickbuf_unittest_import; 35 | 36 | option java_package = "protos.test.protobuf"; 37 | 38 | message SimpleMessage { 39 | required int32 required_field = 1 [deprecated = true]; 40 | } 41 | 42 | message NestedRequiredMessage { 43 | optional SimpleMessage optional_simple_message = 1; 44 | } 45 | 46 | message TestAllTypesRequired { 47 | 48 | enum NestedEnum { 49 | FOO = 1; 50 | BAR = 2; 51 | BAZ = 3; 52 | } 53 | 54 | required int32 required_int32 = 1; 55 | required int64 required_int64 = 2; 56 | required uint32 required_uint32 = 3; 57 | required uint64 required_uint64 = 4; 58 | required sint32 required_sint32 = 5; 59 | required sint64 required_sint64 = 6; 60 | required fixed32 required_fixed32 = 7; 61 | required fixed64 required_fixed64 = 8; 62 | required sfixed32 required_sfixed32 = 9; 63 | required sfixed64 required_sfixed64 = 10; 64 | required float required_float = 11; 65 | required double required_double = 12; 66 | required bool required_bool = 13; 67 | required string required_string = 14; 68 | required bytes required_bytes = 15; 69 | 70 | required NestedEnum required_nested_enum = 21; 71 | required SimpleMessage required_nested_message = 22; 72 | 73 | } -------------------------------------------------------------------------------- /settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | ossrh 8 | ${env.MAVEN_USERNAME} 9 | ${env.MAVEN_PASSWORD} 10 | 11 | 12 | 13 | 14 | 15 | 16 | true 17 | 18 | 19 | ${env.GPG_KEYNAME} 20 | ${env.GPG_PASSPHRASE} 21 | 22 | 23 | 24 | 25 | --------------------------------------------------------------------------------