Skip to content

Commit 56a9096

Browse files
committed
add support for jextract classes
1 parent cea8b92 commit 56a9096

File tree

3 files changed

+90
-36
lines changed

3 files changed

+90
-36
lines changed

Samples/JExtractJNISampleApp/src/test/java/com/example/swift/OptionalsTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,10 @@ void optionalString() {
8484
void optionalClass() {
8585
try (var arena = new ConfinedSwiftMemorySession()) {
8686
MySwiftClass c = MySwiftClass.init(arena);
87-
assertEquals(Optional.empty(), MySwiftLibrary.optionalClass(Optional.empty()));
88-
assertEquals(Optional.of(c), MySwiftLibrary.optionalClass(Optional.of(c)));
87+
assertEquals(Optional.empty(), MySwiftLibrary.optionalClass(Optional.empty(), arena));
88+
Optional<MySwiftClass> optionalClass = MySwiftLibrary.optionalClass(Optional.of(c), arena);
89+
assertTrue(optionalClass.isPresent());
90+
assertEquals(c.getX(), optionalClass.get().getX());
8991
}
9092
}
9193
}

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ extension JNISwift2JavaGenerator {
362362
throw JavaTranslationError.unsupportedSwiftType(swiftType)
363363
}
364364

365-
let (returnType, staticCallee) = switch javaType {
365+
let (returnType, optionalClass) = switch javaType {
366366
case .boolean: ("Optional<Boolean>", "Optional")
367367
case .byte: ("Optional<Byte>", "Optional")
368368
case .char: ("Optional<Character>", "Optional")
@@ -387,7 +387,7 @@ extension JNISwift2JavaGenerator {
387387
nextIntergralTypeWithSpaceForByte.java,
388388
valueType: javaType,
389389
valueSizeInBytes: nextIntergralTypeWithSpaceForByte.valueBytes,
390-
optionalType: staticCallee
390+
optionalType: optionalClass
391391
)
392392
)
393393
} else {
@@ -398,19 +398,11 @@ extension JNISwift2JavaGenerator {
398398
outParameters: [
399399
OutParameter(name: "result_discriminator$", type: .array(.byte), allocation: .newArray(.byte, size: 1))
400400
],
401-
conversion: .aggregate(
402-
name: "result$",
403-
type: javaType,
404-
[
405-
.ternary(
406-
.equals(
407-
.subscriptOf(.constant("result_discriminator$"), arguments: [.constant("0")]),
408-
.constant("1")
409-
),
410-
thenExp: .method(.constant(staticCallee), function: "of", arguments: [.constant("result$")]),
411-
elseExp: .method(.constant(staticCallee), function: "empty")
412-
)
413-
]
401+
conversion: .toOptionalFromIndirectReturn(
402+
discriminatorName: "result_discriminator$",
403+
optionalClass: optionalClass,
404+
javaType: javaType,
405+
toValue: .placeholder
414406
)
415407
)
416408
}
@@ -420,8 +412,20 @@ extension JNISwift2JavaGenerator {
420412
throw JavaTranslationError.unsupportedSwiftType(swiftType)
421413
}
422414

423-
// Assume JExtract imported class
424-
throw JavaTranslationError.unsupportedSwiftType(swiftType)
415+
// We assume this is a JExtract class.
416+
let returnType = JavaType.class(package: nil, name: "Optional<\(nominalTypeName)>")
417+
return TranslatedResult(
418+
javaType: returnType,
419+
outParameters: [
420+
OutParameter(name: "result_discriminator$", type: .array(.byte), allocation: .newArray(.byte, size: 1))
421+
],
422+
conversion: .toOptionalFromIndirectReturn(
423+
discriminatorName: "result_discriminator$",
424+
optionalClass: "Optional",
425+
javaType: .long,
426+
toValue: .constructSwiftValue(.placeholder, .class(package: nil, name: nominalTypeName))
427+
)
428+
)
425429

426430
default:
427431
throw JavaTranslationError.unsupportedSwiftType(swiftType)
@@ -558,6 +562,28 @@ extension JNISwift2JavaGenerator {
558562

559563
indirect case subscriptOf(JavaNativeConversionStep, arguments: [JavaNativeConversionStep])
560564

565+
static func toOptionalFromIndirectReturn(
566+
discriminatorName: String,
567+
optionalClass: String,
568+
javaType: JavaType,
569+
toValue valueConversion: JavaNativeConversionStep
570+
) -> JavaNativeConversionStep {
571+
.aggregate(
572+
name: "result$",
573+
type: javaType,
574+
[
575+
.ternary(
576+
.equals(
577+
.subscriptOf(.constant(discriminatorName), arguments: [.constant("0")]),
578+
.constant("1")
579+
),
580+
thenExp: .method(.constant(optionalClass), function: "of", arguments: [valueConversion]),
581+
elseExp: .method(.constant(optionalClass), function: "empty")
582+
)
583+
]
584+
)
585+
}
586+
561587
/// Perform multiple conversions using the same input.
562588
case aggregate(name: String, type: JavaType, [JavaNativeConversionStep])
563589

@@ -652,8 +678,8 @@ extension JNISwift2JavaGenerator {
652678
case .commaSeparated(let list):
653679
return list.contains(where: { $0.requiresSwiftArena })
654680

655-
case .method(let inner, _, _):
656-
return inner.requiresSwiftArena
681+
case .method(let inner, _, let args):
682+
return inner.requiresSwiftArena || args.contains(where: \.requiresSwiftArena)
657683

658684
case .combinedValueToOptional(let inner, _, _, _, _):
659685
return inner.requiresSwiftArena

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,8 @@ extension JNISwift2JavaGenerator {
237237
return NativeResult(
238238
javaType: javaType,
239239
conversion: .optionalRaisingIndirectReturn(
240-
.getJNIValue(.optionalChain(.placeholder)),
240+
.getJNIValue(.placeholder),
241+
returnType: javaType,
241242
discriminatorParameterName: discriminatorName,
242243
placeholderValue: .member(
243244
.constant("\(swiftType)"),
@@ -257,8 +258,20 @@ extension JNISwift2JavaGenerator {
257258
}
258259

259260
// Assume JExtract imported class
260-
// TODO: Should be the same as above, just with a long and different conversion?
261-
throw JavaTranslationError.unsupportedSwiftType(swiftType)
261+
let discriminatorName = "result_discriminator$"
262+
263+
return NativeResult(
264+
javaType: .long,
265+
conversion: .optionalRaisingIndirectReturn(
266+
.getJNIValue(.allocateSwiftValue(name: "_result", swiftType: swiftType)),
267+
returnType: .long,
268+
discriminatorParameterName: discriminatorName,
269+
placeholderValue: .constant("0")
270+
),
271+
outParameters: [
272+
JavaParameter(name: discriminatorName, type: .array(.byte))
273+
]
274+
)
262275

263276
default:
264277
throw JavaTranslationError.unsupportedSwiftType(swiftType)
@@ -443,7 +456,7 @@ extension JNISwift2JavaGenerator {
443456

444457
indirect case optionalRaisingWidenIntegerType(NativeSwiftConversionStep, valueType: JavaType, combinedSwiftType: String, valueSizeInBytes: Int)
445458

446-
indirect case optionalRaisingIndirectReturn(NativeSwiftConversionStep, discriminatorParameterName: String, placeholderValue: NativeSwiftConversionStep)
459+
indirect case optionalRaisingIndirectReturn(NativeSwiftConversionStep, returnType: JavaType, discriminatorParameterName: String, placeholderValue: NativeSwiftConversionStep)
447460

448461
indirect case method(NativeSwiftConversionStep, function: String, arguments: [(String?, NativeSwiftConversionStep)] = [])
449462

@@ -574,17 +587,30 @@ extension JNISwift2JavaGenerator {
574587
)
575588
return "value$"
576589

577-
case .optionalRaisingIndirectReturn(let inner, let discriminatorParameterName, let placeholderValue):
578-
let inner = inner.render(&printer, placeholder)
579-
let placeholderValue = placeholderValue.render(&printer, placeholder)
580-
printer.print(
581-
"""
582-
let result$ = \(inner)
583-
var flag$ = result$ != nil ? jbyte(1) : jbyte(2)
584-
environment.interface.SetByteArrayRegion(environment, \(discriminatorParameterName), 0, 1, &flag$)
585-
"""
586-
)
587-
return "result$ ?? \(placeholderValue)"
590+
case .optionalRaisingIndirectReturn(let inner, let returnType, let discriminatorParameterName, let placeholderValue):
591+
printer.print("let result$: \(returnType.jniTypeName)")
592+
printer.printBraceBlock("if let innerResult$ = \(placeholder)") { printer in
593+
let inner = inner.render(&printer, "innerResult$")
594+
printer.print(
595+
"""
596+
result$ = \(inner)
597+
var flag$ = Int8(1)
598+
environment.interface.SetByteArrayRegion(environment, \(discriminatorParameterName), 0, 1, &flag$)
599+
"""
600+
)
601+
}
602+
printer.printBraceBlock("else") { printer in
603+
let placeholderValue = placeholderValue.render(&printer, placeholder)
604+
printer.print(
605+
"""
606+
result$ = \(placeholderValue)
607+
var flag$ = Int8(0)
608+
environment.interface.SetByteArrayRegion(environment, \(discriminatorParameterName), 0, 1, &flag$)
609+
"""
610+
)
611+
}
612+
613+
return "result$"
588614

589615
case .method(let inner, let methodName, let arguments):
590616
let inner = inner.render(&printer, placeholder)

0 commit comments

Comments
 (0)