Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,13 @@ public enum EnumWithBacktick {
case `let`
case `default`
}

public enum EnumWithCaseNameValue {
case success(Success)
public struct Success {
public init(message: String) {
self.message = message
}
public var message: String
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ public void afterAll() {
}

@Benchmark
public Vehicle.Motorbike getAssociatedValues(BenchmarkState state, Blackhole bh) {
Vehicle.Motorbike motorbike = state.vehicle.getAsMotorbike().orElseThrow();
public Vehicle.Case.Motorbike getAssociatedValues(BenchmarkState state, Blackhole bh) {
Vehicle.Case.Motorbike motorbike = state.vehicle.getAsMotorbike().orElseThrow();
bh.consume(motorbike.arg0());
bh.consume(motorbike.horsePower());
return motorbike;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class EnumTest {
void enumWithValueCases() {
try (var arena = SwiftArena.ofConfined()) {
EnumWithValueCases e = EnumWithValueCases.firstCase(48, arena);
EnumWithValueCases.FirstCase c = (EnumWithValueCases.FirstCase) e.getCase();
EnumWithValueCases.Case.FirstCase c = (EnumWithValueCases.Case.FirstCase) e.getCase();
assertNotNull(c);
}
}
Expand All @@ -36,4 +36,17 @@ void enumWithBacktick() {
assertTrue(e.getAsDefault().isPresent());
}
}

@Test
void enumWithCaseNameValue() {
try (var arena = SwiftArena.ofConfined()) {
var success = EnumWithCaseNameValue.Success.init("ok", arena);
EnumWithCaseNameValue e = EnumWithCaseNameValue.success(success, arena);

switch (e.getCase(arena)) {
case EnumWithCaseNameValue.Case.Success(var s):
assertEquals("ok", s.getMessage());
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ void genericEnum() {
try (var arena = SwiftArena.ofConfined()) {
GenericEnum<Long> value = MySwiftLibrary.makeIntGenericEnum(arena);
switch (value.getCase()) {
case GenericEnum.Foo _ -> assertTrue(value.getAsFoo().isPresent());
case GenericEnum.Bar _ -> assertTrue(value.getAsBar().isPresent());
case GenericEnum.Case.Foo _ -> assertTrue(value.getAsFoo().isPresent());
case GenericEnum.Case.Bar _ -> assertTrue(value.getAsBar().isPresent());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ void upgrade() {
void getAsBicycle() {
try (var arena = SwiftArena.ofConfined()) {
Vehicle vehicle = Vehicle.bicycle(arena);
Vehicle.Bicycle bicycle = vehicle.getAsBicycle().orElseThrow();
Vehicle.Case.Bicycle bicycle = vehicle.getAsBicycle().orElseThrow();
assertNotNull(bicycle);
}
}
Expand All @@ -101,7 +101,7 @@ void getAsBicycle() {
void getAsCar() {
try (var arena = SwiftArena.ofConfined()) {
Vehicle vehicle = Vehicle.car("BMW", Optional.empty(), arena);
Vehicle.Car car = vehicle.getAsCar().orElseThrow();
Vehicle.Case.Car car = vehicle.getAsCar().orElseThrow();
assertEquals("BMW", car.arg0());

vehicle = Vehicle.car("BMW", Optional.of("Long trailer"), arena);
Expand All @@ -114,7 +114,7 @@ void getAsCar() {
void getAsMotorbike() {
try (var arena = SwiftArena.ofConfined()) {
Vehicle vehicle = Vehicle.motorbike("Yamaha", 750, OptionalInt.empty(), arena);
Vehicle.Motorbike motorbike = vehicle.getAsMotorbike().orElseThrow();
Vehicle.Case.Motorbike motorbike = vehicle.getAsMotorbike().orElseThrow();
assertEquals("Yamaha", motorbike.arg0());
assertEquals(750, motorbike.horsePower());
assertEquals(OptionalInt.empty(), motorbike.helmets());
Expand All @@ -129,7 +129,7 @@ void getAsMotorbike() {
void getAsTransformer() {
try (var arena = SwiftArena.ofConfined()) {
Vehicle vehicle = Vehicle.transformer(Vehicle.bicycle(arena), Vehicle.car("BMW", Optional.empty(), arena), arena);
Vehicle.Transformer transformer = vehicle.getAsTransformer(arena).orElseThrow();
Vehicle.Case.Transformer transformer = vehicle.getAsTransformer(arena).orElseThrow();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The alternative would be to Vehicle.TransformerCase or Vehicle.$Transformer hm... The $ in the name is not ideal perhaps, we usually tell folks that things with $ in the name are "not for them" but the Case sufficient could work without the additional nesting...

WDYT, any opinions @madsodgaard ?

assertTrue(transformer.front().getAsBicycle().isPresent());
assertEquals("BMW", transformer.back().getAsCar().orElseThrow().arg0());
}
Expand All @@ -139,7 +139,7 @@ void getAsTransformer() {
void getAsBoat() {
try (var arena = SwiftArena.ofConfined()) {
Vehicle vehicle = Vehicle.boat(OptionalInt.of(10), Optional.of((short) 1), arena);
Vehicle.Boat boat = vehicle.getAsBoat().orElseThrow();
Vehicle.Case.Boat boat = vehicle.getAsBoat().orElseThrow();
assertEquals(OptionalInt.of(10), boat.passengers());
assertEquals(Optional.of((short) 1), boat.length());
}
Expand All @@ -149,10 +149,10 @@ void getAsBoat() {
void associatedValuesAreCopied() {
try (var arena = SwiftArena.ofConfined()) {
Vehicle vehicle = Vehicle.car("BMW", Optional.empty(), arena);
Vehicle.Car car = vehicle.getAsCar().orElseThrow();
Vehicle.Case.Car car = vehicle.getAsCar().orElseThrow();
assertEquals("BMW", car.arg0());
vehicle.upgrade();
Vehicle.Motorbike motorbike = vehicle.getAsMotorbike().orElseThrow();
Vehicle.Case.Motorbike motorbike = vehicle.getAsMotorbike().orElseThrow();
assertNotNull(motorbike);
// Motorbike should still remain
assertEquals("BMW", car.arg0());
Expand All @@ -174,7 +174,7 @@ void getCase() {
try (var arena = SwiftArena.ofConfined()) {
Vehicle vehicle = Vehicle.bicycle(arena);
Vehicle.Case caseElement = vehicle.getCase(arena);
assertInstanceOf(Vehicle.Bicycle.class, caseElement);
assertInstanceOf(Vehicle.Case.Bicycle.class, caseElement);
}
}

Expand All @@ -183,23 +183,23 @@ void switchGetCase() {
try (var arena = SwiftArena.ofConfined()) {
Vehicle vehicle = Vehicle.car("BMW", Optional.empty(), arena);
switch (vehicle.getCase(arena)) {
case Vehicle.Bicycle b:
case Vehicle.Case.Bicycle b:
fail("Was bicycle");
break;
case Vehicle.Car car:
case Vehicle.Case.Car car:
assertEquals("BMW", car.arg0());
break;
case Vehicle.Motorbike motorbike:
case Vehicle.Case.Motorbike motorbike:
fail("Was motorbike");
break;
case Vehicle.Transformer transformer:
case Vehicle.Case.Transformer transformer:
fail("Was transformer");
break;
case Vehicle.Boat b:
case Vehicle.Case.Boat b:
fail("Was boat");
break;
}
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,30 @@ extension JNISwift2JavaGenerator {
return
}

printer.print("public sealed interface Case {}")
printer.printBraceBlock("public sealed interface Case") { printer in
for enumCase in decl.cases {
guard let translatedCase = self.translatedEnumCase(for: enumCase) else {
continue
}

let members = translatedCase.translatedValues.map {
$0.parameter.renderParameter()
}
let caseName = enumCase.name.firstCharacterUppercased

// Print record
printer.printBraceBlock("record \(caseName)(\(members.joined(separator: ", "))) implements Case") {
printer in
let nativeParameters = zip(translatedCase.translatedValues, translatedCase.parameterConversions).map {
value,
conversion in
"\(conversion.native.javaType) \(value.parameter.name)"
}

printer.print("record _NativeParameters(\(nativeParameters.joined(separator: ", "))) {}")
}
}
}
printer.println()

let requiresSwiftArena = decl.cases.compactMap {
Expand Down Expand Up @@ -539,24 +562,6 @@ extension JNISwift2JavaGenerator {
return
}

let members = translatedCase.translatedValues.map {
$0.parameter.renderParameter()
}

let caseName = enumCase.name.firstCharacterUppercased

// Print record
printer.printBraceBlock("public record \(caseName)(\(members.joined(separator: ", "))) implements Case") {
printer in
let nativeParameters = zip(translatedCase.translatedValues, translatedCase.parameterConversions).map {
value,
conversion in
"\(conversion.native.javaType) \(value.parameter.name)"
}

printer.print("record _NativeParameters(\(nativeParameters.joined(separator: ", "))) {}")
}

self.printJavaBindingWrapperMethod(&printer, translatedCase.getAsCaseFunction, skipMethodBody: false)
printer.println()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ extension JNISwift2JavaGenerator {

let caseName = enumCase.name.firstCharacterUppercased
let enumName = enumCase.enumType.nominalTypeDecl.name
let nativeParametersType = JavaType.class(package: nil, name: "\(caseName)._NativeParameters")
let caseType = JavaType.class(package: nil, name: "Case.\(caseName)")
let nativeParametersType = JavaType.class(package: nil, name: "Case.\(caseName)._NativeParameters")
let getAsCaseName = "getAs\(caseName)"
// If the case has no parameters, we can skip the native call.
let constructRecordConversion = JavaNativeConversionStep.method(
Expand All @@ -138,7 +139,7 @@ extension JNISwift2JavaGenerator {
arguments: [
.constructJavaClass(
.commaSeparated(conversions.map(\.translated.conversion)),
.class(package: nil, name: caseName),
caseType,
)
],
)
Expand Down Expand Up @@ -179,7 +180,7 @@ extension JNISwift2JavaGenerator {
),
parameters: [],
resultType: TranslatedResult(
javaType: .class(package: nil, name: "Optional", typeParameters: [.class(package: nil, name: caseName)]),
javaType: .optional(caseType),
outParameters: conversions.flatMap(\.translated.outParameters),
conversion: enumCase.parameters.isEmpty
? constructRecordConversion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ extension JNISwift2JavaGenerator {
}

private func renderEnumCaseCacheInit(_ enumCase: TranslatedEnumCase) -> String {
let nativeParametersClassName = "\(enumCase.enumName)$\(enumCase.name)$_NativeParameters"
let nativeParametersClassName = "\(enumCase.enumName)$Case$\(enumCase.name)$_NativeParameters"
let methodSignature = MethodSignature(
resultType: .void,
parameterTypes: enumCase.parameterConversions.map(\.native.javaType),
Expand Down
5 changes: 5 additions & 0 deletions Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ extension JavaType {
.class(package: "java.lang", name: "Object")
}

/// The description of the type java.util.Optional.
static func optional(_ T: JavaType) -> JavaType {
.class(package: "java.util", name: "Optional", typeParameters: [T])
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice


/// The description of the type java.util.concurrent.CompletableFuture<T>
static func completableFuture(_ T: JavaType) -> JavaType {
.class(package: "java.util.concurrent", name: "CompletableFuture", typeParameters: [T.boxedType])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ You can then instantiate a case of `Vehicle` by using one of the static methods:
```java
try (var arena = SwiftArena.ofConfined()) {
Vehicle vehicle = Vehicle.car("BMW", arena);
Optional<Vehicle.Car> car = vehicle.getAsCar();
Optional<Vehicle.Case.Car> car = vehicle.getAsCar();
assertEquals("BMW", car.orElseThrow().arg0());
}
```
Expand All @@ -217,10 +217,10 @@ As you can see above, to access the associated values of a case you can call one
```java
try (var arena = SwiftArena.ofConfined()) {
Vehicle vehicle = Vehicle.bycicle("My Brand", arena);
Optional<Vehicle.Car> car = vehicle.getAsCar();
Optional<Vehicle.Case.Car> car = vehicle.getAsCar();
assertFalse(car.isPresent());

Optional<Vehicle.Bicycle> bicycle = vehicle.getAsBicycle();
Optional<Vehicle.Case.Bicycle> bicycle = vehicle.getAsBicycle();
assertEquals("My Brand", bicycle.orElseThrow().maker());
}
```
Expand All @@ -246,10 +246,10 @@ If you are running Java 21+ you can use [pattern matching for switch](https://op
```java
Vehicle vehicle = ...;
switch (vehicle.getCase()) {
case Vehicle.Bicycle b:
case Vehicle.Case.Bicycle b:
System.out.println("Bicycle maker: " + b.maker());
break;
case Vehicle.Car c:
case Vehicle.Case.Car c:
System.out.println("Car: " + c.arg0());
break;
}
Expand All @@ -258,7 +258,7 @@ or even, destructuring the records in the switch statement's pattern match direc
```java
Vehicle vehicle = ...;
switch (vehicle.getCase()) {
case Vehicle.Car(var name, var unused):
case Vehicle.Case.Car(var name, var unused):
System.out.println("Car: " + name);
break;
default:
Expand All @@ -270,21 +270,21 @@ For Java 16+ you can use [pattern matching for instanceof](https://openjdk.org/j
```java
Vehicle vehicle = ...;
Vehicle.Case case = vehicle.getCase();
if (case instanceof Vehicle.Bicycle b) {
if (case instanceof Vehicle.Case.Bicycle b) {
System.out.println("Bicycle maker: " + b.maker());
} else if(case instanceof Vehicle.Car c) {
} else if(case instanceof Vehicle.Case.Car c) {
System.out.println("Car: " + c.arg0());
}
```
For any previous Java versions you can resort to casting the `Case` to the expected type:
```java
Vehicle vehicle = ...;
Vehicle.Case case = vehicle.getCase();
if (case instanceof Vehicle.Bicycle) {
Vehicle.Bicycle b = (Vehicle.Bicycle) case;
if (case instanceof Vehicle.Case.Bicycle) {
Vehicle.Bicycle b = (Vehicle.Case.Bicycle) case;
System.out.println("Bicycle maker: " + b.maker());
} else if(case instanceof Vehicle.Car) {
Vehicle.Car c = (Vehicle.Car) case;
} else if(case instanceof Vehicle.Case.Car) {
Vehicle.Car c = (Vehicle.Case.Car) case;
System.out.println("Car: " + c.arg0());
}
```
Expand Down
Loading
Loading