diff options
| author | Michael Williamson <mike@zwobble.org> | 2026-07-11 15:47:22 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2026-07-11 15:47:22 +0100 |
| commit | f9fe80fa50e6ac0c3121c0dde6420c79973c4ccc (patch) | |
| tree | 77009b5272acfa7cbfc999bc023fad9970f1404e | |
| parent | c80835cf60e3d772152fd1873dde76d41fa6cec2 (diff) | |
Support options in Java transient-0
4 files changed, 135 insertions, 0 deletions
diff --git a/examples/10-transient-0/output/java-junit/src/test/java/org/zwobble/example/Transient0Tests.java b/examples/10-transient-0/output/java-junit/src/test/java/org/zwobble/example/Transient0Tests.java index b7e841c..40acde4 100644 --- a/examples/10-transient-0/output/java-junit/src/test/java/org/zwobble/example/Transient0Tests.java +++ b/examples/10-transient-0/output/java-junit/src/test/java/org/zwobble/example/Transient0Tests.java @@ -4,6 +4,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.List; +import java.util.Optional; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.zwobble.example.types.data.HobgoblinTransient0Data; @@ -13,6 +14,7 @@ import org.zwobble.example.types.data.StructWithBool; import org.zwobble.example.types.data.StructWithInt32; import org.zwobble.example.types.data.StructWithInt64; import org.zwobble.example.types.data.StructWithList; +import org.zwobble.example.types.data.StructWithOption; import org.zwobble.example.types.data.StructWithString; public class Transient0Tests { @@ -106,4 +108,38 @@ public class Transient0Tests { Assertions.assertEquals(value, decodedValue); } + + @Test + public void structWithOptionNone() throws IOException { + var value = new StructWithOption( + Optional.empty(), + Optional.empty() + ); + + var outputStream = new ByteArrayOutputStream(); + HobgoblinTransient0Data.encodeStructWithOption(value, outputStream); + var bytes = outputStream.toByteArray(); + + var inputStream = new ByteArrayInputStream(bytes); + var decodedValue = HobgoblinTransient0Data.decodeStructWithOption(inputStream); + + Assertions.assertEquals(value, decodedValue); + } + + @Test + public void structWithOptionSome() throws IOException { + var value = new StructWithOption( + Optional.of(10L), + Optional.of(new InnerStruct(42, 47)) + ); + + var outputStream = new ByteArrayOutputStream(); + HobgoblinTransient0Data.encodeStructWithOption(value, outputStream); + var bytes = outputStream.toByteArray(); + + var inputStream = new ByteArrayInputStream(bytes); + var decodedValue = HobgoblinTransient0Data.decodeStructWithOption(inputStream); + + Assertions.assertEquals(value, decodedValue); + } } diff --git a/examples/10-transient-0/src/data.hob b/examples/10-transient-0/src/data.hob index 8550d6d..80ba8e5 100644 --- a/examples/10-transient-0/src/data.hob +++ b/examples/10-transient-0/src/data.hob @@ -32,3 +32,8 @@ struct StructWithList { field a: List[Int64]; field b: List[InnerStruct]; } + +struct StructWithOption { + field a: Option[Int64]; + field b: Option[InnerStruct]; +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatransient0/JavaTransient0Generator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatransient0/JavaTransient0Generator.java index 5feba05..59dcefe 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatransient0/JavaTransient0Generator.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatransient0/JavaTransient0Generator.java @@ -433,6 +433,8 @@ public class JavaTransient0Generator implements Generator { case ConstructedNativeType constructedNativeType -> { if (constructedNativeType.constructor().equals(NativeTypes.LIST)) { yield generateEncodeList(value, constructedNativeType.args().getFirst()); + } else if (constructedNativeType.constructor().equals(NativeTypes.OPTION)) { + yield generateEncodeOption(value, constructedNativeType.args().getFirst()); } else { throw new UnsupportedOperationException("TODO"); } @@ -491,6 +493,8 @@ public class JavaTransient0Generator implements Generator { case ConstructedNativeType constructedNativeType -> { if (constructedNativeType.constructor().equals(NativeTypes.LIST)) { yield generateDecodeList(target, constructedNativeType.args().getFirst()); + } else if (constructedNativeType.constructor().equals(NativeTypes.OPTION)) { + yield generateDecodeOption(target, constructedNativeType.args().getFirst()); } else { throw new UnsupportedOperationException("TODO"); } @@ -633,6 +637,88 @@ public class JavaTransient0Generator implements Generator { return statements; } + private List<JavaBlockStatement> generateEncodeOption( + JavaExpression value, + Type elementType + ) { + var statements = new ArrayList<JavaBlockStatement>(); + var isPresent = new JavaMethodCall( + value, + JavaIdentifier.of("isPresent"), + List.of() + ); + + statements.addAll(generateEncode( + isPresent, + NativeTypes.BOOL + )); + + statements.add(new JavaIfStatement( + isPresent, + new JavaBlock(generateEncode( + new JavaMethodCall( + value, + JavaIdentifier.of("get"), + List.of() + ), + elementType + )), + new JavaBlock(List.of()) + )); + + return statements; + } + + private List<JavaBlockStatement> generateDecodeOption( + JavaIdentifier target, + Type elementType + ) { + var isPresent = JavaIdentifier.of(target.value() + "$isPresent"); + var element = JavaIdentifier.of(target.value() + "$element"); + + var statements = new ArrayList<JavaBlockStatement>(); + + statements.addAll(generateDecode(isPresent, NativeTypes.BOOL)); + + statements.add(new JavaLocalVariableDeclaration( + Optional.of(JavaTypeRef.optional(this.javaGenerator.generateReferenceTypeRef(elementType))), + target, + Optional.empty() + )); + + var ifTrue = new ArrayList<JavaBlockStatement>(); + + ifTrue.addAll(generateDecode(element, elementType)); + + ifTrue.add(new JavaExpressionStatement(new JavaBinaryOperation( + JavaBinaryOperator.ASSIGN, + new JavaRef(target), + new JavaStaticMethodCall( + JavaTypeRef.OPTIONAL, + JavaIdentifier.of("of"), + List.of(new JavaRef(element)) + ) + ))); + + statements.add(new JavaIfStatement( + new JavaRef(isPresent), + new JavaBlock(ifTrue), + new JavaBlock(List.of( + new JavaExpressionStatement(new JavaBinaryOperation( + JavaBinaryOperator.ASSIGN, + new JavaRef(target), + new JavaStaticMethodCall( + JavaTypeRef.OPTIONAL, + JavaIdentifier.of("empty"), + List.of() + ) + )) + )) + )); + + return statements; + } + private static JavaMethodCall generateOutputStreamWrite(JavaExpression byteToWrite) { return new JavaMethodCall( new JavaRef(OUTPUT_STREAM_NAME), diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/java/ast/JavaTypeRef.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/java/ast/JavaTypeRef.java index 0975e4e..8dbca61 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/java/ast/JavaTypeRef.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/java/ast/JavaTypeRef.java @@ -75,6 +75,14 @@ public record JavaTypeRef(JavaPackageName packageName, List<JavaIdentifier> type public static final JavaTypeRef OPTIONAL = topLevel(JavaPackages.JAVA_UTIL, JavaIdentifier.of("Optional")); + public static JavaTypeRef optional(JavaTypeRef elementType) { + return new JavaTypeRef( + OPTIONAL.packageName, + OPTIONAL.typeNames, + List.of(JavaTypeArg.invariant(elementType)) + ); + } + public static final JavaTypeRef OUTPUT_STREAM = topLevel(JavaPackages.JAVA_IO, JavaIdentifier.of("OutputStream")); public static final JavaTypeRef STANDARD_CHARSETS = topLevel(JavaPackages.JAVA_NIO_CHARSET, JavaIdentifier.of("StandardCharsets")); |
