Skip to content

Commit 8d6365c

Browse files
authored
jextract (ffm, jni): Subscripts support (#459)
Co-authored-by: pelekon <[email protected]>
1 parent 6eb4705 commit 8d6365c

File tree

15 files changed

+717
-88
lines changed

15 files changed

+717
-88
lines changed

Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftStruct.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,14 @@ public struct MySwiftStruct {
1616

1717
private var cap: Int
1818
private var len: Int
19+
private var subscriptValue: Int
20+
private var subscriptArray: [Int]
1921

2022
public init(cap: Int, len: Int) {
2123
self.cap = cap
2224
self.len = len
25+
self.subscriptValue = 0
26+
self.subscriptArray = [10, 20, 15, 75]
2327
}
2428

2529
public func voidMethod() {
@@ -61,4 +65,22 @@ public struct MySwiftStruct {
6165
public func makeRandomIntMethod() -> Int {
6266
return Int.random(in: 1..<256)
6367
}
68+
69+
public func getSubscriptValue() -> Int {
70+
return self.subscriptValue
71+
}
72+
73+
public func getSubscriptArrayValue(index: Int) -> Int {
74+
return self.subscriptArray[index]
75+
}
76+
77+
public subscript() -> Int {
78+
get { return subscriptValue }
79+
set { subscriptValue = newValue }
80+
}
81+
82+
public subscript(index: Int) -> Int {
83+
get { return subscriptArray[index] }
84+
set { subscriptArray[index] = newValue }
85+
}
6486
}

Samples/SwiftJavaExtractFFMSampleApp/src/test/java/org/swift/swiftkitffm/MySwiftStructTest.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,26 @@ void create_struct() {
3333
assertEquals(len, struct.getLength());
3434
}
3535
}
36+
37+
@Test
38+
void testSubscript() {
39+
try (var arena = AllocatingSwiftArena.ofConfined()) {
40+
MySwiftStruct s = MySwiftStruct.init(1337, 42, arena);
41+
long currentValue = s.getSubscript();
42+
s.setSubscript(66);
43+
assertEquals(0, currentValue);
44+
assertEquals(66, s.getSubscriptValue());
45+
}
46+
}
47+
48+
@Test
49+
void testSubscriptWithParams() {
50+
try (var arena = AllocatingSwiftArena.ofConfined()) {
51+
MySwiftStruct s = MySwiftStruct.init(1337, 42, arena);
52+
long currentValue = s.getSubscript(1);
53+
s.setSubscript(1, 66);
54+
assertEquals(20, currentValue);
55+
assertEquals(66, s.getSubscriptArrayValue(1));
56+
}
57+
}
3658
}

Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/MySwiftStruct.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,14 @@
1515
public struct MySwiftStruct {
1616
private var cap: Int64
1717
public var len: Int64
18+
private var subscriptValue: Int64
19+
private var subscriptArray: [Int64]
1820

1921
public init(cap: Int64, len: Int64) {
2022
self.cap = cap
2123
self.len = len
24+
self.subscriptValue = 0
25+
self.subscriptArray = [10, 20, 15, 75]
2226
}
2327

2428
public init?(doInit: Bool) {
@@ -38,4 +42,22 @@ public struct MySwiftStruct {
3842
self.cap += value
3943
return self.cap
4044
}
45+
46+
public func getSubscriptValue() -> Int64 {
47+
return self.subscriptValue
48+
}
49+
50+
public func getSubscriptArrayValue(index: Int64) -> Int64 {
51+
return self.subscriptArray[Int(index)]
52+
}
53+
54+
public subscript() -> Int64 {
55+
get { return subscriptValue }
56+
set { subscriptValue = newValue }
57+
}
58+
59+
public subscript(index: Int64) -> Int64 {
60+
get { return subscriptArray[Int(index)] }
61+
set { subscriptArray[Int(index)] = newValue }
62+
}
4163
}

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,26 @@ void increaseCap() {
6161
assertEquals(1347, s.getCapacity());
6262
}
6363
}
64+
65+
@Test
66+
void testSubscript() {
67+
try (var arena = SwiftArena.ofConfined()) {
68+
MySwiftStruct s = MySwiftStruct.init(1337, 42, arena);
69+
long currentValue = s.getSubscript();
70+
s.setSubscript(66);
71+
assertEquals(0, currentValue);
72+
assertEquals(66, s.getSubscriptValue());
73+
}
74+
}
75+
76+
@Test
77+
void testSubscriptWithParams() {
78+
try (var arena = SwiftArena.ofConfined()) {
79+
MySwiftStruct s = MySwiftStruct.init(1337, 42, arena);
80+
long currentValue = s.getSubscript(1);
81+
s.setSubscript(1, 66);
82+
assertEquals(20, currentValue);
83+
assertEquals(66, s.getSubscriptArrayValue(1));
84+
}
85+
}
6486
}

