├── .github ├── README.md ├── renovate.json └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── binary ├── build.gradle.kts └── src │ ├── main │ └── java │ │ └── alpine │ │ └── binary │ │ ├── ArrayBinaryCodec.java │ │ ├── ArrayBinaryCodecs.java │ │ ├── BinaryCodec.java │ │ ├── BinaryTemplate.java │ │ ├── Either.java │ │ ├── EitherBinaryCodec.java │ │ ├── ListBinaryCodec.java │ │ ├── MapBinaryCodec.java │ │ ├── MappedBinaryCodec.java │ │ ├── NullableBinaryCodec.java │ │ ├── OptionalBinaryCodec.java │ │ ├── PrimitiveBinaryCodecs.java │ │ ├── StandardBinaryCodecs.java │ │ ├── StringBinaryCodec.java │ │ └── VariableBinaryCodecs.java │ └── test │ └── java │ └── alpine │ └── binary │ └── CodecTest.java ├── build.gradle.kts ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle.kts /.github/README.md: -------------------------------------------------------------------------------- 1 | # alpine 2 | A binary(JSON soon™) serialization library for Java. 3 | 4 | ![](https://wakatime.com/badge/github/mudkipdev/alpine.svg) 5 | 6 | ## Installation 7 | ### Binary 8 | 9 |
10 | Gradle (Kotlin) 11 |
12 | 13 | ```kts 14 | dependencies { 15 | implementation("dev.mudkip:alpine-binary:0.1.1") 16 | implementation("io.netty:netty-buffer:4.2.0.Final") 17 | } 18 | ``` 19 | 20 |
21 | 22 |
23 | Gradle (Groovy) 24 |
25 | 26 | ```groovy 27 | dependencies { 28 | implementation 'dev.mudkip:alpine-binary:0.1.1' 29 | implementation 'io.netty:netty-buffer:4.2.0.Final' 30 | } 31 | ``` 32 | 33 |
34 | 35 |
36 | Maven 37 |
38 | 39 | ```xml 40 | 41 | dev.mudkip 42 | alpine-binary 43 | 0.1.1 44 | 45 | 46 | 47 | io.netty 48 | netty-buffer 49 | 4.2.0.Final 50 | 51 | ``` 52 | 53 |
54 | 55 | ## Documentation 56 | The core primitive of Alpine is a codec. A codec is something that can encode and decode an object from a byte buffer. 57 | Netty's `ByteBuf` is used for this, however you don't need any other parts of Netty to take advantage of this system. 58 | 59 | You can easily create an `Integer` codec like this: 60 | ```java 61 | public static final BinaryCodec INTEGER = new BinaryCodec<>() { 62 | @Override 63 | public Integer read(ByteBuf buffer) { 64 | return buffer.readInt(); 65 | } 66 | 67 | @Override 68 | public void write(ByteBuf buffer, Integer value) { 69 | buffer.writeInt(value); 70 | } 71 | }; 72 | ``` 73 | 74 | ### Built-in codecs 75 | There are already many built-in codecs exposed through the `BinaryCodec` class, a partial list is available below: 76 | 77 | | Java Type | Codec | Notes | 78 | |-------------|-------------------|-------------------------------------------------------------------------------------| 79 | | `boolean` | `BOOLEAN` | Encoded as `0` or `1`. | 80 | | `byte` | `BYTE` | | 81 | | `char` | `CHARACTER` | Encoded as a two-byte UTF-16 character. | 82 | | `short` | `SHORT` | | 83 | | `int` | `INTEGER` | | 84 | | `int` | `VARINT` | [LEB128](https://en.wikipedia.org/wiki/LEB128) encoded. Uses between 1 and 5 bytes. | 85 | | `long` | `LONG` | | 86 | | `float` | `FLOAT` | | 87 | | `double` | `DOUBLE` | | 88 | | `String` | `STRING` | Encoded as UTF-8. Length-prefixed with a varint. | 89 | | `UUID` | `UUID` | Encoded as two 64-bit integers. | 90 | 91 | ### Templates 92 | Complex composite types can be created using the template syntax: 93 | 94 | ```java 95 | public record User(String name, Gender gender, int age) { 96 | public static final BinaryCodec CODEC = BinaryTemplate.of( 97 | STRING, User::name, 98 | Gender.CODEC, User::gender, 99 | INTEGER, User::age, 100 | // include up to 20 fields (total) 101 | User::new); 102 | } 103 | ``` 104 | 105 | ### Transformations 106 | Use these methods to map a codec to another type. 107 | - `.array()` → `T[]` 108 | - `.list()` → `List` 109 | - `.nullable()` → `@Nullable T` 110 | - `.optional()` → `Optional` 111 | - `.map(Function, Function)` → `U` 112 | 113 | ### There's more! 114 | - Use `BinaryCodec.ordinal(Example.class)` to represent an enum. 115 | - Use `BinaryCodec.unit(Example::new)` to represent singleton types. 116 | - Use `BinaryCodec.map(keyCodec, valueCodec)` to represent a hash map. 117 | - Use `BinaryCodec.either(leftCodec, rightCodec)` to represent something which can be one of two types. 118 | - Use `BinaryCodec.of(Function, BiConsumer)` for an easier way to create a codec, especially if using the `::` syntax. 119 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended" 5 | ], 6 | "rangeStrategy": "bump", 7 | "assignees": [ 8 | "mudkipdev" 9 | ] 10 | } -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | 13 | - name: Set up Java 14 | uses: actions/setup-java@v4 15 | with: 16 | distribution: temurin 17 | java-version: 21 18 | 19 | - name: Set up Gradle 20 | uses: gradle/actions/setup-gradle@v4 21 | 22 | - name: Add execute permissions for gradlew 23 | run: chmod +x gradlew 24 | 25 | - name: Build with Gradle 26 | run: ./gradlew build 27 | 28 | - name: Upload artifact 29 | uses: actions/upload-artifact@v4 30 | with: 31 | name: alpine 32 | path: | 33 | binary/build/libs/alpine-*.*.*.jar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | gradle.properties 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### IntelliJ IDEA ### 9 | .idea 10 | *.iws 11 | *.iml 12 | *.ipr 13 | out/ 14 | !**/src/main/**/out/ 15 | !**/src/test/**/out/ 16 | 17 | ### Eclipse ### 18 | .apt_generated 19 | .classpath 20 | .factorypath 21 | .project 22 | .settings 23 | .springBeans 24 | .sts4-cache 25 | bin/ 26 | !**/src/main/**/bin/ 27 | !**/src/test/**/bin/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | 39 | ### Mac OS ### 40 | .DS_Store -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 mudkip 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /binary/build.gradle.kts: -------------------------------------------------------------------------------- 1 | description = "A binary serialization library for Java." 2 | 3 | dependencies { 4 | compileOnly("io.netty:netty-buffer:4.2.2.Final") 5 | testImplementation("io.netty:netty-buffer:4.2.2.Final") 6 | } -------------------------------------------------------------------------------- /binary/src/main/java/alpine/binary/ArrayBinaryCodec.java: -------------------------------------------------------------------------------- 1 | package alpine.binary; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | /** 6 | * A binary codec which serializes a sequence of values as an array. 7 | * @param parent The binary codec to serialize the values with. 8 | * @param The element type. 9 | * @author mudkip 10 | */ 11 | record ArrayBinaryCodec(BinaryCodec parent) implements BinaryCodec { 12 | @SuppressWarnings("unchecked") 13 | @Override 14 | public T[] read(ByteBuf buffer) { 15 | var length = VARINT.read(buffer); 16 | var data = new Object[length]; 17 | 18 | for (var index = 0; index < length; index++) { 19 | data[index] = this.parent.read(buffer); 20 | } 21 | 22 | return (T[]) data; 23 | } 24 | 25 | @Override 26 | public void write(ByteBuf buffer, T[] array) { 27 | VARINT.write(buffer, array.length); 28 | 29 | for (var value : array) { 30 | this.parent.write(buffer, value); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /binary/src/main/java/alpine/binary/ArrayBinaryCodecs.java: -------------------------------------------------------------------------------- 1 | package alpine.binary; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | /** 6 | * Built-in binary codecs for various primitive arrays. 7 | * @author mudkip 8 | */ 9 | interface ArrayBinaryCodecs { 10 | BinaryCodec BOOLEAN_ARRAY = new BinaryCodec<>() { 11 | @Override 12 | public boolean[] read(ByteBuf buffer) { 13 | var length = VARINT.read(buffer); 14 | var data = new boolean[length]; 15 | 16 | for (var index = 0; index < length; index++) { 17 | data[index] = BOOLEAN.read(buffer); 18 | } 19 | 20 | return data; 21 | } 22 | 23 | @Override 24 | public void write(ByteBuf buffer, boolean[] array) { 25 | VARINT.write(buffer, array.length); 26 | 27 | for (var value : array) { 28 | BOOLEAN.write(buffer, value); 29 | } 30 | } 31 | }; 32 | 33 | BinaryCodec CHARACTER_ARRAY = new BinaryCodec<>() { 34 | @Override 35 | public char[] read(ByteBuf buffer) { 36 | var length = VARINT.read(buffer); 37 | var data = new char[length]; 38 | 39 | for (var index = 0; index < length; index++) { 40 | data[index] = CHARACTER.read(buffer); 41 | } 42 | 43 | return data; 44 | } 45 | 46 | @Override 47 | public void write(ByteBuf buffer, char[] array) { 48 | VARINT.write(buffer, array.length); 49 | 50 | for (var value : array) { 51 | CHARACTER.write(buffer, value); 52 | } 53 | } 54 | }; 55 | 56 | BinaryCodec BYTE_ARRAY = new BinaryCodec<>() { 57 | @Override 58 | public byte[] read(ByteBuf buffer) { 59 | var length = VARINT.read(buffer); 60 | var data = new byte[length]; 61 | 62 | for (var index = 0; index < length; index++) { 63 | data[index] = BYTE.read(buffer); 64 | } 65 | 66 | return data; 67 | } 68 | 69 | @Override 70 | public void write(ByteBuf buffer, byte[] array) { 71 | VARINT.write(buffer, array.length); 72 | buffer.writeBytes(array); 73 | } 74 | }; 75 | 76 | BinaryCodec SHORT_ARRAY = new BinaryCodec<>() { 77 | @Override 78 | public short[] read(ByteBuf buffer) { 79 | var length = VARINT.read(buffer); 80 | var data = new short[length]; 81 | 82 | for (var index = 0; index < length; index++) { 83 | data[index] = SHORT.read(buffer); 84 | } 85 | 86 | return data; 87 | } 88 | 89 | @Override 90 | public void write(ByteBuf buffer, short[] array) { 91 | VARINT.write(buffer, array.length); 92 | 93 | for (var value : array) { 94 | SHORT.write(buffer, value); 95 | } 96 | } 97 | }; 98 | 99 | BinaryCodec INTEGER_ARRAY = new BinaryCodec<>() { 100 | @Override 101 | public int[] read(ByteBuf buffer) { 102 | var length = VARINT.read(buffer); 103 | var data = new int[length]; 104 | 105 | for (var index = 0; index < length; index++) { 106 | data[index] = INTEGER.read(buffer); 107 | } 108 | 109 | return data; 110 | } 111 | 112 | @Override 113 | public void write(ByteBuf buffer, int[] array) { 114 | VARINT.write(buffer, array.length); 115 | 116 | for (var value : array) { 117 | INTEGER.write(buffer, value); 118 | } 119 | } 120 | }; 121 | 122 | BinaryCodec LONG_ARRAY = new BinaryCodec<>() { 123 | @Override 124 | public long[] read(ByteBuf buffer) { 125 | var length = VARINT.read(buffer); 126 | var data = new long[length]; 127 | 128 | for (var index = 0; index < length; index++) { 129 | data[index] = LONG.read(buffer); 130 | } 131 | 132 | return data; 133 | } 134 | 135 | @Override 136 | public void write(ByteBuf buffer, long[] array) { 137 | VARINT.write(buffer, array.length); 138 | 139 | for (var value : array) { 140 | LONG.write(buffer, value); 141 | } 142 | } 143 | }; 144 | 145 | BinaryCodec FLOAT_ARRAY = new BinaryCodec<>() { 146 | @Override 147 | public float[] read(ByteBuf buffer) { 148 | var length = VARINT.read(buffer); 149 | var data = new float[length]; 150 | 151 | for (var index = 0; index < length; index++) { 152 | data[index] = FLOAT.read(buffer); 153 | } 154 | 155 | return data; 156 | } 157 | 158 | @Override 159 | public void write(ByteBuf buffer, float[] array) { 160 | VARINT.write(buffer, array.length); 161 | 162 | for (var value : array) { 163 | FLOAT.write(buffer, value); 164 | } 165 | } 166 | }; 167 | 168 | BinaryCodec DOUBLE_ARRAY = new BinaryCodec<>() { 169 | @Override 170 | public double[] read(ByteBuf buffer) { 171 | var length = VARINT.read(buffer); 172 | var data = new double[length]; 173 | 174 | for (var index = 0; index < length; index++) { 175 | data[index] = DOUBLE.read(buffer); 176 | } 177 | 178 | return data; 179 | } 180 | 181 | @Override 182 | public void write(ByteBuf buffer, double[] array) { 183 | VARINT.write(buffer, array.length); 184 | 185 | for (var value : array) { 186 | DOUBLE.write(buffer, value); 187 | } 188 | } 189 | }; 190 | } 191 | -------------------------------------------------------------------------------- /binary/src/main/java/alpine/binary/BinaryCodec.java: -------------------------------------------------------------------------------- 1 | package alpine.binary; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | import java.nio.charset.Charset; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Optional; 10 | import java.util.function.BiConsumer; 11 | import java.util.function.Function; 12 | import java.util.function.Supplier; 13 | 14 | /** 15 | * Represents something that can encode and decode a value. 16 | * @param The value type. 17 | * @author mudkip 18 | */ 19 | public interface BinaryCodec extends 20 | PrimitiveBinaryCodecs, 21 | StandardBinaryCodecs, 22 | ArrayBinaryCodecs, 23 | VariableBinaryCodecs { 24 | /** 25 | * Decodes the value from the buffer. 26 | * @param buffer The binary buffer. 27 | * @return The value read from the buffer. 28 | */ 29 | T read(ByteBuf buffer); 30 | 31 | /** 32 | * Encodes the value to the buffer. 33 | * @param buffer The binary buffer. 34 | * @param value The value being written to the buffer. 35 | */ 36 | void write(ByteBuf buffer, T value); 37 | 38 | /** 39 | * Maps this codec to a different type using the provided functions {@code to} and {@code from}. 40 | * @param to The function to transform the original value to a new type. 41 | * @param from The function to transform the new type to the original type. 42 | * @return The mapped codec. 43 | * @param The new value type. 44 | */ 45 | default BinaryCodec map(Function to, Function from) { 46 | return new MappedBinaryCodec<>(this, to, from); 47 | } 48 | 49 | default BinaryCodec> optional() { 50 | return new OptionalBinaryCodec<>(this); 51 | } 52 | 53 | default BinaryCodec<@Nullable T> nullable() { 54 | return new NullableBinaryCodec<>(this); 55 | } 56 | 57 | default BinaryCodec> list() { 58 | return new ListBinaryCodec<>(this); 59 | } 60 | 61 | default BinaryCodec array() { 62 | return new ArrayBinaryCodec<>(this); 63 | } 64 | 65 | /** 66 | * Creates a codec based on the {@code reader} and {@code writer} functions. 67 | * @param reader The function to read the value from the buffer. 68 | * @param writer The function to write the value to the buffer. 69 | * @return The newly created codec. 70 | * @param The value type. 71 | */ 72 | static BinaryCodec of(Function reader, BiConsumer writer) { 73 | return new BinaryCodec<>() { 74 | @Override 75 | public T read(ByteBuf buffer) { 76 | return reader.apply(buffer); 77 | } 78 | 79 | @Override 80 | public void write(ByteBuf buffer, T value) { 81 | writer.accept(buffer, value); 82 | } 83 | }; 84 | } 85 | 86 | static BinaryCodec unit(Supplier supplier) { 87 | return of(buffer -> supplier.get(), (buffer, value) -> {}); 88 | } 89 | 90 | static BinaryCodec> either(BinaryCodec leftCodec, BinaryCodec rightCodec) { 91 | return new EitherBinaryCodec<>(leftCodec, rightCodec); 92 | } 93 | 94 | static BinaryCodec> map(BinaryCodec keyCodec, BinaryCodec valueCodec) { 95 | return new MapBinaryCodec<>(keyCodec, valueCodec); 96 | } 97 | 98 | static > BinaryCodec ordinal(Class enumClass) { 99 | return VARINT.map(ordinal -> enumClass.getEnumConstants()[ordinal], Enum::ordinal); 100 | } 101 | 102 | static BinaryCodec string(Charset charset) { 103 | return new StringBinaryCodec(charset); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /binary/src/main/java/alpine/binary/BinaryTemplate.java: -------------------------------------------------------------------------------- 1 | package alpine.binary; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | import java.util.function.Function; 6 | import java.util.function.Supplier; 7 | 8 | /** 9 | * @author mudkip 10 | */ 11 | public interface BinaryTemplate { 12 | @FunctionalInterface 13 | interface F1 { 14 | R apply(P1 p1); 15 | } 16 | 17 | @FunctionalInterface 18 | interface F2 { 19 | R apply(P1 p1, P2 p2); 20 | } 21 | 22 | @FunctionalInterface 23 | interface F3 { 24 | R apply(P1 p1, P2 p2, P3 p3); 25 | } 26 | 27 | @FunctionalInterface 28 | interface F4 { 29 | R apply(P1 p1, P2 p2, P3 p3, P4 p4); 30 | } 31 | 32 | @FunctionalInterface 33 | interface F5 { 34 | R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5); 35 | } 36 | 37 | @FunctionalInterface 38 | interface F6 { 39 | R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6); 40 | } 41 | 42 | @FunctionalInterface 43 | interface F7 { 44 | R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7); 45 | } 46 | 47 | @FunctionalInterface 48 | interface F8 { 49 | R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8); 50 | } 51 | 52 | @FunctionalInterface 53 | interface F9 { 54 | R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9); 55 | } 56 | 57 | @FunctionalInterface 58 | interface F10 { 59 | R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10); 60 | } 61 | 62 | @FunctionalInterface 63 | interface F11 { 64 | R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11); 65 | } 66 | 67 | @FunctionalInterface 68 | interface F12 { 69 | R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12); 70 | } 71 | 72 | @FunctionalInterface 73 | interface F13 { 74 | R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12, P13 p13); 75 | } 76 | 77 | @FunctionalInterface 78 | interface F14 { 79 | R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12, P13 p13, P14 p14); 80 | } 81 | 82 | @FunctionalInterface 83 | interface F15 { 84 | R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12, P13 p13, P14 p14, P15 p15); 85 | } 86 | 87 | @FunctionalInterface 88 | interface F16 { 89 | R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12, P13 p13, P14 p14, P15 p15, P16 p16); 90 | } 91 | 92 | @FunctionalInterface 93 | interface F17 { 94 | R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12, P13 p13, P14 p14, P15 p15, P16 p16, P17 p17); 95 | } 96 | 97 | @FunctionalInterface 98 | interface F18 { 99 | R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12, P13 p13, P14 p14, P15 p15, P16 p16, P17 p17, P18 p18); 100 | } 101 | 102 | @FunctionalInterface 103 | interface F19 { 104 | R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12, P13 p13, P14 p14, P15 p15, P16 p16, P17 p17, P18 p18, P19 p19); 105 | } 106 | 107 | @FunctionalInterface 108 | interface F20 { 109 | R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12, P13 p13, P14 p14, P15 p15, P16 p16, P17 p17, P18 p18, P19 p19, P20 p20); 110 | } 111 | 112 | static BinaryCodec of(Supplier reader) { 113 | return BinaryCodec.unit(reader); 114 | } 115 | 116 | static BinaryCodec of( 117 | BinaryCodec p1, Function g1, 118 | F1 reader 119 | ) { 120 | return new BinaryCodec<>() { 121 | @Override 122 | public void write(ByteBuf buffer, R value) { 123 | p1.write(buffer, g1.apply(value)); 124 | } 125 | 126 | @Override 127 | public R read(ByteBuf buffer) { 128 | return reader.apply(p1.read(buffer)); 129 | } 130 | }; 131 | } 132 | 133 | static BinaryCodec of( 134 | BinaryCodec p1, Function g1, 135 | BinaryCodec p2, Function g2, 136 | F2 reader 137 | ) { 138 | return new BinaryCodec<>() { 139 | @Override 140 | public void write(ByteBuf buffer, R value) { 141 | p1.write(buffer, g1.apply(value)); 142 | p2.write(buffer, g2.apply(value)); 143 | } 144 | 145 | @Override 146 | public R read(ByteBuf buffer) { 147 | return reader.apply( 148 | p1.read(buffer), 149 | p2.read(buffer)); 150 | } 151 | }; 152 | } 153 | 154 | static BinaryCodec of( 155 | BinaryCodec p1, Function g1, 156 | BinaryCodec p2, Function g2, 157 | BinaryCodec p3, Function g3, 158 | F3 reader 159 | ) { 160 | return new BinaryCodec<>() { 161 | @Override 162 | public void write(ByteBuf buffer, R value) { 163 | p1.write(buffer, g1.apply(value)); 164 | p2.write(buffer, g2.apply(value)); 165 | p3.write(buffer, g3.apply(value)); 166 | } 167 | 168 | @Override 169 | public R read(ByteBuf buffer) { 170 | return reader.apply( 171 | p1.read(buffer), 172 | p2.read(buffer), 173 | p3.read(buffer)); 174 | } 175 | }; 176 | } 177 | 178 | static BinaryCodec of( 179 | BinaryCodec p1, Function g1, 180 | BinaryCodec p2, Function g2, 181 | BinaryCodec p3, Function g3, 182 | BinaryCodec p4, Function g4, 183 | F4 reader 184 | ) { 185 | return new BinaryCodec<>() { 186 | @Override 187 | public void write(ByteBuf buffer, R value) { 188 | p1.write(buffer, g1.apply(value)); 189 | p2.write(buffer, g2.apply(value)); 190 | p3.write(buffer, g3.apply(value)); 191 | p4.write(buffer, g4.apply(value)); 192 | } 193 | 194 | @Override 195 | public R read(ByteBuf buffer) { 196 | return reader.apply( 197 | p1.read(buffer), 198 | p2.read(buffer), 199 | p3.read(buffer), 200 | p4.read(buffer)); 201 | } 202 | }; 203 | } 204 | 205 | static BinaryCodec of( 206 | BinaryCodec p1, Function g1, 207 | BinaryCodec p2, Function g2, 208 | BinaryCodec p3, Function g3, 209 | BinaryCodec p4, Function g4, 210 | BinaryCodec p5, Function g5, 211 | F5 reader 212 | ) { 213 | return new BinaryCodec<>() { 214 | @Override 215 | public void write(ByteBuf buffer, R value) { 216 | p1.write(buffer, g1.apply(value)); 217 | p2.write(buffer, g2.apply(value)); 218 | p3.write(buffer, g3.apply(value)); 219 | p4.write(buffer, g4.apply(value)); 220 | p5.write(buffer, g5.apply(value)); 221 | } 222 | 223 | @Override 224 | public R read(ByteBuf buffer) { 225 | return reader.apply( 226 | p1.read(buffer), 227 | p2.read(buffer), 228 | p3.read(buffer), 229 | p4.read(buffer), 230 | p5.read(buffer)); 231 | } 232 | }; 233 | } 234 | 235 | static BinaryCodec of( 236 | BinaryCodec p1, Function g1, 237 | BinaryCodec p2, Function g2, 238 | BinaryCodec p3, Function g3, 239 | BinaryCodec p4, Function g4, 240 | BinaryCodec p5, Function g5, 241 | BinaryCodec p6, Function g6, 242 | F6 reader 243 | ) { 244 | return new BinaryCodec<>() { 245 | @Override 246 | public void write(ByteBuf buffer, R value) { 247 | p1.write(buffer, g1.apply(value)); 248 | p2.write(buffer, g2.apply(value)); 249 | p3.write(buffer, g3.apply(value)); 250 | p4.write(buffer, g4.apply(value)); 251 | p5.write(buffer, g5.apply(value)); 252 | p6.write(buffer, g6.apply(value)); 253 | } 254 | 255 | @Override 256 | public R read(ByteBuf buffer) { 257 | return reader.apply( 258 | p1.read(buffer), 259 | p2.read(buffer), 260 | p3.read(buffer), 261 | p4.read(buffer), 262 | p5.read(buffer), 263 | p6.read(buffer)); 264 | } 265 | }; 266 | } 267 | 268 | static BinaryCodec of( 269 | BinaryCodec p1, Function g1, 270 | BinaryCodec p2, Function g2, 271 | BinaryCodec p3, Function g3, 272 | BinaryCodec p4, Function g4, 273 | BinaryCodec p5, Function g5, 274 | BinaryCodec p6, Function g6, 275 | BinaryCodec p7, Function g7, 276 | F7 reader 277 | ) { 278 | return new BinaryCodec<>() { 279 | @Override 280 | public void write(ByteBuf buffer, R value) { 281 | p1.write(buffer, g1.apply(value)); 282 | p2.write(buffer, g2.apply(value)); 283 | p3.write(buffer, g3.apply(value)); 284 | p4.write(buffer, g4.apply(value)); 285 | p5.write(buffer, g5.apply(value)); 286 | p6.write(buffer, g6.apply(value)); 287 | p7.write(buffer, g7.apply(value)); 288 | } 289 | 290 | @Override 291 | public R read(ByteBuf buffer) { 292 | return reader.apply( 293 | p1.read(buffer), 294 | p2.read(buffer), 295 | p3.read(buffer), 296 | p4.read(buffer), 297 | p5.read(buffer), 298 | p6.read(buffer), 299 | p7.read(buffer)); 300 | } 301 | }; 302 | } 303 | 304 | static BinaryCodec of( 305 | BinaryCodec p1, Function g1, 306 | BinaryCodec p2, Function g2, 307 | BinaryCodec p3, Function g3, 308 | BinaryCodec p4, Function g4, 309 | BinaryCodec p5, Function g5, 310 | BinaryCodec p6, Function g6, 311 | BinaryCodec p7, Function g7, 312 | BinaryCodec p8, Function g8, 313 | F8 reader 314 | ) { 315 | return new BinaryCodec<>() { 316 | @Override 317 | public void write(ByteBuf buffer, R value) { 318 | p1.write(buffer, g1.apply(value)); 319 | p2.write(buffer, g2.apply(value)); 320 | p3.write(buffer, g3.apply(value)); 321 | p4.write(buffer, g4.apply(value)); 322 | p5.write(buffer, g5.apply(value)); 323 | p6.write(buffer, g6.apply(value)); 324 | p7.write(buffer, g7.apply(value)); 325 | p8.write(buffer, g8.apply(value)); 326 | } 327 | 328 | @Override 329 | public R read(ByteBuf buffer) { 330 | return reader.apply( 331 | p1.read(buffer), 332 | p2.read(buffer), 333 | p3.read(buffer), 334 | p4.read(buffer), 335 | p5.read(buffer), 336 | p6.read(buffer), 337 | p7.read(buffer), 338 | p8.read(buffer)); 339 | } 340 | }; 341 | } 342 | 343 | static BinaryCodec of( 344 | BinaryCodec p1, Function g1, 345 | BinaryCodec p2, Function g2, 346 | BinaryCodec p3, Function g3, 347 | BinaryCodec p4, Function g4, 348 | BinaryCodec p5, Function g5, 349 | BinaryCodec p6, Function g6, 350 | BinaryCodec p7, Function g7, 351 | BinaryCodec p8, Function g8, 352 | BinaryCodec p9, Function g9, 353 | F9 reader 354 | ) { 355 | return new BinaryCodec<>() { 356 | @Override 357 | public void write(ByteBuf buffer, R value) { 358 | p1.write(buffer, g1.apply(value)); 359 | p2.write(buffer, g2.apply(value)); 360 | p3.write(buffer, g3.apply(value)); 361 | p4.write(buffer, g4.apply(value)); 362 | p5.write(buffer, g5.apply(value)); 363 | p6.write(buffer, g6.apply(value)); 364 | p7.write(buffer, g7.apply(value)); 365 | p8.write(buffer, g8.apply(value)); 366 | p9.write(buffer, g9.apply(value)); 367 | } 368 | 369 | @Override 370 | public R read(ByteBuf buffer) { 371 | return reader.apply( 372 | p1.read(buffer), 373 | p2.read(buffer), 374 | p3.read(buffer), 375 | p4.read(buffer), 376 | p5.read(buffer), 377 | p6.read(buffer), 378 | p7.read(buffer), 379 | p8.read(buffer), 380 | p9.read(buffer)); 381 | } 382 | }; 383 | } 384 | 385 | static BinaryCodec of( 386 | BinaryCodec p1, Function g1, 387 | BinaryCodec p2, Function g2, 388 | BinaryCodec p3, Function g3, 389 | BinaryCodec p4, Function g4, 390 | BinaryCodec p5, Function g5, 391 | BinaryCodec p6, Function g6, 392 | BinaryCodec p7, Function g7, 393 | BinaryCodec p8, Function g8, 394 | BinaryCodec p9, Function g9, 395 | BinaryCodec p10, Function g10, 396 | F10 reader 397 | ) { 398 | return new BinaryCodec<>() { 399 | @Override 400 | public void write(ByteBuf buffer, R value) { 401 | p1.write(buffer, g1.apply(value)); 402 | p2.write(buffer, g2.apply(value)); 403 | p3.write(buffer, g3.apply(value)); 404 | p4.write(buffer, g4.apply(value)); 405 | p5.write(buffer, g5.apply(value)); 406 | p6.write(buffer, g6.apply(value)); 407 | p7.write(buffer, g7.apply(value)); 408 | p8.write(buffer, g8.apply(value)); 409 | p9.write(buffer, g9.apply(value)); 410 | p10.write(buffer, g10.apply(value)); 411 | } 412 | 413 | @Override 414 | public R read(ByteBuf buffer) { 415 | return reader.apply( 416 | p1.read(buffer), 417 | p2.read(buffer), 418 | p3.read(buffer), 419 | p4.read(buffer), 420 | p5.read(buffer), 421 | p6.read(buffer), 422 | p7.read(buffer), 423 | p8.read(buffer), 424 | p9.read(buffer), 425 | p10.read(buffer)); 426 | } 427 | }; 428 | } 429 | 430 | static BinaryCodec of( 431 | BinaryCodec p1, Function g1, 432 | BinaryCodec p2, Function g2, 433 | BinaryCodec p3, Function g3, 434 | BinaryCodec p4, Function g4, 435 | BinaryCodec p5, Function g5, 436 | BinaryCodec p6, Function g6, 437 | BinaryCodec p7, Function g7, 438 | BinaryCodec p8, Function g8, 439 | BinaryCodec p9, Function g9, 440 | BinaryCodec p10, Function g10, 441 | BinaryCodec p11, Function g11, 442 | F11 reader 443 | ) { 444 | return new BinaryCodec<>() { 445 | @Override 446 | public void write(ByteBuf buffer, R value) { 447 | p1.write(buffer, g1.apply(value)); 448 | p2.write(buffer, g2.apply(value)); 449 | p3.write(buffer, g3.apply(value)); 450 | p4.write(buffer, g4.apply(value)); 451 | p5.write(buffer, g5.apply(value)); 452 | p6.write(buffer, g6.apply(value)); 453 | p7.write(buffer, g7.apply(value)); 454 | p8.write(buffer, g8.apply(value)); 455 | p9.write(buffer, g9.apply(value)); 456 | p10.write(buffer, g10.apply(value)); 457 | p11.write(buffer, g11.apply(value)); 458 | } 459 | 460 | @Override 461 | public R read(ByteBuf buffer) { 462 | return reader.apply( 463 | p1.read(buffer), 464 | p2.read(buffer), 465 | p3.read(buffer), 466 | p4.read(buffer), 467 | p5.read(buffer), 468 | p6.read(buffer), 469 | p7.read(buffer), 470 | p8.read(buffer), 471 | p9.read(buffer), 472 | p10.read(buffer), 473 | p11.read(buffer)); 474 | } 475 | }; 476 | } 477 | 478 | static BinaryCodec of( 479 | BinaryCodec p1, Function g1, 480 | BinaryCodec p2, Function g2, 481 | BinaryCodec p3, Function g3, 482 | BinaryCodec p4, Function g4, 483 | BinaryCodec p5, Function g5, 484 | BinaryCodec p6, Function g6, 485 | BinaryCodec p7, Function g7, 486 | BinaryCodec p8, Function g8, 487 | BinaryCodec p9, Function g9, 488 | BinaryCodec p10, Function g10, 489 | BinaryCodec p11, Function g11, 490 | BinaryCodec p12, Function g12, 491 | F12 reader 492 | ) { 493 | return new BinaryCodec<>() { 494 | @Override 495 | public void write(ByteBuf buffer, R value) { 496 | p1.write(buffer, g1.apply(value)); 497 | p2.write(buffer, g2.apply(value)); 498 | p3.write(buffer, g3.apply(value)); 499 | p4.write(buffer, g4.apply(value)); 500 | p5.write(buffer, g5.apply(value)); 501 | p6.write(buffer, g6.apply(value)); 502 | p7.write(buffer, g7.apply(value)); 503 | p8.write(buffer, g8.apply(value)); 504 | p9.write(buffer, g9.apply(value)); 505 | p10.write(buffer, g10.apply(value)); 506 | p11.write(buffer, g11.apply(value)); 507 | p12.write(buffer, g12.apply(value)); 508 | } 509 | 510 | @Override 511 | public R read(ByteBuf buffer) { 512 | return reader.apply( 513 | p1.read(buffer), 514 | p2.read(buffer), 515 | p3.read(buffer), 516 | p4.read(buffer), 517 | p5.read(buffer), 518 | p6.read(buffer), 519 | p7.read(buffer), 520 | p8.read(buffer), 521 | p9.read(buffer), 522 | p10.read(buffer), 523 | p11.read(buffer), 524 | p12.read(buffer)); 525 | } 526 | }; 527 | } 528 | 529 | static BinaryCodec of( 530 | BinaryCodec p1, Function g1, 531 | BinaryCodec p2, Function g2, 532 | BinaryCodec p3, Function g3, 533 | BinaryCodec p4, Function g4, 534 | BinaryCodec p5, Function g5, 535 | BinaryCodec p6, Function g6, 536 | BinaryCodec p7, Function g7, 537 | BinaryCodec p8, Function g8, 538 | BinaryCodec p9, Function g9, 539 | BinaryCodec p10, Function g10, 540 | BinaryCodec p11, Function g11, 541 | BinaryCodec p12, Function g12, 542 | BinaryCodec p13, Function g13, 543 | F13 reader 544 | ) { 545 | return new BinaryCodec<>() { 546 | @Override 547 | public void write(ByteBuf buffer, R value) { 548 | p1.write(buffer, g1.apply(value)); 549 | p2.write(buffer, g2.apply(value)); 550 | p3.write(buffer, g3.apply(value)); 551 | p4.write(buffer, g4.apply(value)); 552 | p5.write(buffer, g5.apply(value)); 553 | p6.write(buffer, g6.apply(value)); 554 | p7.write(buffer, g7.apply(value)); 555 | p8.write(buffer, g8.apply(value)); 556 | p9.write(buffer, g9.apply(value)); 557 | p10.write(buffer, g10.apply(value)); 558 | p11.write(buffer, g11.apply(value)); 559 | p12.write(buffer, g12.apply(value)); 560 | p13.write(buffer, g13.apply(value)); 561 | } 562 | 563 | @Override 564 | public R read(ByteBuf buffer) { 565 | return reader.apply( 566 | p1.read(buffer), 567 | p2.read(buffer), 568 | p3.read(buffer), 569 | p4.read(buffer), 570 | p5.read(buffer), 571 | p6.read(buffer), 572 | p7.read(buffer), 573 | p8.read(buffer), 574 | p9.read(buffer), 575 | p10.read(buffer), 576 | p11.read(buffer), 577 | p12.read(buffer), 578 | p13.read(buffer)); 579 | } 580 | }; 581 | } 582 | 583 | static BinaryCodec of( 584 | BinaryCodec p1, Function g1, 585 | BinaryCodec p2, Function g2, 586 | BinaryCodec p3, Function g3, 587 | BinaryCodec p4, Function g4, 588 | BinaryCodec p5, Function g5, 589 | BinaryCodec p6, Function g6, 590 | BinaryCodec p7, Function g7, 591 | BinaryCodec p8, Function g8, 592 | BinaryCodec p9, Function g9, 593 | BinaryCodec p10, Function g10, 594 | BinaryCodec p11, Function g11, 595 | BinaryCodec p12, Function g12, 596 | BinaryCodec p13, Function g13, 597 | BinaryCodec p14, Function g14, 598 | F14 reader 599 | ) { 600 | return new BinaryCodec<>() { 601 | @Override 602 | public void write(ByteBuf buffer, R value) { 603 | p1.write(buffer, g1.apply(value)); 604 | p2.write(buffer, g2.apply(value)); 605 | p3.write(buffer, g3.apply(value)); 606 | p4.write(buffer, g4.apply(value)); 607 | p5.write(buffer, g5.apply(value)); 608 | p6.write(buffer, g6.apply(value)); 609 | p7.write(buffer, g7.apply(value)); 610 | p8.write(buffer, g8.apply(value)); 611 | p9.write(buffer, g9.apply(value)); 612 | p10.write(buffer, g10.apply(value)); 613 | p11.write(buffer, g11.apply(value)); 614 | p12.write(buffer, g12.apply(value)); 615 | p13.write(buffer, g13.apply(value)); 616 | p14.write(buffer, g14.apply(value)); 617 | } 618 | 619 | @Override 620 | public R read(ByteBuf buffer) { 621 | return reader.apply( 622 | p1.read(buffer), 623 | p2.read(buffer), 624 | p3.read(buffer), 625 | p4.read(buffer), 626 | p5.read(buffer), 627 | p6.read(buffer), 628 | p7.read(buffer), 629 | p8.read(buffer), 630 | p9.read(buffer), 631 | p10.read(buffer), 632 | p11.read(buffer), 633 | p12.read(buffer), 634 | p13.read(buffer), 635 | p14.read(buffer)); 636 | } 637 | }; 638 | } 639 | 640 | static BinaryCodec of( 641 | BinaryCodec p1, Function g1, 642 | BinaryCodec p2, Function g2, 643 | BinaryCodec p3, Function g3, 644 | BinaryCodec p4, Function g4, 645 | BinaryCodec p5, Function g5, 646 | BinaryCodec p6, Function g6, 647 | BinaryCodec p7, Function g7, 648 | BinaryCodec p8, Function g8, 649 | BinaryCodec p9, Function g9, 650 | BinaryCodec p10, Function g10, 651 | BinaryCodec p11, Function g11, 652 | BinaryCodec p12, Function g12, 653 | BinaryCodec p13, Function g13, 654 | BinaryCodec p14, Function g14, 655 | BinaryCodec p15, Function g15, 656 | F15 reader 657 | ) { 658 | return new BinaryCodec<>() { 659 | @Override 660 | public void write(ByteBuf buffer, R value) { 661 | p1.write(buffer, g1.apply(value)); 662 | p2.write(buffer, g2.apply(value)); 663 | p3.write(buffer, g3.apply(value)); 664 | p4.write(buffer, g4.apply(value)); 665 | p5.write(buffer, g5.apply(value)); 666 | p6.write(buffer, g6.apply(value)); 667 | p7.write(buffer, g7.apply(value)); 668 | p8.write(buffer, g8.apply(value)); 669 | p9.write(buffer, g9.apply(value)); 670 | p10.write(buffer, g10.apply(value)); 671 | p11.write(buffer, g11.apply(value)); 672 | p12.write(buffer, g12.apply(value)); 673 | p13.write(buffer, g13.apply(value)); 674 | p14.write(buffer, g14.apply(value)); 675 | p15.write(buffer, g15.apply(value)); 676 | } 677 | 678 | @Override 679 | public R read(ByteBuf buffer) { 680 | return reader.apply( 681 | p1.read(buffer), p2.read(buffer), 682 | p3.read(buffer), p4.read(buffer), 683 | p5.read(buffer), p6.read(buffer), 684 | p7.read(buffer), p8.read(buffer), 685 | p9.read(buffer), p10.read(buffer), 686 | p11.read(buffer), p12.read(buffer), 687 | p13.read(buffer), p14.read(buffer), 688 | p15.read(buffer)); 689 | } 690 | }; 691 | } 692 | 693 | static BinaryCodec of( 694 | BinaryCodec p1, Function g1, 695 | BinaryCodec p2, Function g2, 696 | BinaryCodec p3, Function g3, 697 | BinaryCodec p4, Function g4, 698 | BinaryCodec p5, Function g5, 699 | BinaryCodec p6, Function g6, 700 | BinaryCodec p7, Function g7, 701 | BinaryCodec p8, Function g8, 702 | BinaryCodec p9, Function g9, 703 | BinaryCodec p10, Function g10, 704 | BinaryCodec p11, Function g11, 705 | BinaryCodec p12, Function g12, 706 | BinaryCodec p13, Function g13, 707 | BinaryCodec p14, Function g14, 708 | BinaryCodec p15, Function g15, 709 | BinaryCodec p16, Function g16, 710 | F16 reader 711 | ) { 712 | return new BinaryCodec<>() { 713 | @Override 714 | public void write(ByteBuf buffer, R value) { 715 | p1.write(buffer, g1.apply(value)); 716 | p2.write(buffer, g2.apply(value)); 717 | p3.write(buffer, g3.apply(value)); 718 | p4.write(buffer, g4.apply(value)); 719 | p5.write(buffer, g5.apply(value)); 720 | p6.write(buffer, g6.apply(value)); 721 | p7.write(buffer, g7.apply(value)); 722 | p8.write(buffer, g8.apply(value)); 723 | p9.write(buffer, g9.apply(value)); 724 | p10.write(buffer, g10.apply(value)); 725 | p11.write(buffer, g11.apply(value)); 726 | p12.write(buffer, g12.apply(value)); 727 | p13.write(buffer, g13.apply(value)); 728 | p14.write(buffer, g14.apply(value)); 729 | p15.write(buffer, g15.apply(value)); 730 | p16.write(buffer, g16.apply(value)); 731 | } 732 | 733 | @Override 734 | public R read(ByteBuf buffer) { 735 | return reader.apply( 736 | p1.read(buffer), 737 | p2.read(buffer), 738 | p3.read(buffer), 739 | p4.read(buffer), 740 | p5.read(buffer), 741 | p6.read(buffer), 742 | p7.read(buffer), 743 | p8.read(buffer), 744 | p9.read(buffer), 745 | p10.read(buffer), 746 | p11.read(buffer), 747 | p12.read(buffer), 748 | p13.read(buffer), 749 | p14.read(buffer), 750 | p15.read(buffer), 751 | p16.read(buffer)); 752 | } 753 | }; 754 | } 755 | 756 | static BinaryCodec of( 757 | BinaryCodec p1, Function g1, 758 | BinaryCodec p2, Function g2, 759 | BinaryCodec p3, Function g3, 760 | BinaryCodec p4, Function g4, 761 | BinaryCodec p5, Function g5, 762 | BinaryCodec p6, Function g6, 763 | BinaryCodec p7, Function g7, 764 | BinaryCodec p8, Function g8, 765 | BinaryCodec p9, Function g9, 766 | BinaryCodec p10, Function g10, 767 | BinaryCodec p11, Function g11, 768 | BinaryCodec p12, Function g12, 769 | BinaryCodec p13, Function g13, 770 | BinaryCodec p14, Function g14, 771 | BinaryCodec p15, Function g15, 772 | BinaryCodec p16, Function g16, 773 | BinaryCodec p17, Function g17, 774 | F17 reader 775 | ) { 776 | return new BinaryCodec<>() { 777 | @Override 778 | public void write(ByteBuf buffer, R value) { 779 | p1.write(buffer, g1.apply(value)); 780 | p2.write(buffer, g2.apply(value)); 781 | p3.write(buffer, g3.apply(value)); 782 | p4.write(buffer, g4.apply(value)); 783 | p5.write(buffer, g5.apply(value)); 784 | p6.write(buffer, g6.apply(value)); 785 | p7.write(buffer, g7.apply(value)); 786 | p8.write(buffer, g8.apply(value)); 787 | p9.write(buffer, g9.apply(value)); 788 | p10.write(buffer, g10.apply(value)); 789 | p11.write(buffer, g11.apply(value)); 790 | p12.write(buffer, g12.apply(value)); 791 | p13.write(buffer, g13.apply(value)); 792 | p14.write(buffer, g14.apply(value)); 793 | p15.write(buffer, g15.apply(value)); 794 | p16.write(buffer, g16.apply(value)); 795 | p17.write(buffer, g17.apply(value)); 796 | } 797 | 798 | @Override 799 | public R read(ByteBuf buffer) { 800 | return reader.apply( 801 | p1.read(buffer), 802 | p2.read(buffer), 803 | p3.read(buffer), 804 | p4.read(buffer), 805 | p5.read(buffer), 806 | p6.read(buffer), 807 | p7.read(buffer), 808 | p8.read(buffer), 809 | p9.read(buffer), 810 | p10.read(buffer), 811 | p11.read(buffer), 812 | p12.read(buffer), 813 | p13.read(buffer), 814 | p14.read(buffer), 815 | p15.read(buffer), 816 | p16.read(buffer), 817 | p17.read(buffer)); 818 | } 819 | }; 820 | } 821 | 822 | static BinaryCodec of( 823 | BinaryCodec p1, Function g1, 824 | BinaryCodec p2, Function g2, 825 | BinaryCodec p3, Function g3, 826 | BinaryCodec p4, Function g4, 827 | BinaryCodec p5, Function g5, 828 | BinaryCodec p6, Function g6, 829 | BinaryCodec p7, Function g7, 830 | BinaryCodec p8, Function g8, 831 | BinaryCodec p9, Function g9, 832 | BinaryCodec p10, Function g10, 833 | BinaryCodec p11, Function g11, 834 | BinaryCodec p12, Function g12, 835 | BinaryCodec p13, Function g13, 836 | BinaryCodec p14, Function g14, 837 | BinaryCodec p15, Function g15, 838 | BinaryCodec p16, Function g16, 839 | BinaryCodec p17, Function g17, 840 | BinaryCodec p18, Function g18, 841 | F18 reader 842 | ) { 843 | return new BinaryCodec<>() { 844 | @Override 845 | public void write(ByteBuf buffer, R value) { 846 | p1.write(buffer, g1.apply(value)); 847 | p2.write(buffer, g2.apply(value)); 848 | p3.write(buffer, g3.apply(value)); 849 | p4.write(buffer, g4.apply(value)); 850 | p5.write(buffer, g5.apply(value)); 851 | p6.write(buffer, g6.apply(value)); 852 | p7.write(buffer, g7.apply(value)); 853 | p8.write(buffer, g8.apply(value)); 854 | p9.write(buffer, g9.apply(value)); 855 | p10.write(buffer, g10.apply(value)); 856 | p11.write(buffer, g11.apply(value)); 857 | p12.write(buffer, g12.apply(value)); 858 | p13.write(buffer, g13.apply(value)); 859 | p14.write(buffer, g14.apply(value)); 860 | p15.write(buffer, g15.apply(value)); 861 | p16.write(buffer, g16.apply(value)); 862 | p17.write(buffer, g17.apply(value)); 863 | p18.write(buffer, g18.apply(value)); 864 | } 865 | 866 | @Override 867 | public R read(ByteBuf buffer) { 868 | return reader.apply( 869 | p1.read(buffer), 870 | p2.read(buffer), 871 | p3.read(buffer), 872 | p4.read(buffer), 873 | p5.read(buffer), 874 | p6.read(buffer), 875 | p7.read(buffer), 876 | p8.read(buffer), 877 | p9.read(buffer), 878 | p10.read(buffer), 879 | p11.read(buffer), 880 | p12.read(buffer), 881 | p13.read(buffer), 882 | p14.read(buffer), 883 | p15.read(buffer), 884 | p16.read(buffer), 885 | p17.read(buffer), 886 | p18.read(buffer)); 887 | } 888 | }; 889 | } 890 | 891 | static BinaryCodec of( 892 | BinaryCodec p1, Function g1, 893 | BinaryCodec p2, Function g2, 894 | BinaryCodec p3, Function g3, 895 | BinaryCodec p4, Function g4, 896 | BinaryCodec p5, Function g5, 897 | BinaryCodec p6, Function g6, 898 | BinaryCodec p7, Function g7, 899 | BinaryCodec p8, Function g8, 900 | BinaryCodec p9, Function g9, 901 | BinaryCodec p10, Function g10, 902 | BinaryCodec p11, Function g11, 903 | BinaryCodec p12, Function g12, 904 | BinaryCodec p13, Function g13, 905 | BinaryCodec p14, Function g14, 906 | BinaryCodec p15, Function g15, 907 | BinaryCodec p16, Function g16, 908 | BinaryCodec p17, Function g17, 909 | BinaryCodec p18, Function g18, 910 | BinaryCodec p19, Function g19, 911 | F19 reader 912 | ) { 913 | return new BinaryCodec<>() { 914 | @Override 915 | public void write(ByteBuf buffer, R value) { 916 | p1.write(buffer, g1.apply(value)); 917 | p2.write(buffer, g2.apply(value)); 918 | p3.write(buffer, g3.apply(value)); 919 | p4.write(buffer, g4.apply(value)); 920 | p5.write(buffer, g5.apply(value)); 921 | p6.write(buffer, g6.apply(value)); 922 | p7.write(buffer, g7.apply(value)); 923 | p8.write(buffer, g8.apply(value)); 924 | p9.write(buffer, g9.apply(value)); 925 | p10.write(buffer, g10.apply(value)); 926 | p11.write(buffer, g11.apply(value)); 927 | p12.write(buffer, g12.apply(value)); 928 | p13.write(buffer, g13.apply(value)); 929 | p14.write(buffer, g14.apply(value)); 930 | p15.write(buffer, g15.apply(value)); 931 | p16.write(buffer, g16.apply(value)); 932 | p17.write(buffer, g17.apply(value)); 933 | p18.write(buffer, g18.apply(value)); 934 | p19.write(buffer, g19.apply(value)); 935 | } 936 | 937 | @Override 938 | public R read(ByteBuf buffer) { 939 | return reader.apply( 940 | p1.read(buffer), 941 | p2.read(buffer), 942 | p3.read(buffer), 943 | p4.read(buffer), 944 | p5.read(buffer), 945 | p6.read(buffer), 946 | p7.read(buffer), 947 | p8.read(buffer), 948 | p9.read(buffer), 949 | p10.read(buffer), 950 | p11.read(buffer), 951 | p12.read(buffer), 952 | p13.read(buffer), 953 | p14.read(buffer), 954 | p15.read(buffer), 955 | p16.read(buffer), 956 | p17.read(buffer), 957 | p18.read(buffer), 958 | p19.read(buffer)); 959 | } 960 | }; 961 | } 962 | 963 | static BinaryCodec of( 964 | BinaryCodec p1, Function g1, 965 | BinaryCodec p2, Function g2, 966 | BinaryCodec p3, Function g3, 967 | BinaryCodec p4, Function g4, 968 | BinaryCodec p5, Function g5, 969 | BinaryCodec p6, Function g6, 970 | BinaryCodec p7, Function g7, 971 | BinaryCodec p8, Function g8, 972 | BinaryCodec p9, Function g9, 973 | BinaryCodec p10, Function g10, 974 | BinaryCodec p11, Function g11, 975 | BinaryCodec p12, Function g12, 976 | BinaryCodec p13, Function g13, 977 | BinaryCodec p14, Function g14, 978 | BinaryCodec p15, Function g15, 979 | BinaryCodec p16, Function g16, 980 | BinaryCodec p17, Function g17, 981 | BinaryCodec p18, Function g18, 982 | BinaryCodec p19, Function g19, 983 | BinaryCodec p20, Function g20, 984 | F20 reader 985 | ) { 986 | return new BinaryCodec<>() { 987 | @Override 988 | public void write(ByteBuf buffer, R value) { 989 | p1.write(buffer, g1.apply(value)); 990 | p2.write(buffer, g2.apply(value)); 991 | p3.write(buffer, g3.apply(value)); 992 | p4.write(buffer, g4.apply(value)); 993 | p5.write(buffer, g5.apply(value)); 994 | p6.write(buffer, g6.apply(value)); 995 | p7.write(buffer, g7.apply(value)); 996 | p8.write(buffer, g8.apply(value)); 997 | p9.write(buffer, g9.apply(value)); 998 | p10.write(buffer, g10.apply(value)); 999 | p11.write(buffer, g11.apply(value)); 1000 | p12.write(buffer, g12.apply(value)); 1001 | p13.write(buffer, g13.apply(value)); 1002 | p14.write(buffer, g14.apply(value)); 1003 | p15.write(buffer, g15.apply(value)); 1004 | p16.write(buffer, g16.apply(value)); 1005 | p17.write(buffer, g17.apply(value)); 1006 | p18.write(buffer, g18.apply(value)); 1007 | p19.write(buffer, g19.apply(value)); 1008 | p20.write(buffer, g20.apply(value)); 1009 | } 1010 | 1011 | @Override 1012 | public R read(ByteBuf buffer) { 1013 | return reader.apply( 1014 | p1.read(buffer), 1015 | p2.read(buffer), 1016 | p3.read(buffer), 1017 | p4.read(buffer), 1018 | p5.read(buffer), 1019 | p6.read(buffer), 1020 | p7.read(buffer), 1021 | p8.read(buffer), 1022 | p9.read(buffer), 1023 | p10.read(buffer), 1024 | p11.read(buffer), 1025 | p12.read(buffer), 1026 | p13.read(buffer), 1027 | p14.read(buffer), 1028 | p15.read(buffer), 1029 | p16.read(buffer), 1030 | p17.read(buffer), 1031 | p18.read(buffer), 1032 | p19.read(buffer), 1033 | p20.read(buffer)); 1034 | } 1035 | }; 1036 | } 1037 | } 1038 | -------------------------------------------------------------------------------- /binary/src/main/java/alpine/binary/Either.java: -------------------------------------------------------------------------------- 1 | package alpine.binary; 2 | 3 | import java.util.Objects; 4 | import java.util.Optional; 5 | import java.util.function.Consumer; 6 | import java.util.function.Function; 7 | 8 | /** 9 | * Something that can be represented as one of two types. 10 | * @param The left type. 11 | * @param The right type. 12 | */ 13 | public final class Either { 14 | enum Type { 15 | LEFT, 16 | RIGHT 17 | } 18 | 19 | private final Type type; 20 | private final L left; 21 | private final R right; 22 | 23 | private Either(Type type, L left, R right) { 24 | this.type = type; 25 | this.left = left; 26 | this.right = right; 27 | } 28 | 29 | public static Either left(L left) { 30 | return new Either<>(Type.LEFT, left, null); 31 | } 32 | 33 | public static Either right(R right) { 34 | return new Either<>(Type.RIGHT, null, right); 35 | } 36 | 37 | @Override 38 | public int hashCode() { 39 | return Objects.hash(this.type, this.left, this.right); 40 | } 41 | 42 | @Override 43 | public boolean equals(Object object) { 44 | return object instanceof Either either 45 | && this.type == either.type 46 | && Objects.equals(this.left, either.left) 47 | && Objects.equals(this.right, either.right); 48 | } 49 | 50 | @Override 51 | public String toString() { 52 | return this.fold( 53 | left -> String.format("Left(%s)", left), 54 | right -> String.format("Right(%s)", right)); 55 | } 56 | 57 | public Optional left() { 58 | return this.isLeft() ? Optional.ofNullable(this.left) : Optional.empty(); 59 | } 60 | 61 | public Optional right() { 62 | return this.isRight() ? Optional.ofNullable(this.right) : Optional.empty(); 63 | } 64 | 65 | public Either map(Function leftMapper, Function rightMapper) { 66 | return this.fold( 67 | left -> left(leftMapper.apply(left)), 68 | right -> right(rightMapper.apply(right))); 69 | } 70 | 71 | public Either mapLeft(Function mapper) { 72 | return this.fold(left -> left(mapper.apply(left)), Either::right); 73 | } 74 | 75 | public Either mapRight(Function mapper) { 76 | return this.fold(Either::left, right -> right(mapper.apply(right))); 77 | } 78 | 79 | public T fold(Function leftFunction, Function rightFunction) { 80 | if (this.isLeft()) { 81 | return leftFunction.apply(this.left); 82 | } else { 83 | return rightFunction.apply(this.right); 84 | } 85 | } 86 | 87 | public void consume(Consumer leftConsumer, Consumer rightConsumer) { 88 | this.ifLeft(leftConsumer); 89 | this.ifRight(rightConsumer); 90 | } 91 | 92 | public boolean isLeft() { 93 | return this.type == Type.LEFT; 94 | } 95 | 96 | public boolean isRight() { 97 | return this.type == Type.RIGHT; 98 | } 99 | 100 | public void ifLeft(Consumer consumer) { 101 | if (this.isLeft()) { 102 | consumer.accept(this.left); 103 | } 104 | } 105 | 106 | public void ifRight(Consumer consumer) { 107 | if (this.isRight()) { 108 | consumer.accept(this.right); 109 | } 110 | } 111 | 112 | public L expectLeft() { 113 | if (this.isLeft()) { 114 | return this.left; 115 | } else { 116 | throw new IllegalStateException("The right value was unexpected!"); 117 | } 118 | } 119 | 120 | public R expectRight() { 121 | if (this.isRight()) { 122 | return this.right; 123 | } else { 124 | throw new IllegalStateException("The left value was unexpected!"); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /binary/src/main/java/alpine/binary/EitherBinaryCodec.java: -------------------------------------------------------------------------------- 1 | package alpine.binary; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | /** 6 | * A binary codec which serializes something that can be represented as one of two values. 7 | * @param leftCodec The binary codec to serialize a left value with. 8 | * @param rightCodec The binary codec to serialize a right value with. 9 | * @param The left value type. 10 | * @param The right value type. 11 | * @see Either 12 | */ 13 | record EitherBinaryCodec(BinaryCodec leftCodec, BinaryCodec rightCodec) implements BinaryCodec> { 14 | @Override 15 | public Either read(ByteBuf buffer) { 16 | if (buffer.readBoolean()) { 17 | return Either.right(this.rightCodec.read(buffer)); 18 | } else { 19 | return Either.left(this.leftCodec.read(buffer)); 20 | } 21 | } 22 | 23 | @Override 24 | public void write(ByteBuf buffer, Either value) { 25 | if (value.isLeft()) { 26 | BOOLEAN.write(buffer, false); 27 | this.leftCodec.write(buffer, value.expectLeft()); 28 | } else { 29 | BOOLEAN.write(buffer, true); 30 | this.rightCodec.write(buffer, value.expectRight()); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /binary/src/main/java/alpine/binary/ListBinaryCodec.java: -------------------------------------------------------------------------------- 1 | package alpine.binary; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * A binary codec which serializes a sequence of values as an {@link ArrayList}. 10 | * @param parent The binary codec to serialize the values with. 11 | * @param The element type. 12 | * @author mudkip 13 | */ 14 | record ListBinaryCodec(BinaryCodec parent) implements BinaryCodec> { 15 | @Override 16 | public List read(ByteBuf buffer) { 17 | var size = VARINT.read(buffer); 18 | var list = new ArrayList(size); 19 | 20 | for (var index = 0; index < size; index++) { 21 | list.add(this.parent.read(buffer)); 22 | } 23 | 24 | return list; 25 | } 26 | 27 | @Override 28 | public void write(ByteBuf buffer, List value) { 29 | VARINT.write(buffer, value.size()); 30 | value.forEach(it -> this.parent.write(buffer, it)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /binary/src/main/java/alpine/binary/MapBinaryCodec.java: -------------------------------------------------------------------------------- 1 | package alpine.binary; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | import java.util.LinkedHashMap; 6 | import java.util.Map; 7 | 8 | /** 9 | * A binary codec which serializes an ordered sequence of key-value pairs. 10 | * @param keyCodec The binary codec to serialize the keys with. 11 | * @param valueCodec The binary codec to serialize the values with. 12 | * @param The key type. 13 | * @param The value type. 14 | * @author mudkip 15 | */ 16 | record MapBinaryCodec(BinaryCodec keyCodec, BinaryCodec valueCodec) implements BinaryCodec> { 17 | @Override 18 | public Map read(ByteBuf buffer) { 19 | var size = VARINT.read(buffer); 20 | var map = new LinkedHashMap(size); 21 | 22 | for (var index = 0; index < size; index++) { 23 | map.put(this.keyCodec.read(buffer), this.valueCodec.read(buffer)); 24 | } 25 | 26 | return map; 27 | } 28 | 29 | @Override 30 | public void write(ByteBuf buffer, Map value) { 31 | for (var entry : value.entrySet()) { 32 | this.keyCodec.write(buffer, entry.getKey()); 33 | this.valueCodec.write(buffer, entry.getValue()); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /binary/src/main/java/alpine/binary/MappedBinaryCodec.java: -------------------------------------------------------------------------------- 1 | package alpine.binary; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | import java.util.function.Function; 6 | 7 | /** 8 | * A binary codec which converts one type to another. 9 | * @param parent The binary codec to serialize the value with. 10 | * @param to The function to transform the original value to a new type. 11 | * @param from The function to transform the new type to the original type. 12 | * @param The original value type. 13 | * @param The new value type. 14 | * @author mudkip 15 | */ 16 | record MappedBinaryCodec(BinaryCodec parent, Function to, Function from) implements BinaryCodec { 17 | @Override 18 | public U read(ByteBuf buffer) { 19 | return this.to.apply(this.parent.read(buffer)); 20 | } 21 | 22 | @Override 23 | public void write(ByteBuf buffer, U value) { 24 | this.parent.write(buffer, this.from.apply(value)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /binary/src/main/java/alpine/binary/NullableBinaryCodec.java: -------------------------------------------------------------------------------- 1 | package alpine.binary; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | /** 7 | * A binary codec which may or may not have a value present. 8 | * The value will be read as {@code null} if it is not present. 9 | * @param parent The binary codec to serialize the value with. 10 | * @param The value type. 11 | * @see OptionalBinaryCodec 12 | * @author mudkip 13 | */ 14 | record NullableBinaryCodec(BinaryCodec parent) implements BinaryCodec { 15 | @Override 16 | public @Nullable T read(ByteBuf buffer) { 17 | if (BOOLEAN.read(buffer)) { 18 | return this.parent.read(buffer); 19 | } else { 20 | return null; 21 | } 22 | } 23 | 24 | @Override 25 | public void write(ByteBuf buffer, @Nullable T value) { 26 | BOOLEAN.write(buffer, value != null); 27 | 28 | if (value != null) { 29 | this.parent.write(buffer, value); 30 | } 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /binary/src/main/java/alpine/binary/OptionalBinaryCodec.java: -------------------------------------------------------------------------------- 1 | package alpine.binary; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | import java.util.Optional; 6 | 7 | /** 8 | * A binary codec which may or may not have a value present. 9 | * The value is wrapped with Java's {@link Optional} type to ensure proper handling. 10 | * @param parent The binary codec to serialize the value with. 11 | * @param The value type. 12 | * @see NullableBinaryCodec 13 | * @author mudkip 14 | */ 15 | record OptionalBinaryCodec(BinaryCodec parent) implements BinaryCodec> { 16 | @Override 17 | public Optional read(ByteBuf buffer) { 18 | if (BOOLEAN.read(buffer)) { 19 | return Optional.of(this.parent.read(buffer)); 20 | } else { 21 | return Optional.empty(); 22 | } 23 | } 24 | 25 | @Override 26 | public void write(ByteBuf buffer, Optional optional) { 27 | BOOLEAN.write(buffer, optional.isPresent()); 28 | optional.ifPresent(value -> this.parent.write(buffer, value)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /binary/src/main/java/alpine/binary/PrimitiveBinaryCodecs.java: -------------------------------------------------------------------------------- 1 | package alpine.binary; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | import static alpine.binary.BinaryCodec.of; 6 | 7 | /** 8 | * Built-in binary codecs for Java's primitive types. 9 | * @author mudkip 10 | */ 11 | interface PrimitiveBinaryCodecs { 12 | /** 13 | * A binary codec which serializes a boolean as a {@code 0} or {@code 1} value. 14 | * If the value is {@code 0}, then {@code false} is returned. Otherwise, {@code true} is returned. 15 | */ 16 | BinaryCodec BOOLEAN = of(ByteBuf::readBoolean, ByteBuf::writeBoolean); 17 | 18 | /** 19 | * A binary codec which serializes a signed 8-bit integer. 20 | */ 21 | BinaryCodec BYTE = of(ByteBuf::readByte, (buffer, value) -> buffer.writeByte(value)); 22 | 23 | /** 24 | * A binary codec which serializes a two byte UTF-16 character. 25 | */ 26 | BinaryCodec CHARACTER = of(ByteBuf::readChar, (buffer, value) -> buffer.writeChar(Character.getNumericValue(value))); 27 | 28 | /** 29 | * A binary codec which serializes a signed 16-bit integer. 30 | */ 31 | BinaryCodec SHORT = of(ByteBuf::readShort, (buffer, value) -> buffer.writeShort(value)); 32 | 33 | /** 34 | * A binary codec which serializes a signed 32-bit integer. 35 | */ 36 | BinaryCodec INTEGER = of(ByteBuf::readInt, ByteBuf::writeInt); 37 | 38 | /** 39 | * A binary codec which serializes a signed 64-bit integer. 40 | */ 41 | BinaryCodec LONG = of(ByteBuf::readLong, ByteBuf::writeLong); 42 | 43 | /** 44 | * A binary codec which serializes a signed 32-bit floating-point decimal. 45 | */ 46 | BinaryCodec FLOAT = of(ByteBuf::readFloat, ByteBuf::writeFloat); 47 | 48 | /** 49 | * A binary codec which serializes a signed 64-bit floating-point decimal. 50 | */ 51 | BinaryCodec DOUBLE = of(ByteBuf::readDouble, ByteBuf::writeDouble); 52 | } 53 | -------------------------------------------------------------------------------- /binary/src/main/java/alpine/binary/StandardBinaryCodecs.java: -------------------------------------------------------------------------------- 1 | package alpine.binary; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | import javax.imageio.ImageIO; 6 | import java.awt.image.BufferedImage; 7 | import java.io.ByteArrayInputStream; 8 | import java.io.ByteArrayOutputStream; 9 | import java.io.IOException; 10 | import java.nio.charset.StandardCharsets; 11 | import java.util.UUID; 12 | 13 | import static alpine.binary.ArrayBinaryCodecs.BYTE_ARRAY; 14 | import static alpine.binary.BinaryCodec.LONG; 15 | 16 | /** 17 | * Built-in binary codecs for Java's standard library types. 18 | * @author mudkip 19 | */ 20 | interface StandardBinaryCodecs { 21 | BinaryCodec STRING = new StringBinaryCodec(StandardCharsets.UTF_8); 22 | 23 | /** 24 | * A binary codec which serializes a UUID as two signed 64-bit integers. 25 | * @see java.util.UUID 26 | */ 27 | BinaryCodec UUID = BinaryTemplate.of( 28 | LONG, java.util.UUID::getMostSignificantBits, 29 | LONG, java.util.UUID::getLeastSignificantBits, 30 | UUID::new); 31 | 32 | /** 33 | * Returns binary codec which serializes an image. 34 | * @return A binary codec which serializes an image. 35 | * @see java.awt.image.BufferedImage 36 | */ 37 | static BinaryCodec image(String format) { 38 | return BYTE_ARRAY.map( 39 | array -> { 40 | try (var stream = new ByteArrayInputStream(array)) { 41 | return ImageIO.read(stream); 42 | } catch (IOException e) { 43 | throw new RuntimeException("Failed to read image!", e); 44 | } 45 | }, 46 | image -> { 47 | try { 48 | var stream = new ByteArrayOutputStream(); 49 | ImageIO.write(image, format, stream); 50 | return stream.toByteArray(); 51 | } catch (IOException e) { 52 | throw new RuntimeException("Failed to write image!", e); 53 | } 54 | }); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /binary/src/main/java/alpine/binary/StringBinaryCodec.java: -------------------------------------------------------------------------------- 1 | package alpine.binary; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | import java.nio.charset.Charset; 6 | 7 | /** 8 | * A binary codec which serializes a sequence of characters. 9 | * @param charset The encoding to serialize the string with. 10 | * @author mudkip 11 | */ 12 | record StringBinaryCodec(Charset charset) implements BinaryCodec { 13 | @Override 14 | public String read(ByteBuf buffer) { 15 | var length = BinaryCodec.VARINT.read(buffer); 16 | return String.valueOf(buffer.readCharSequence(length, this.charset)); 17 | } 18 | 19 | @Override 20 | public void write(ByteBuf buffer, String value) { 21 | BinaryCodec.VARINT.write(buffer, value.length()); 22 | buffer.writeCharSequence(value, this.charset); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /binary/src/main/java/alpine/binary/VariableBinaryCodecs.java: -------------------------------------------------------------------------------- 1 | package alpine.binary; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | /** 6 | * Implements VarInt and VarLong binary codecs. 7 | * @author mudkip 8 | */ 9 | interface VariableBinaryCodecs { 10 | /** 11 | * LEB128 encoded. Uses between 1 and 5 bytes. 12 | */ 13 | BinaryCodec VARINT = new BinaryCodec<>() { 14 | private static final int SEGMENT_BITS = 0x7F; 15 | private static final int CONTINUE_BIT = 0x80; 16 | 17 | @Override 18 | public Integer read(ByteBuf buffer) { 19 | var readable = buffer.readableBytes(); 20 | var k = buffer.readByte(); 21 | 22 | if ((k & CONTINUE_BIT) != 128) { 23 | return (int) k; 24 | } 25 | 26 | var maxRead = Math.min(5, readable); 27 | var i = k & SEGMENT_BITS; 28 | 29 | for (var j = 1; j < maxRead; j++) { 30 | k = buffer.readByte(); 31 | i |= (k & SEGMENT_BITS) << j * 7; 32 | 33 | if ((k & CONTINUE_BIT) != 128) { 34 | return i; 35 | } 36 | } 37 | 38 | return 0; 39 | } 40 | 41 | @Override 42 | public void write(ByteBuf buffer, Integer value) { 43 | while (true) { 44 | if ((value & 0xFFFFFF80) == 0) { 45 | buffer.writeByte(value); 46 | return; 47 | } 48 | 49 | buffer.writeByte(value & SEGMENT_BITS | CONTINUE_BIT); 50 | value >>>= 7; 51 | } 52 | } 53 | }; 54 | } 55 | -------------------------------------------------------------------------------- /binary/src/test/java/alpine/binary/CodecTest.java: -------------------------------------------------------------------------------- 1 | package alpine.binary; 2 | 3 | import io.netty.buffer.Unpooled; 4 | import org.junit.jupiter.params.ParameterizedTest; 5 | import org.junit.jupiter.params.provider.Arguments; 6 | import org.junit.jupiter.params.provider.MethodSource; 7 | 8 | import java.util.Arrays; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | import java.util.stream.Stream; 12 | 13 | final class CodecTest { 14 | static Stream arguments() { 15 | return Stream.of( 16 | // Boolean 17 | Arguments.of("Boolean", BinaryCodec.BOOLEAN, false, new byte[] {0}), 18 | Arguments.of("Boolean", BinaryCodec.BOOLEAN, true, new byte[] {1}), 19 | 20 | // String 21 | Arguments.of("String", BinaryCodec.STRING, "ABC", new byte[] {3, 65, 66, 67}), 22 | 23 | // Either 24 | Arguments.of( 25 | "Either", 26 | BinaryCodec.either(BinaryCodec.INTEGER, BinaryCodec.STRING), 27 | Either.right("A"), 28 | new byte[] {1, 1, 65}), 29 | 30 | // Optional 31 | Arguments.of("Optional", BinaryCodec.BOOLEAN.optional(), Optional.empty(), new byte[] {0}), 32 | Arguments.of("Optional", BinaryCodec.INTEGER.optional(), Optional.of(3), new byte[] {1, 0, 0, 0, 3})); 33 | } 34 | 35 | @ParameterizedTest(name = "{0} (encoding)") 36 | @MethodSource("arguments") 37 | void testEncoding(String label, BinaryCodec codec, T value, byte[] data) { 38 | var buffer = Unpooled.buffer(); 39 | codec.write(buffer, value); 40 | var array = new byte[buffer.readableBytes()]; 41 | buffer.getBytes(buffer.readerIndex(), array); 42 | 43 | assert Arrays.equals(array, data) : String.format( 44 | "Expected %s while encoding, got %s.", 45 | Arrays.toString(data), 46 | Arrays.toString(array)); 47 | } 48 | 49 | @ParameterizedTest(name = "{0} (decoding)") 50 | @MethodSource("arguments") 51 | void testDecoding(String label, BinaryCodec codec, T value, byte[] data) { 52 | var buffer = Unpooled.buffer(); 53 | buffer.writeBytes(data); 54 | var actualValue = codec.read(buffer); 55 | 56 | assert Objects.equals(actualValue, value) : String.format( 57 | "Expected %s while decoding, got %s.", value, actualValue); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.vanniktech.maven.publish.SonatypeHost 2 | 3 | plugins { 4 | java 5 | signing 6 | id("com.vanniktech.maven.publish") version "0.33.0" 7 | } 8 | 9 | subprojects { 10 | apply(plugin = "java") 11 | apply(plugin = "signing") 12 | apply(plugin = "com.vanniktech.maven.publish") 13 | 14 | group = "dev.mudkip" 15 | version = "0.1.1" 16 | java.toolchain.languageVersion = JavaLanguageVersion.of(21) 17 | 18 | repositories { 19 | mavenCentral() 20 | } 21 | 22 | dependencies { 23 | compileOnly("org.jetbrains:annotations:26.0.2") 24 | testImplementation("org.junit.jupiter:junit-jupiter-api:5.13.3") 25 | testImplementation("org.junit.jupiter:junit-jupiter-params:5.13.3") 26 | testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.13.3") 27 | testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.13.3") 28 | } 29 | 30 | tasks.test { 31 | useJUnitPlatform() 32 | } 33 | 34 | mavenPublishing { 35 | coordinates(group.toString(), "${rootProject.name}-${project.name}", version.toString()) 36 | publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) 37 | signAllPublications() 38 | 39 | pom { 40 | name = project.name 41 | description = project.description 42 | url = "https://github.com/mudkipdev/alpine" 43 | 44 | licenses { 45 | license { 46 | name = "MIT" 47 | url = "https://github.com/mudkipdev/alpine/blob/main/LICENSE" 48 | } 49 | } 50 | 51 | developers { 52 | developer { 53 | name = "mudkip" 54 | id = "mudkipdev" 55 | email = "mudkip@mudkip.dev" 56 | url = "https://mudkip.dev" 57 | } 58 | } 59 | 60 | scm { 61 | url = "https://github.com/mudkipdev/alpine" 62 | connection = "scm:git:git://github.com/mudkipdev/alpine.git" 63 | developerConnection = "scm:git:ssh://git@github.com/mudkipdev/alpine.git" 64 | } 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mudkipdev/alpine/d166de42749d1f2cf61e6b5e7658c27a16abbf54/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH="\\\"\\\"" 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | if ! command -v java >/dev/null 2>&1 137 | then 138 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 139 | 140 | Please set the JAVA_HOME variable in your environment to match the 141 | location of your Java installation." 142 | fi 143 | fi 144 | 145 | # Increase the maximum file descriptors if we can. 146 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 147 | case $MAX_FD in #( 148 | max*) 149 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 150 | # shellcheck disable=SC2039,SC3045 151 | MAX_FD=$( ulimit -H -n ) || 152 | warn "Could not query maximum file descriptor limit" 153 | esac 154 | case $MAX_FD in #( 155 | '' | soft) :;; #( 156 | *) 157 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 158 | # shellcheck disable=SC2039,SC3045 159 | ulimit -n "$MAX_FD" || 160 | warn "Could not set maximum file descriptor limit to $MAX_FD" 161 | esac 162 | fi 163 | 164 | # Collect all arguments for the java command, stacking in reverse order: 165 | # * args from the command line 166 | # * the main class name 167 | # * -classpath 168 | # * -D...appname settings 169 | # * --module-path (only if needed) 170 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 171 | 172 | # For Cygwin or MSYS, switch paths to Windows format before running java 173 | if "$cygwin" || "$msys" ; then 174 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 175 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 176 | 177 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 178 | 179 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 180 | for arg do 181 | if 182 | case $arg in #( 183 | -*) false ;; # don't mess with options #( 184 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 185 | [ -e "$t" ] ;; #( 186 | *) false ;; 187 | esac 188 | then 189 | arg=$( cygpath --path --ignore --mixed "$arg" ) 190 | fi 191 | # Roll the args list around exactly as many times as the number of 192 | # args, so each arg winds up back in the position where it started, but 193 | # possibly modified. 194 | # 195 | # NB: a `for` loop captures its iteration list before it begins, so 196 | # changing the positional parameters here affects neither the number of 197 | # iterations, nor the values presented in `arg`. 198 | shift # remove old arg 199 | set -- "$@" "$arg" # push replacement arg 200 | done 201 | fi 202 | 203 | 204 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 205 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 206 | 207 | # Collect all arguments for the java command: 208 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 209 | # and any embedded shellness will be escaped. 210 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 211 | # treated as '${Hostname}' itself on the command line. 212 | 213 | set -- \ 214 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 215 | -classpath "$CLASSPATH" \ 216 | -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ 217 | "$@" 218 | 219 | # Stop when "xargs" is not available. 220 | if ! command -v xargs >/dev/null 2>&1 221 | then 222 | die "xargs is not available" 223 | fi 224 | 225 | # Use "xargs" to parse quoted args. 226 | # 227 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 228 | # 229 | # In Bash we could simply go: 230 | # 231 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 232 | # set -- "${ARGS[@]}" "$@" 233 | # 234 | # but POSIX shell has neither arrays nor command substitution, so instead we 235 | # post-process each arg (as a line of input to sed) to backslash-escape any 236 | # character that might be a shell metacharacter, then use eval to reverse 237 | # that process (while maintaining the separation between arguments), and wrap 238 | # the whole thing up as a single "set" statement. 239 | # 240 | # This will of course break if any of these variables contains a newline or 241 | # an unmatched quote. 242 | # 243 | 244 | eval "set -- $( 245 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 246 | xargs -n1 | 247 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 248 | tr '\n' ' ' 249 | )" '"$@"' 250 | 251 | exec "$JAVACMD" "$@" 252 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH= 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "alpine" 2 | include("binary") --------------------------------------------------------------------------------