Skip to content

Commit bd224aa

Browse files
committed
Move case classes into Case interface block.
1 parent 41fc310 commit bd224aa

12 files changed

Lines changed: 112 additions & 83 deletions

File tree

Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Enums.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,13 @@ public enum EnumWithBacktick {
2121
case `let`
2222
case `default`
2323
}
24+
25+
public enum EnumWithCaseNameValue {
26+
case success(Success)
27+
public struct Success {
28+
public init(message: String) {
29+
self.message = message
30+
}
31+
public var message: String
32+
}
33+
}

Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/EnumTest.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public class EnumTest {
2424
void enumWithValueCases() {
2525
try (var arena = SwiftArena.ofConfined()) {
2626
EnumWithValueCases e = EnumWithValueCases.firstCase(48, arena);
27-
EnumWithValueCases.FirstCase c = (EnumWithValueCases.FirstCase) e.getCase();
27+
EnumWithValueCases.Case.FirstCase c = (EnumWithValueCases.Case.FirstCase) e.getCase();
2828
assertNotNull(c);
2929
}
3030
}
@@ -36,4 +36,17 @@ void enumWithBacktick() {
3636
assertTrue(e.getAsDefault().isPresent());
3737
}
3838
}
39+
40+
@Test
41+
void enumWithCaseNameValue() {
42+
try (var arena = SwiftArena.ofConfined()) {
43+
var success = EnumWithCaseNameValue.Success.init("ok", arena);
44+
EnumWithCaseNameValue e = EnumWithCaseNameValue.success(success, arena);
45+
46+
switch (e.getCase(arena)) {
47+
case EnumWithCaseNameValue.Case.Success(var s):
48+
assertEquals("ok", s.getMessage());
49+
}
50+
}
51+
}
3952
}

Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/GenericTypeTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ void genericEnum() {
6565
try (var arena = SwiftArena.ofConfined()) {
6666
GenericEnum<Long> value = MySwiftLibrary.makeIntGenericEnum(arena);
6767
switch (value.getCase()) {
68-
case GenericEnum.Foo _ -> assertTrue(value.getAsFoo().isPresent());
69-
case GenericEnum.Bar _ -> assertTrue(value.getAsBar().isPresent());
68+
case GenericEnum.Case.Foo _ -> assertTrue(value.getAsFoo().isPresent());
69+
case GenericEnum.Case.Bar _ -> assertTrue(value.getAsBar().isPresent());
7070
}
7171
}
7272
}

Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/VehicleEnumTest.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ void upgrade() {
9292
void getAsBicycle() {
9393
try (var arena = SwiftArena.ofConfined()) {
9494
Vehicle vehicle = Vehicle.bicycle(arena);
95-
Vehicle.Bicycle bicycle = vehicle.getAsBicycle().orElseThrow();
95+
Vehicle.Case.Bicycle bicycle = vehicle.getAsBicycle().orElseThrow();
9696
assertNotNull(bicycle);
9797
}
9898
}
@@ -101,7 +101,7 @@ void getAsBicycle() {
101101
void getAsCar() {
102102
try (var arena = SwiftArena.ofConfined()) {
103103
Vehicle vehicle = Vehicle.car("BMW", Optional.empty(), arena);
104-
Vehicle.Car car = vehicle.getAsCar().orElseThrow();
104+
Vehicle.Case.Car car = vehicle.getAsCar().orElseThrow();
105105
assertEquals("BMW", car.arg0());
106106

107107
vehicle = Vehicle.car("BMW", Optional.of("Long trailer"), arena);
@@ -114,7 +114,7 @@ void getAsCar() {
114114
void getAsMotorbike() {
115115
try (var arena = SwiftArena.ofConfined()) {
116116
Vehicle vehicle = Vehicle.motorbike("Yamaha", 750, OptionalInt.empty(), arena);
117-
Vehicle.Motorbike motorbike = vehicle.getAsMotorbike().orElseThrow();
117+
Vehicle.Case.Motorbike motorbike = vehicle.getAsMotorbike().orElseThrow();
118118
assertEquals("Yamaha", motorbike.arg0());
119119
assertEquals(750, motorbike.horsePower());
120120
assertEquals(OptionalInt.empty(), motorbike.helmets());
@@ -129,7 +129,7 @@ void getAsMotorbike() {
129129
void getAsTransformer() {
130130
try (var arena = SwiftArena.ofConfined()) {
131131
Vehicle vehicle = Vehicle.transformer(Vehicle.bicycle(arena), Vehicle.car("BMW", Optional.empty(), arena), arena);
132-
Vehicle.Transformer transformer = vehicle.getAsTransformer(arena).orElseThrow();
132+
Vehicle.Case.Transformer transformer = vehicle.getAsTransformer(arena).orElseThrow();
133133
assertTrue(transformer.front().getAsBicycle().isPresent());
134134
assertEquals("BMW", transformer.back().getAsCar().orElseThrow().arg0());
135135
}
@@ -139,7 +139,7 @@ void getAsTransformer() {
139139
void getAsBoat() {
140140
try (var arena = SwiftArena.ofConfined()) {
141141
Vehicle vehicle = Vehicle.boat(OptionalInt.of(10), Optional.of((short) 1), arena);
142-
Vehicle.Boat boat = vehicle.getAsBoat().orElseThrow();
142+
Vehicle.Case.Boat boat = vehicle.getAsBoat().orElseThrow();
143143
assertEquals(OptionalInt.of(10), boat.passengers());
144144
assertEquals(Optional.of((short) 1), boat.length());
145145
}
@@ -149,10 +149,10 @@ void getAsBoat() {
149149
void associatedValuesAreCopied() {
150150
try (var arena = SwiftArena.ofConfined()) {
151151
Vehicle vehicle = Vehicle.car("BMW", Optional.empty(), arena);
152-
Vehicle.Car car = vehicle.getAsCar().orElseThrow();
152+
Vehicle.Case.Car car = vehicle.getAsCar().orElseThrow();
153153
assertEquals("BMW", car.arg0());
154154
vehicle.upgrade();
155-
Vehicle.Motorbike motorbike = vehicle.getAsMotorbike().orElseThrow();
155+
Vehicle.Case.Motorbike motorbike = vehicle.getAsMotorbike().orElseThrow();
156156
assertNotNull(motorbike);
157157
// Motorbike should still remain
158158
assertEquals("BMW", car.arg0());
@@ -174,7 +174,7 @@ void getCase() {
174174
try (var arena = SwiftArena.ofConfined()) {
175175
Vehicle vehicle = Vehicle.bicycle(arena);
176176
Vehicle.Case caseElement = vehicle.getCase(arena);
177-
assertInstanceOf(Vehicle.Bicycle.class, caseElement);
177+
assertInstanceOf(Vehicle.Case.Bicycle.class, caseElement);
178178
}
179179
}
180180

@@ -183,23 +183,23 @@ void switchGetCase() {
183183
try (var arena = SwiftArena.ofConfined()) {
184184
Vehicle vehicle = Vehicle.car("BMW", Optional.empty(), arena);
185185
switch (vehicle.getCase(arena)) {
186-
case Vehicle.Bicycle b:
186+
case Vehicle.Case.Bicycle b:
187187
fail("Was bicycle");
188188
break;
189-
case Vehicle.Car car:
189+
case Vehicle.Case.Car car:
190190
assertEquals("BMW", car.arg0());
191191
break;
192-
case Vehicle.Motorbike motorbike:
192+
case Vehicle.Case.Motorbike motorbike:
193193
fail("Was motorbike");
194194
break;
195-
case Vehicle.Transformer transformer:
195+
case Vehicle.Case.Transformer transformer:
196196
fail("Was transformer");
197197
break;
198-
case Vehicle.Boat b:
198+
case Vehicle.Case.Boat b:
199199
fail("Was boat");
200200
break;
201201
}
202202
}
203203
}
204204

205-
}
205+
}

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,30 @@ extension JNISwift2JavaGenerator {
497497
return
498498
}
499499

500-
printer.print("public sealed interface Case {}")
500+
printer.printBraceBlock("public sealed interface Case") { printer in
501+
for enumCase in decl.cases {
502+
guard let translatedCase = self.translatedEnumCase(for: enumCase) else {
503+
continue
504+
}
505+
506+
let members = translatedCase.translatedValues.map {
507+
$0.parameter.renderParameter()
508+
}
509+
let caseName = enumCase.name.firstCharacterUppercased
510+
511+
// Print record
512+
printer.printBraceBlock("record \(caseName)(\(members.joined(separator: ", "))) implements Case") {
513+
printer in
514+
let nativeParameters = zip(translatedCase.translatedValues, translatedCase.parameterConversions).map {
515+
value,
516+
conversion in
517+
"\(conversion.native.javaType) \(value.parameter.name)"
518+
}
519+
520+
printer.print("record _NativeParameters(\(nativeParameters.joined(separator: ", "))) {}")
521+
}
522+
}
523+
}
501524
printer.println()
502525

503526
let requiresSwiftArena = decl.cases.compactMap {
@@ -539,24 +562,6 @@ extension JNISwift2JavaGenerator {
539562
return
540563
}
541564

542-
let members = translatedCase.translatedValues.map {
543-
$0.parameter.renderParameter()
544-
}
545-
546-
let caseName = enumCase.name.firstCharacterUppercased
547-
548-
// Print record
549-
printer.printBraceBlock("public record \(caseName)(\(members.joined(separator: ", "))) implements Case") {
550-
printer in
551-
let nativeParameters = zip(translatedCase.translatedValues, translatedCase.parameterConversions).map {
552-
value,
553-
conversion in
554-
"\(conversion.native.javaType) \(value.parameter.name)"
555-
}
556-
557-
printer.print("record _NativeParameters(\(nativeParameters.joined(separator: ", "))) {}")
558-
}
559-
560565
self.printJavaBindingWrapperMethod(&printer, translatedCase.getAsCaseFunction, skipMethodBody: false)
561566
printer.println()
562567
}

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ extension JNISwift2JavaGenerator {
129129

130130
let caseName = enumCase.name.firstCharacterUppercased
131131
let enumName = enumCase.enumType.nominalTypeDecl.name
132-
let nativeParametersType = JavaType.class(package: nil, name: "\(caseName)._NativeParameters")
132+
let caseType = JavaType.class(package: nil, name: "Case.\(caseName)")
133+
let nativeParametersType = JavaType.class(package: nil, name: "Case.\(caseName)._NativeParameters")
133134
let getAsCaseName = "getAs\(caseName)"
134135
// If the case has no parameters, we can skip the native call.
135136
let constructRecordConversion = JavaNativeConversionStep.method(
@@ -138,7 +139,7 @@ extension JNISwift2JavaGenerator {
138139
arguments: [
139140
.constructJavaClass(
140141
.commaSeparated(conversions.map(\.translated.conversion)),
141-
.class(package: nil, name: caseName),
142+
caseType,
142143
)
143144
],
144145
)
@@ -179,7 +180,7 @@ extension JNISwift2JavaGenerator {
179180
),
180181
parameters: [],
181182
resultType: TranslatedResult(
182-
javaType: .class(package: nil, name: "Optional", typeParameters: [.class(package: nil, name: caseName)]),
183+
javaType: .optional(caseType),
183184
outParameters: conversions.flatMap(\.translated.outParameters),
184185
conversion: enumCase.parameters.isEmpty
185186
? constructRecordConversion

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ extension JNISwift2JavaGenerator {
409409
}
410410

411411
private func renderEnumCaseCacheInit(_ enumCase: TranslatedEnumCase) -> String {
412-
let nativeParametersClassName = "\(enumCase.enumName)$\(enumCase.name)$_NativeParameters"
412+
let nativeParametersClassName = "\(enumCase.enumName)$Case$\(enumCase.name)$_NativeParameters"
413413
let methodSignature = MethodSignature(
414414
resultType: .void,
415415
parameterTypes: enumCase.parameterConversions.map(\.native.javaType),

Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ extension JavaType {
4545
.class(package: "java.lang", name: "Object")
4646
}
4747

48+
/// The description of the type java.util.Optional.
49+
static func optional(_ T: JavaType) -> JavaType {
50+
.class(package: "java.util", name: "Optional", typeParameters: [T])
51+
}
52+
4853
/// The description of the type java.util.concurrent.CompletableFuture<T>
4954
static func completableFuture(_ T: JavaType) -> JavaType {
5055
.class(package: "java.util.concurrent", name: "CompletableFuture", typeParameters: [T.boxedType])

Sources/SwiftJavaDocumentation/Documentation.docc/SupportedFeatures.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ You can then instantiate a case of `Vehicle` by using one of the static methods:
208208
```java
209209
try (var arena = SwiftArena.ofConfined()) {
210210
Vehicle vehicle = Vehicle.car("BMW", arena);
211-
Optional<Vehicle.Car> car = vehicle.getAsCar();
211+
Optional<Vehicle.Case.Car> car = vehicle.getAsCar();
212212
assertEquals("BMW", car.orElseThrow().arg0());
213213
}
214214
```
@@ -217,10 +217,10 @@ As you can see above, to access the associated values of a case you can call one
217217
```java
218218
try (var arena = SwiftArena.ofConfined()) {
219219
Vehicle vehicle = Vehicle.bycicle("My Brand", arena);
220-
Optional<Vehicle.Car> car = vehicle.getAsCar();
220+
Optional<Vehicle.Case.Car> car = vehicle.getAsCar();
221221
assertFalse(car.isPresent());
222222

223-
Optional<Vehicle.Bicycle> bicycle = vehicle.getAsBicycle();
223+
Optional<Vehicle.Case.Bicycle> bicycle = vehicle.getAsBicycle();
224224
assertEquals("My Brand", bicycle.orElseThrow().maker());
225225
}
226226
```
@@ -246,10 +246,10 @@ If you are running Java 21+ you can use [pattern matching for switch](https://op
246246
```java
247247
Vehicle vehicle = ...;
248248
switch (vehicle.getCase()) {
249-
case Vehicle.Bicycle b:
249+
case Vehicle.Case.Bicycle b:
250250
System.out.println("Bicycle maker: " + b.maker());
251251
break;
252-
case Vehicle.Car c:
252+
case Vehicle.Case.Car c:
253253
System.out.println("Car: " + c.arg0());
254254
break;
255255
}
@@ -258,7 +258,7 @@ or even, destructuring the records in the switch statement's pattern match direc
258258
```java
259259
Vehicle vehicle = ...;
260260
switch (vehicle.getCase()) {
261-
case Vehicle.Car(var name, var unused):
261+
case Vehicle.Case.Car(var name, var unused):
262262
System.out.println("Car: " + name);
263263
break;
264264
default:
@@ -270,21 +270,21 @@ For Java 16+ you can use [pattern matching for instanceof](https://openjdk.org/j
270270
```java
271271
Vehicle vehicle = ...;
272272
Vehicle.Case case = vehicle.getCase();
273-
if (case instanceof Vehicle.Bicycle b) {
273+
if (case instanceof Vehicle.Case.Bicycle b) {
274274
System.out.println("Bicycle maker: " + b.maker());
275-
} else if(case instanceof Vehicle.Car c) {
275+
} else if(case instanceof Vehicle.Case.Car c) {
276276
System.out.println("Car: " + c.arg0());
277277
}
278278
```
279279
For any previous Java versions you can resort to casting the `Case` to the expected type:
280280
```java
281281
Vehicle vehicle = ...;
282282
Vehicle.Case case = vehicle.getCase();
283-
if (case instanceof Vehicle.Bicycle) {
284-
Vehicle.Bicycle b = (Vehicle.Bicycle) case;
283+
if (case instanceof Vehicle.Case.Bicycle) {
284+
Vehicle.Bicycle b = (Vehicle.Case.Bicycle) case;
285285
System.out.println("Bicycle maker: " + b.maker());
286-
} else if(case instanceof Vehicle.Car) {
287-
Vehicle.Car c = (Vehicle.Car) case;
286+
} else if(case instanceof Vehicle.Case.Car) {
287+
Vehicle.Car c = (Vehicle.Case.Car) case;
288288
System.out.println("Car: " + c.arg0());
289289
}
290290
```

0 commit comments

Comments
 (0)