Skip to content

Commit 68b5c1d

Browse files
committed
wip
1 parent 39af7d9 commit 68b5c1d

File tree

8 files changed

+156
-133
lines changed

8 files changed

+156
-133
lines changed

Plugins/JExtractSwiftPlugin/JExtractSwiftPlugin.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
236236
)
237237
]
238238

239+
let singleSwiftFileOutputName = "WrapJavaGenerated.swift"
240+
239241
// In the end we can run wrap-java on the previous inputs
240242
commands += [
241243
.buildCommand(
@@ -247,9 +249,10 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
247249
"--output-directory", outputSwiftDirectory.path(percentEncoded: false),
248250
"--config", swiftJavaConfigURL.path(percentEncoded: false),
249251
"--cp", swiftKitCoreClassPath.path(percentEncoded: false),
252+
"--single-swift-file-output", singleSwiftFileOutputName,
250253
],
251254
inputFiles: [swiftJavaConfigURL, swiftKitCoreClassPath],
252-
outputFiles: [outputSwiftDirectory.appending(path: "JavaStorage.swift")]
255+
outputFiles: [outputSwiftDirectory.appending(path: singleSwiftFileOutputName)]
253256
)
254257
]
255258

Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Storage.swift

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -34,44 +34,3 @@ public func saveWithStorage(_ item: StorageItem, s: any Storage) {
3434
public func loadWithStorage(s: any Storage) -> StorageItem {
3535
return s.load();
3636
}
37-
38-
39-
40-
final class StorageJavaWrapper: Storage {
41-
let javaStorage: JavaStorage
42-
43-
init(javaStorage: JavaStorage) {
44-
self.javaStorage = javaStorage
45-
}
46-
47-
func load() -> StorageItem {
48-
let javaStorageItem = javaStorage.load()!
49-
// Convert JavaStorageItem to (Swift) StorageItem
50-
// First we get the memory address
51-
let memoryAddress = javaStorageItem.as(JavaJNISwiftInstance.self)!.memoryAddress()
52-
let pointer = UnsafeMutablePointer<StorageItem>(bitPattern: Int(memoryAddress))!
53-
return pointer.pointee
54-
}
55-
56-
func save(_ item: StorageItem) {
57-
// convert SwiftPerson to Java Person
58-
// here we can use `wrapMemoryAddressUnsafe`
59-
// and pass in a global arena that we somehow
60-
// access from Swift
61-
let javaStorageItemClass = try! JavaClass<JavaStorageItem>(environment: JavaVirtualMachine.shared().environment())
62-
let pointer = UnsafeMutablePointer<StorageItem>.allocate(capacity: 1)
63-
pointer.initialize(to: item)
64-
let javaStorageItem = javaStorageItemClass.wrapMemoryAddressUnsafe(selfPointer: Int64(Int(bitPattern: pointer)))
65-
javaStorage.save(item: javaStorageItem);
66-
}
67-
68-
func load() -> Int64 {
69-
70-
}
71-
}
72-
73-
@JavaInterface("org.swift.swiftkit.core.JNISwiftInstance")
74-
struct JavaJNISwiftInstance {
75-
@JavaMethod("$memoryAddress")
76-
public func memoryAddress() -> Int64
77-
}

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -962,7 +962,7 @@ extension JNISwift2JavaGenerator {
962962

963963
/// Function signature of the native function that will be implemented by Swift
964964
let nativeFunctionSignature: NativeFunctionSignature
965-
965+
966966
/// Annotations to include on the Java function declaration
967967
var annotations: [JavaAnnotation] {
968968
self.translatedFunctionSignature.annotations

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift

Lines changed: 98 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -125,26 +125,16 @@ extension JNISwift2JavaGenerator {
125125

126126
/// Prints the extension needed to make allow upcalls from Swift to Java for protocols
127127
private func printSwiftInterfaceWrapper(_ printer: inout CodePrinter, _ type: ImportedNominalType) throws {
128-
let safeProtocolName = type.qualifiedName.replacingOccurrences(of: ".", with: "_")
129-
let wrapperName = "SwiftJava\(safeProtocolName)Wrapper"
130-
131-
try printer.printBraceBlock("final class \(wrapperName): \(type.qualifiedName)") { printer in
132-
let javaInterfaceVariableName = "javaInterface"
133-
let swiftJavaInterfaceName = "Java\(safeProtocolName)"
134-
135-
printer.print(
136-
"""
137-
let \(javaInterfaceVariableName): \(swiftJavaInterfaceName)
138-
139-
init(javaInterface: \(swiftJavaInterfaceName)) {
140-
self.\(javaInterfaceVariableName) = javaInterface
141-
}
142-
"""
143-
)
144-
printer.println()
128+
let wrapperName = type.javaInterfaceSwiftProtocolWrapperName
129+
let javaInterfaceVariableName = "_\(type.javaInterfaceName.firstCharacterLowercased)Interface"
145130

131+
printer.printBraceBlock("protocol \(wrapperName)") { printer in
132+
printer.print("var \(javaInterfaceVariableName): \(type.javaInterfaceName) { get }")
133+
}
134+
printer.println()
135+
printer.printBraceBlock("extension \(wrapperName): \(type.qualifiedName)") { printer in
146136
for method in type.methods {
147-
try printer.printBraceBlock(method.swiftDecl.signatureString) { printer in
137+
printer.printBraceBlock(method.swiftDecl.signatureString) { printer in
148138
let methodName = method.name
149139

150140
let parameters = method.functionSignature.parameters.map { parameter in
@@ -164,13 +154,16 @@ extension JNISwift2JavaGenerator {
164154
"""
165155
)
166156

167-
return "\(parameterName)Class.wrapMemoryAddressUnsafe(selfPointer: Int64(Int(bitPattern: pointer)))"
157+
return "\(parameterName)Class.wrapMemoryAddressUnsafe(Int64(Int(bitPattern: pointer)))"
168158
}
169159

170160
let javaUpcall = "\(javaInterfaceVariableName).\(methodName)(\(parameters.joined(separator: ", ")))"
171161

162+
let resultType = method.functionSignature.result.type
172163
if !method.functionSignature.result.type.isVoid {
173-
guard let importedNominalType = self.asImportedNominalTypeDecl(type.swiftType) else {
164+
guard let importedNominalType = self.asImportedNominalTypeDecl(resultType),
165+
importedNominalType.swiftNominal.knownTypeKind == nil
166+
else {
174167
printer.print("return \(javaUpcall)")
175168
return
176169
}
@@ -180,7 +173,9 @@ extension JNISwift2JavaGenerator {
180173
let resultName = "_upcallResult"
181174
printer.print(
182175
"""
183-
let \(resultName) = \(javaUpcall)
176+
guard let \(resultName) = \(javaUpcall) else {
177+
fatalError("Upcall to \(methodName) unexpectedly returned nil")
178+
}
184179
let memoryAddress$ = \(resultName).as(JavaJNISwiftInstance.self)!.memoryAddress()
185180
let pointer = UnsafeMutablePointer<StorageItem>(bitPattern: Int(memoryAddress$))!
186181
return pointer.pointee
@@ -190,38 +185,6 @@ extension JNISwift2JavaGenerator {
190185
printer.print(javaUpcall)
191186
}
192187
}
193-
//
194-
// try printer.printBraceBlock(method.swiftDecl.signatureString) { printer in
195-
// printer.print(
196-
// """
197-
// let environment = try! JavaVirtualMachine.shared().environment()
198-
// let methodID$: jmethodID!
199-
// """
200-
// )
201-
//
202-
// // Passing down Swift parameters to Java basically means
203-
// // that we are returning these values to Java,
204-
// // we therefore take all the Swift parameters and translate them
205-
// // as if they were results.
206-
// let upcallValues = try method.functionSignature.parameters.map { parameter in
207-
// let result = try self.nativeTranslator.translate(
208-
// swiftResult: SwiftResult(
209-
// convention: .direct,
210-
// type: parameter.type
211-
// )
212-
// )
213-
// return result.conversion.render(&printer, parameter.parameterName!)
214-
// }
215-
//
216-
// let javaResultType = translatedDecl.nativeFunctionSignature.result.javaType
217-
// // TODO: Convert arguments to jvalue
218-
// printer.print(
219-
// """
220-
// let javaResult$ = environment.interface.\(javaResultType.jniCallMethodAName)(environment, self.objectHolder.object, methodID$, [\(upcallValues.joined(separator: ", "))])
221-
// """
222-
// )
223-
// }
224-
225188
printer.println()
226189
}
227190
}
@@ -297,19 +260,19 @@ extension JNISwift2JavaGenerator {
297260

298261
private func printJavaMacroBindings(_ printer: inout CodePrinter, _ type: ImportedNominalType) {
299262
// TODO: Nested subclasses here is wrong.
300-
let javaTypeName = type.swiftNominal.qualifiedName
301-
302-
printer.print(
303-
"""
304-
@JavaClass("\(javaPackage).\(javaTypeName)")
305-
open class \(type.generatedJavaClassMacroName): JavaObject {}
306-
307-
extension JavaClass<\(type.generatedJavaClassMacroName)> {
308-
@JavaStaticMethod
309-
public func wrapMemoryAddressUnsafe(selfPointer: Int64) -> \(type.generatedJavaClassMacroName)!
310-
}
311-
"""
312-
)
263+
// let javaTypeName = type.swiftNominal.qualifiedName
264+
//
265+
// printer.print(
266+
// """
267+
// @JavaClass("\(javaPackage).\(javaTypeName)")
268+
// open class \(type.generatedJavaClassMacroName): JavaObject {}
269+
//
270+
// extension JavaClass<\(type.generatedJavaClassMacroName)> {
271+
// @JavaStaticMethod
272+
// public func wrapMemoryAddressUnsafe(selfPointer: Int64) -> \(type.generatedJavaClassMacroName)!
273+
// }
274+
// """
275+
// )
313276
}
314277

315278
private func printProtocolThunks(_ printer: inout CodePrinter, _ type: ImportedNominalType) throws {
@@ -418,6 +381,8 @@ extension JNISwift2JavaGenerator {
418381
return
419382
}
420383

384+
printSwiftFunctionHelperClasses(&printer, decl)
385+
421386
printCDecl(
422387
&printer,
423388
translatedDecl
@@ -426,6 +391,61 @@ extension JNISwift2JavaGenerator {
426391
}
427392
}
428393

394+
395+
private func printSwiftFunctionHelperClasses(
396+
_ printer: inout CodePrinter,
397+
_ decl: ImportedFunc
398+
) {
399+
let protocolParameters = decl.functionSignature.parameters.compactMap { parameter in
400+
if let concreteType = parameter.type.typeIn(
401+
genericParameters: decl.functionSignature.genericParameters,
402+
genericRequirements: decl.functionSignature.genericRequirements
403+
) {
404+
return (parameter, concreteType)
405+
}
406+
407+
switch parameter.type {
408+
case .opaque(let protocolType),
409+
.existential(let protocolType):
410+
return (parameter, protocolType)
411+
412+
default:
413+
return nil
414+
}
415+
}.map { parameter, protocolType in
416+
// We flatten any composite types
417+
switch protocolType {
418+
case .composite(let protocols):
419+
return (parameter, protocols)
420+
421+
default:
422+
return (parameter, [protocolType])
423+
}
424+
}
425+
426+
// For each parameter that is a generic or a protocol,
427+
// we generate a Swift class that conforms to all of those.
428+
for (parameter, protocolTypes) in protocolParameters {
429+
guard let parameterName = parameter.parameterName else {
430+
// TODO: Throw
431+
fatalError()
432+
}
433+
let parent = if let parent = decl.parentType {
434+
"\(parent)_"
435+
} else {
436+
""
437+
}
438+
let swiftClassName = "_\(parent)\(decl.name)_\(parameterName)_Wrapper"
439+
let implementingProtocols = protocolTypes.compactMap {
440+
$0.asNominalType?.javaInterfaceSwiftProtocolWrapperName
441+
}.joined(separator: ", ")
442+
443+
printer.printBraceBlock("final class \(swiftClassName): \(implementingProtocols)") { printer in
444+
445+
}
446+
}
447+
}
448+
429449
private func printFunctionDowncall(
430450
_ printer: inout CodePrinter,
431451
_ decl: ImportedFunc
@@ -682,8 +702,17 @@ extension JNISwift2JavaGenerator {
682702
}
683703
}
684704

685-
extension ImportedNominalType {
686-
var generatedJavaClassMacroName: String {
687-
"Java\(self.swiftNominal.qualifiedName.replacingOccurrences(of: ".", with: "_"))"
705+
extension SwiftNominalType {
706+
private var safeProtocolName: String {
707+
self.nominalTypeDecl.qualifiedName.replacingOccurrences(of: ".", with: "_")
708+
}
709+
710+
/// The name of the corresponding `@JavaInterface` of this type.
711+
var javaInterfaceName: String {
712+
"Java\(safeProtocolName)"
713+
}
714+
715+
var javaInterfaceSwiftProtocolWrapperName: String {
716+
"SwiftJava\(safeProtocolName)Wrapper"
688717
}
689718
}

Sources/SwiftJavaConfigurationShared/Configuration.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ public struct Configuration: Codable {
9191
/// Exclude input Java types by their package prefix or exact match.
9292
public var filterExclude: [String]?
9393

94+
public var singleSwiftFileOutput: String?
95+
9496
// ==== dependencies ---------------------------------------------------------
9597

9698
// Java dependencies we need to fetch for this target.

Sources/SwiftJavaMacros/JavaMethodMacro.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,9 @@ extension JavaMethodMacro: BodyMacro {
5252

5353
let funcName =
5454
if case .argumentList(let arguments) = node.arguments,
55-
let wrapperTypeNameExpr = arguments.first?.expression,
56-
let stringLiteral = wrapperTypeNameExpr.as(StringLiteralExprSyntax.self),
55+
let argument = arguments.first,
56+
argument.label?.text != "typeErasedResult",
57+
let stringLiteral = argument.expression.as(StringLiteralExprSyntax.self),
5758
stringLiteral.segments.count == 1,
5859
case let .stringSegment(funcNameSegment)? = stringLiteral.segments.first
5960
{
@@ -68,8 +69,8 @@ extension JavaMethodMacro: BodyMacro {
6869

6970
let genericResultType: String? =
7071
if case let .argumentList(arguments) = node.arguments,
71-
let firstElement = arguments.first,
72-
let stringLiteral = firstElement.expression
72+
let element = arguments.first(where: { $0.label?.text == "typeErasedResult" }),
73+
let stringLiteral = element.expression
7374
.as(StringLiteralExprSyntax.self),
7475
stringLiteral.segments.count == 1,
7576
case let .stringSegment(wrapperName)? = stringLiteral.segments.first {

Sources/SwiftJavaTool/Commands/ConfigureCommand.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ extension SwiftJava.ConfigureCommand {
147147
} else if FileManager.default.fileExists(atPath: entry), let entryURL = URL(string: entry) {
148148
print("[debug][swift-java] Importing classpath as directory: \(entryURL)")
149149
try addJavaToSwiftMappings(
150-
to: &configuration,
150+
to: &config,
151151
forDirectory: entryURL
152152
)
153153
} else {

0 commit comments

Comments
 (0)