Sources/JExtractSwiftLib/FFM/CDeclLowering/FFMSwift2JavaGenerator+FunctionLowering.swift

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -812,11 +812,10 @@ extension LoweredFunctionSignature {
812812

813813
// Build callee expression.
814814
let callee: ExprSyntax = if let selfExpr {
815-
if case .initializer = apiKind {
815+
switch apiKind {
816816
// Don't bother to create explicit ${Self}.init expression.
817-
selfExpr
818-
} else {
819-
ExprSyntax(MemberAccessExprSyntax(base: selfExpr, name: .identifier(swiftAPIName)))
817+
case .initializer, .subscriptGetter, .subscriptSetter: selfExpr
818+
default: ExprSyntax(MemberAccessExprSyntax(base: selfExpr, name: .identifier(swiftAPIName)))
820819
}
821820
} else {
822821
ExprSyntax(DeclReferenceExprSyntax(baseName: .identifier(swiftAPIName)))
@@ -845,6 +844,18 @@ extension LoweredFunctionSignature {
845844
case .enumCase:
846845
// This should not be called, but let's fatalError.
847846
fatalError("Enum cases are not supported with FFM.")
847+
848+
case .subscriptGetter:
849+
let parameters = paramExprs.map { $0.description }.joined(separator: ", ")
850+
resultExpr = "\(callee)[\(raw: parameters)]"
851+
case .subscriptSetter:
852+
assert(paramExprs.count >= 1)
853+
854+
var argumentsWithoutNewValue = paramExprs
855+
let newValueArgument = argumentsWithoutNewValue.removeLast()
856+
857+
let parameters = argumentsWithoutNewValue.map { $0.description }.joined(separator: ", ")
858+
resultExpr = "\(callee)[\(raw: parameters)] = \(newValueArgument)"
848859
}
849860

850861
// Lower the result.

Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,8 @@ extension FFMSwift2JavaGenerator {
144144

145145
// Name.
146146
let javaName = switch decl.apiKind {
147-
case .getter: decl.javaGetterName
148-
case .setter: decl.javaSetterName
147+
case .getter, .subscriptGetter: decl.javaGetterName
148+
case .setter, .subscriptSetter: decl.javaSetterName
149149
case .function, .initializer, .enumCase: decl.name
150150
}
151151

Sources/JExtractSwiftLib/ImportedDecls.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ package enum SwiftAPIKind {
2323
case getter
2424
case setter
2525
case enumCase
26+
case subscriptGetter
27+
case subscriptSetter
2628
}
2729

2830
/// Describes a Swift nominal type (e.g., a class, struct, enum) that has been
@@ -179,6 +181,8 @@ public final class ImportedFunc: ImportedDecl, CustomStringConvertible {
179181
case .setter: "setter:"
180182
case .enumCase: "case:"
181183
case .function, .initializer: ""
184+
case .subscriptGetter: "subscriptGetter:"
185+
case .subscriptSetter: "subscriptSetter:"
182186
}
183187

184188
let context = if let parentType {

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,8 @@ extension JNISwift2JavaGenerator {
176176

177177
// Name.
178178
let javaName = switch decl.apiKind {
179-
case .getter: decl.javaGetterName
180-
case .setter: decl.javaSetterName
179+
case .getter, .subscriptGetter: decl.javaGetterName
180+
case .setter, .subscriptSetter: decl.javaSetterName
181181
case .function, .initializer, .enumCase: decl.name
182182
}
183183

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,19 @@ extension JNISwift2JavaGenerator {
348348
}
349349

350350
result = "\(callee).\(decl.name) = \(newValueArgument)"
351+
case .subscriptGetter:
352+
let parameters = arguments.joined(separator: ", ")
353+
result = "\(callee)[\(parameters)]"
354+
case .subscriptSetter:
355+
guard let newValueArgument = arguments.last else {
356+
fatalError("Setter did not contain newValue parameter: \(decl)")
357+
}
358+
359+
var argumentsWithoutNewValue = arguments
360+
argumentsWithoutNewValue.removeLast()
361+
362+
let parameters = argumentsWithoutNewValue.joined(separator: ", ")
363+
result = "\(callee)[\(parameters)] = \(newValueArgument)"
351364
}
352365

353366
// Lower the result.

0 commit comments

Comments
 (0)