diff --git a/.licenseignore b/.licenseignore index a49ab625d..b8009e6df 100644 --- a/.licenseignore +++ b/.licenseignore @@ -52,3 +52,7 @@ Samples/JavaDependencySampleApp/gradle Sources/_Subprocess/** Sources/_SubprocessCShims/** Samples/gradle +Sources/SwiftJavaRuntimeSupport/Foundation/* +Sources/SwiftRuntimeFunctions/Foundation/* +SwiftKitCore/src/main/java/org/swift/swiftkit/core/foundation/* +SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/foundation/* diff --git a/Samples/SwiftJavaExtractFFMSampleApp/src/jmh/java/org/swift/swiftkit/ffm/FFMDataBenchmark.java b/Samples/SwiftJavaExtractFFMSampleApp/src/jmh/java/org/swift/swiftkit/ffm/FFMDataBenchmark.java index 39a64c7a9..6cac287ff 100644 --- a/Samples/SwiftJavaExtractFFMSampleApp/src/jmh/java/org/swift/swiftkit/ffm/FFMDataBenchmark.java +++ b/Samples/SwiftJavaExtractFFMSampleApp/src/jmh/java/org/swift/swiftkit/ffm/FFMDataBenchmark.java @@ -14,10 +14,10 @@ package org.swift.swiftkit.ffm; -import com.example.swift.Data; import com.example.swift.MySwiftLibrary; import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.infra.Blackhole; +import org.swift.swiftkit.ffm.foundation.Data; import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; @@ -79,7 +79,7 @@ public ByteBuffer ffm_data_withUnsafeBytes_asByteBuffer() { }); return buf.value; } - + @Benchmark public byte[] ffm_data_withUnsafeBytes_toArray() { Holder buf = new Holder<>(); diff --git a/Samples/SwiftJavaExtractFFMSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java b/Samples/SwiftJavaExtractFFMSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java index 62c29482a..53fca07b6 100644 --- a/Samples/SwiftJavaExtractFFMSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java +++ b/Samples/SwiftJavaExtractFFMSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java @@ -22,6 +22,7 @@ import org.swift.swiftkit.core.SwiftLibraries; import org.swift.swiftkit.ffm.AllocatingSwiftArena; import org.swift.swiftkit.ffm.SwiftRuntime; +import org.swift.swiftkit.ffm.foundation.Data; import java.util.Optional; import java.util.OptionalLong; @@ -85,7 +86,7 @@ static void examples() { var origBytes = arena.allocateFrom("foobar"); var origDat = Data.init(origBytes, origBytes.byteSize(), arena); CallTraces.trace("origDat.count = " + origDat.getCount()); - + var retDat = MySwiftLibrary.globalReceiveReturnData(origDat, arena); retDat.withUnsafeBytes((retBytes) -> { var str = retBytes.getString(0); diff --git a/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/DataImportTest.java b/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/DataImportTest.java index 82fb09464..69ed9db31 100644 --- a/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/DataImportTest.java +++ b/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/DataImportTest.java @@ -16,6 +16,7 @@ import org.junit.jupiter.api.Test; import org.swift.swiftkit.ffm.AllocatingSwiftArena; +import org.swift.swiftkit.ffm.foundation.Data; import java.lang.foreign.ValueLayout; @@ -134,7 +135,7 @@ void test_Data_toByteBuffer_emptyData() { byte[] original = new byte[0]; var data = Data.fromByteArray(original, arena); var buffer = data.toByteBuffer(arena); - + assertEquals(0, buffer.capacity()); } } diff --git a/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/OptionalImportTest.java b/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/OptionalImportTest.java index 57e8dba61..306ce688c 100644 --- a/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/OptionalImportTest.java +++ b/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/OptionalImportTest.java @@ -16,6 +16,7 @@ import org.junit.jupiter.api.Test; import org.swift.swiftkit.ffm.AllocatingSwiftArena; +import org.swift.swiftkit.ffm.foundation.Data; import java.util.Optional; import java.util.OptionalLong; diff --git a/Samples/SwiftJavaExtractJNISampleApp/src/jmh/java/com/example/swift/JNIDataBenchmark.java b/Samples/SwiftJavaExtractJNISampleApp/src/jmh/java/com/example/swift/JNIDataBenchmark.java index 283f1f7c0..52b1d16b8 100644 --- a/Samples/SwiftJavaExtractJNISampleApp/src/jmh/java/com/example/swift/JNIDataBenchmark.java +++ b/Samples/SwiftJavaExtractJNISampleApp/src/jmh/java/com/example/swift/JNIDataBenchmark.java @@ -18,6 +18,7 @@ import org.openjdk.jmh.infra.Blackhole; import org.swift.swiftkit.core.ClosableSwiftArena; import org.swift.swiftkit.core.SwiftArena; +import org.swift.swiftkit.core.foundation.Data; import java.util.concurrent.TimeUnit; diff --git a/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/DataTest.java b/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/DataTest.java index a6024ca12..32bd4a98b 100644 --- a/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/DataTest.java +++ b/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/DataTest.java @@ -16,6 +16,7 @@ import org.junit.jupiter.api.Test; import org.swift.swiftkit.core.SwiftArena; +import org.swift.swiftkit.core.foundation.Data; import static org.junit.jupiter.api.Assertions.*; diff --git a/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/DateTest.java b/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/DateTest.java index 9b13f37ec..36da11d9d 100644 --- a/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/DateTest.java +++ b/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/DateTest.java @@ -16,6 +16,7 @@ import org.junit.jupiter.api.Test; import org.swift.swiftkit.core.SwiftArena; +import org.swift.swiftkit.core.foundation.Date; import java.time.Instant; import java.time.temporal.ChronoUnit; @@ -59,4 +60,4 @@ void date_timeIntervalSince1970() { assertEquals(1000, date.getTimeIntervalSince1970()); } } -} \ No newline at end of file +} diff --git a/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/OptionalsTest.java b/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/OptionalsTest.java index 771cffc33..941d2a545 100644 --- a/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/OptionalsTest.java +++ b/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/OptionalsTest.java @@ -14,9 +14,10 @@ package com.example.swift; -import com.example.swift.MySwiftLibrary; import org.junit.jupiter.api.Test; import org.swift.swiftkit.core.SwiftArena; +import org.swift.swiftkit.core.foundation.Data; +import org.swift.swiftkit.core.foundation.Date; import java.time.Instant; import java.util.Optional; @@ -143,4 +144,4 @@ void optionalThrows() { assertEquals("swiftError", exception.getMessage()); } } -} \ No newline at end of file +} diff --git a/Sources/FakeFoundation/Data.swift b/Sources/FakeFoundation/Data.swift new file mode 100644 index 000000000..5fd160dd0 --- /dev/null +++ b/Sources/FakeFoundation/Data.swift @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2026 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +#if canImport(FoundationEssentials) +import FoundationEssentials +#else +import Foundation +#endif + +public struct Data: DataProtocol { + public init(bytes: UnsafeRawPointer, count: Int) + public init(_ bytes: [UInt8]) + public var count: Int { get } + public func withUnsafeBytes(_ body: (UnsafeRawBufferPointer) -> Void) +} diff --git a/Sources/FakeFoundation/DataProtocol.swift b/Sources/FakeFoundation/DataProtocol.swift new file mode 100644 index 000000000..d5a02d423 --- /dev/null +++ b/Sources/FakeFoundation/DataProtocol.swift @@ -0,0 +1,21 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2026 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +#if canImport(FoundationEssentials) +import FoundationEssentials +#else +import Foundation +#endif + +public protocol DataProtocol {} diff --git a/Sources/FakeFoundation/Date.swift b/Sources/FakeFoundation/Date.swift new file mode 100644 index 000000000..ee18b8afc --- /dev/null +++ b/Sources/FakeFoundation/Date.swift @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2026 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +#if canImport(FoundationEssentials) +import FoundationEssentials +#else +import Foundation +#endif + +public struct Date { + /// The interval between the date object and 00:00:00 UTC on 1 January 1970. + public var timeIntervalSince1970: Double { get } + + /// Returns a `Date` initialized relative to 00:00:00 UTC on 1 January 1970 by a given number of seconds. + public init(timeIntervalSince1970: Double) +} diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift index cb7eac727..1385894d3 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift @@ -456,6 +456,8 @@ extension FFMSwift2JavaGenerator { let arena = if let className = type.className, analysis.importedTypes[className] != nil + || type == .swiftkitFFMFoundationData + || type == .swiftkitFFMFoundationDataProtocol { // Use passed-in 'SwiftArena' for 'SwiftValue'. "swiftArena" @@ -619,7 +621,9 @@ extension FFMSwift2JavaGenerator { func renderMemoryLayoutValue(for javaType: JavaType) -> String { if let layout = ForeignValueLayout(javaType: javaType) { return layout.description - } else if case .class(package: _, name: let customClass, _) = javaType { + } else if case .class(.some(let package), name: let customClass, _) = javaType { + return ForeignValueLayout(customType: "\(package).\(customClass)").description + } else if case .class(.none, name: let customClass, _) = javaType { return ForeignValueLayout(customType: customClass).description } else { fatalError("renderMemoryLayoutValue not supported for \(javaType)") @@ -776,7 +780,7 @@ extension FFMSwift2JavaGenerator.JavaConversionStep { case .wrapMemoryAddressUnsafe(let inner, let javaType): let inner = inner.render(&printer, placeholder, placeholderForDowncall: placeholderForDowncall) - return "\(javaType.className!).wrapMemoryAddressUnsafe(\(inner), swiftArena)" + return "\(javaType).wrapMemoryAddressUnsafe(\(inner), swiftArena)" case .construct(let inner, let javaType): let inner = inner.render(&printer, placeholder, placeholderForDowncall: placeholderForDowncall) diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift index e3a61dc75..6fe7ccb6e 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift @@ -464,7 +464,15 @@ extension FFMSwift2JavaGenerator { ) case .foundationData, .essentialsData: - break + return TranslatedParameter( + javaParameters: [ + JavaParameter( + name: parameterName, + type: .swiftkitFFMFoundationData + ) + ], + conversion: .swiftValueSelfSegment(.placeholder) + ) case .swiftJavaError: // SwiftJavaError is a class — treat as arbitrary nominal type below @@ -635,10 +643,26 @@ extension FFMSwift2JavaGenerator { case .nominal(let nominal): if let knownType = nominal.nominalTypeDecl.knownTypeKind { switch knownType { - case .foundationData, .foundationDataProtocol: - break - case .essentialsData, .essentialsDataProtocol: - break + case .foundationData, .essentialsData: + return TranslatedParameter( + javaParameters: [ + JavaParameter( + name: parameterName, + type: .optional(.swiftkitFFMFoundationData) + ) + ], + conversion: .call(.placeholder, function: "SwiftRuntime.toOptionalSegmentInstance", withArena: false) + ) + case .foundationDataProtocol, .essentialsDataProtocol: + return TranslatedParameter( + javaParameters: [ + JavaParameter( + name: parameterName, + type: .optional(.swiftkitFFMFoundationDataProtocol) + ) + ], + conversion: .call(.placeholder, function: "SwiftRuntime.toOptionalSegmentInstance", withArena: false) + ) default: throw JavaTranslationError.unhandledType(known: .optional(swiftType)) } @@ -647,7 +671,7 @@ extension FFMSwift2JavaGenerator { let translatedTy = try self.translate(swiftType: swiftType) return TranslatedParameter( javaParameters: [ - JavaParameter(name: parameterName, type: JavaType(className: "Optional<\(translatedTy.description)>")) + JavaParameter(name: parameterName, type: .optional(translatedTy)) ], conversion: .call(.placeholder, function: "SwiftRuntime.toOptionalSegmentInstance", withArena: false) ) @@ -750,7 +774,15 @@ extension FFMSwift2JavaGenerator { ) case .foundationData, .essentialsData: - break // Implemented as wrapper + let javaType: JavaType = .swiftkitFFMFoundationData + return TranslatedResult( + javaResultType: javaType, + annotations: resultAnnotations, + outParameters: [ + JavaParameter(name: "", type: javaType) + ], + conversion: .wrapMemoryAddressUnsafe(.placeholder, javaType) + ) case .unsafePointer, .unsafeMutablePointer: // FIXME: Implement diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift index fe7372759..99b2640f3 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift @@ -71,6 +71,7 @@ extension FFMSwift2JavaGenerator { // === All types // We have to write all types to their corresponding output file that matches the file they were declared in, // because otherwise SwiftPM plugins will not pick up files apropriately -- we expect 1 output +SwiftJava.swift file for every input. + let filteredTypes: [String: ImportedNominalType] if let singleType = config.singleType { filteredTypes = self.analysis.importedTypes.filter { $0.key == singleType } @@ -92,14 +93,13 @@ extension FFMSwift2JavaGenerator { let filename = "\(inputFileName)".replacing(".swift", with: "+SwiftJava.swift") // Print file header before all type thunks - printer.print( - """ - // Generated by swift-java - - import SwiftRuntimeFunctions + printer.print("// Generated by swift-java") + printer.println() + if !group.value.allSatisfy({ $0.value.swiftNominal.moduleName == "SwiftRuntimeFunctions" }) { + printer.print("import SwiftRuntimeFunctions") + } + printer.println() - """ - ) self.lookupContext.symbolTable.printImportedModules(&printer) for ty in importedTypesForThisFile { @@ -263,16 +263,15 @@ struct SwiftThunkTranslator { /// Render special thunks for known types like Foundation.Data func renderSpecificTypeThunks(_ nominal: ImportedNominalType) -> [DeclSyntax] { - guard let knownType = nominal.swiftNominal.knownTypeKind else { - return [] - } - - switch knownType { - case .foundationData, .essentialsData: - return renderFoundationDataThunks(nominal) - default: - return [] + if nominal.swiftNominal.moduleName == "SwiftRuntimeFunctions" { + switch nominal.swiftNominal.qualifiedName { + case "Data": + return renderFoundationDataThunks(nominal) + default: + break + } } + return [] } /// Render Swift thunks for Foundation.Data helper methods diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift index 41c063048..65a3d9d65 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift @@ -448,7 +448,7 @@ extension FFMSwift2JavaGenerator { printer.print( """ - static MemorySegment findOrThrow(String symbol) { + public static MemorySegment findOrThrow(String symbol) { return SYMBOL_LOOKUP.find(symbol) .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: %s".formatted(symbol))); } @@ -557,15 +557,13 @@ extension FFMSwift2JavaGenerator { /// Print special helper methods for known types like Foundation.Data func printSpecificTypeHelpers(_ printer: inout CodePrinter, _ decl: ImportedNominalType) { - guard let knownType = decl.swiftNominal.knownTypeKind else { - return - } - - switch knownType { - case .foundationData, .essentialsData: - printFoundationDataHelpers(&printer, decl) - default: - break + if decl.swiftNominal.moduleName == "SwiftRuntimeFunctions" { + switch decl.swiftNominal.qualifiedName { + case "Data": + printFoundationDataHelpers(&printer, decl) + default: + break + } } } diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift index e6b3c71b8..ffee615f7 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift @@ -42,13 +42,21 @@ extension JNISwift2JavaGenerator { } package func writeExportedJavaSources(_ printer: inout CodePrinter) throws { - let importedTypes = analysis.importedTypes.sorted(by: { (lhs, rhs) in lhs.key < rhs.key }) + let typesToExport: [(key: String, value: ImportedNominalType)] + if let singleType = config.singleType { + typesToExport = analysis.importedTypes + .filter { $0.key == singleType } + .sorted(by: { $0.key < $1.key }) + } else { + typesToExport = analysis.importedTypes + .sorted(by: { $0.key < $1.key }) + } var exportedFileNames: OrderedSet = [] // Each parent type goes into its own file // any nested types are printed inside the body as `static class` - for (_, ty) in importedTypes.filter({ _, type in type.parent == nil }) { + for (_, ty) in typesToExport.filter({ _, type in type.parent == nil }) { let filename = "\(ty.effectiveJavaSimpleName).java" logger.debug("Printing contents: \(filename)") printImportedNominal(&printer, ty) @@ -63,17 +71,20 @@ extension JNISwift2JavaGenerator { } } - let filename = "\(self.swiftModuleName).java" - logger.trace("Printing module class: \(filename)") - printModule(&printer) + // Skip the module-level .swift file when generating for a single type + if config.singleType == nil { + let filename = "\(self.swiftModuleName).java" + logger.trace("Printing module class: \(filename)") + printModule(&printer) - if let outputFile = try printer.writeContents( - outputDirectory: javaOutputDirectory, - javaPackagePath: javaPackagePath, - filename: filename, - ) { - exportedFileNames.append(outputFile.path(percentEncoded: false)) - logger.info("[swift-java] Generated: \(self.swiftModuleName).java (at \(outputFile))") + if let outputFile = try printer.writeContents( + outputDirectory: javaOutputDirectory, + javaPackagePath: javaPackagePath, + filename: filename, + ) { + exportedFileNames.append(outputFile.path(percentEncoded: false)) + logger.info("[swift-java] Generated: \(self.swiftModuleName).java (at \(outputFile))") + } } // Write java sources list file @@ -338,17 +349,15 @@ extension JNISwift2JavaGenerator { /// Prints helpers for specific types like `Foundation.Date` private func printSpecificTypeHelpers(_ printer: inout CodePrinter, _ decl: ImportedNominalType) { - guard let knownType = decl.swiftNominal.knownTypeKind else { return } - - switch knownType { - case .foundationDate, .essentialsDate: - printFoundationDateHelpers(&printer, decl) - - case .foundationData, .essentialsData: - printFoundationDataHelpers(&printer, decl) - - default: - break + if decl.swiftNominal.moduleName == "SwiftJava" { + switch decl.swiftNominal.qualifiedName { + case "Date": + printFoundationDateHelpers(&printer, decl) + case "Data": + printFoundationDataHelpers(&printer, decl) + default: + break + } } } @@ -616,7 +625,7 @@ extension JNISwift2JavaGenerator { } generics.append((name, extends)) } - .map { "\($0) extends \($1.compactMap(\.className).joined(separator: " & "))" } + .map { "\($0) extends \($1.compactMap(\.description).joined(separator: " & "))" } .joined(separator: ", ") if !generics.isEmpty { diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift index f5a2fe320..410887f86 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift @@ -176,7 +176,7 @@ extension JNISwift2JavaGenerator { ), parameters: [], resultType: TranslatedResult( - javaType: .class(package: nil, name: "Optional", typeParameters: [.class(package: nil, name: caseName)]), + javaType: .optional(.class(package: nil, name: caseName)), outParameters: conversions.flatMap(\.translated.outParameters), conversion: enumCase.parameters.isEmpty ? constructRecordConversion @@ -505,10 +505,24 @@ extension JNISwift2JavaGenerator { ) case .foundationDate, .essentialsDate: - break // Handled as wrapped struct + return TranslatedParameter( + parameter: JavaParameter( + name: parameterName, + type: .concrete(.swiftkitCoreFoundationDate), + annotations: parameterAnnotations, + ), + conversion: .valueMemoryAddress(.placeholder), + ) case .foundationData, .essentialsData: - break // Handled as wrapped struct + return TranslatedParameter( + parameter: JavaParameter( + name: parameterName, + type: .concrete(.swiftkitCoreFoundationData), + annotations: parameterAnnotations, + ), + conversion: .valueMemoryAddress(.placeholder), + ) case .unsafeRawBufferPointer, .unsafeMutableRawBufferPointer: return TranslatedParameter( @@ -872,7 +886,7 @@ extension JNISwift2JavaGenerator { return TranslatedParameter( parameter: JavaParameter( name: parameterName, - type: .class(package: nil, name: "Optional", typeParameters: [javaType]), + type: .optional(javaType), annotations: parameterAnnotations, ), conversion: .method( @@ -945,12 +959,22 @@ extension JNISwift2JavaGenerator { ) case .foundationDate, .essentialsDate: - // Handled as wrapped struct - break + let javaType = JavaType.swiftkitCoreFoundationDate + return TranslatedResult( + javaType: javaType, + annotations: resultAnnotations, + outParameters: [], + conversion: .wrapMemoryAddressUnsafe(.placeholder, javaType), + ) case .foundationData, .essentialsData: - // Handled as wrapped struct - break + let javaType = JavaType.swiftkitCoreFoundationData + return TranslatedResult( + javaType: javaType, + annotations: resultAnnotations, + outParameters: [], + conversion: .wrapMemoryAddressUnsafe(.placeholder, javaType), + ) case .foundationUUID, .essentialsUUID: return TranslatedResult( @@ -1053,7 +1077,7 @@ extension JNISwift2JavaGenerator { genericParameters: genericParameters, genericRequirements: genericRequirements, ) - return .class(package: "java.util", name: "Optional", typeParameters: [wrappedType]) + return .optional(wrappedType) case .array: guard let elementType = nominalType.genericArguments?.first else { @@ -1094,13 +1118,13 @@ extension JNISwift2JavaGenerator { return .swiftSet(elementJavaType) case .foundationDate, .essentialsDate: - return .class(package: nil, name: "Date") + return .swiftkitCoreFoundationDate case .foundationData, .essentialsData: - return .class(package: nil, name: "Data") + return .swiftkitCoreFoundationData case .foundationDataProtocol, .essentialsDataProtocol: - return .class(package: nil, name: "DataProtocol") + return .swiftkitCoreFoundationDataProtocol case .foundationUUID, .essentialsUUID: return .javaUtilUUID @@ -1162,7 +1186,6 @@ extension JNISwift2JavaGenerator { genericParameters: [SwiftGenericParameterDeclaration], genericRequirements: [SwiftGenericRequirement], ) throws -> TranslatedResult { - let arity = elements.count var outParameters: [OutParameter] = [] var elementOutParamNames: [String] = [] var elementConversions: [JavaNativeConversionStep] = [] @@ -1338,7 +1361,7 @@ extension JNISwift2JavaGenerator { .void } - let returnType = JavaType.class(package: nil, name: "Optional", typeParameters: [javaType]) + let returnType = JavaType.optional(javaType) return TranslatedResult( javaType: returnType, annotations: parameterAnnotations, @@ -1896,16 +1919,22 @@ extension JNISwift2JavaGenerator { case .wrapMemoryAddressUnsafe(let inner, let javaType): let inner = inner.render(&printer, placeholder) - guard case .class(_, let className, let typeParameters) = javaType else { + guard case .class(let package, let className, let typeParameters) = javaType else { fatalError("\(javaType) is not class.") } + let packagePart: String = + if let package { + "\(package)." + } else { + "" + } let genericClause = if !typeParameters.isEmpty { "<\(typeParameters.map(\.description).joined(separator: ", "))>" } else { "" } - return "\(className).\(genericClause)wrapMemoryAddressUnsafe(\(inner), swiftArena)" + return "\(packagePart)\(className).\(genericClause)wrapMemoryAddressUnsafe(\(inner), swiftArena)" case .constructJavaClass(let inner, let javaType): let inner = inner.render(&printer, placeholder) diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift index 544b1b5ac..fdf1db9f3 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift @@ -57,24 +57,35 @@ extension JNISwift2JavaGenerator { let moduleFilename = "\(moduleFilenameBase).swift" do { - logger.trace("Printing swift module class: \(moduleFilename)") - - try printGlobalSwiftThunkSources(&printer) - - if let outputFile = try printer.writeContents( - outputDirectory: self.swiftOutputDirectory, - javaPackagePath: nil, - filename: moduleFilename, - ) { - logger.info("Generated: \(moduleFilenameBase.bold).swift (at \(outputFile.absoluteString))") - self.expectedOutputSwiftFileNames.remove(moduleFilename) + // Skip the module-level .swift file when generating for a single type + if config.singleType == nil { + logger.trace("Printing swift module class: \(moduleFilename)") + + try printGlobalSwiftThunkSources(&printer) + + if let outputFile = try printer.writeContents( + outputDirectory: self.swiftOutputDirectory, + javaPackagePath: nil, + filename: moduleFilename, + ) { + logger.info("Generated: \(moduleFilenameBase.bold).swift (at \(outputFile.absoluteString))") + self.expectedOutputSwiftFileNames.remove(moduleFilename) + } } // === All types // We have to write all types to their corresponding output file that matches the file they were declared in, // because otherwise SwiftPM plugins will not pick up files apropriately -- we expect 1 output +SwiftJava.swift file for every input. + + let filteredTypes: [String: ImportedNominalType] + if let singleType = config.singleType { + filteredTypes = self.analysis.importedTypes.filter { $0.key == singleType } + } else { + filteredTypes = self.analysis.importedTypes + } + for group: (key: String, value: [Dictionary.Element]) in Dictionary( - grouping: self.analysis.importedTypes, + grouping: filteredTypes, by: { $0.value.sourceFilePath }, ) { logger.warning("Writing types in file group: \(group.key): \(group.value.map(\.key))") @@ -275,7 +286,7 @@ extension JNISwift2JavaGenerator { } private func printGlobalSwiftThunkSources(_ printer: inout CodePrinter) throws { - printHeader(&printer) + printHeader(&printer, nil) for decl in analysis.importedGlobalFuncs { printSwiftFunctionThunk(&printer, decl) @@ -289,7 +300,7 @@ extension JNISwift2JavaGenerator { } private func printNominalTypeThunks(_ printer: inout CodePrinter, _ type: ImportedNominalType) throws { - printHeader(&printer) + printHeader(&printer, type) printJNICache(&printer, type) printer.println() @@ -818,17 +829,20 @@ extension JNISwift2JavaGenerator { } } - private func printHeader(_ printer: inout CodePrinter) { - printer.print( - """ - // Generated by swift-java - - import SwiftJava - import SwiftJavaJNICore - import SwiftJavaRuntimeSupport - - """ - ) + private func printHeader(_ printer: inout CodePrinter, _ type: ImportedNominalType?) { + var imports = [ + "SwiftJava", + "SwiftJavaJNICore", + ] + if !(type?.swiftNominal.moduleName == "SwiftJava") { + imports.append("SwiftJavaRuntimeSupport") + } + printer.print("// Generated by swift-java") + printer.println() + for package in imports { + printer.print("import \(package)") + } + printer.println() self.lookupContext.symbolTable.printImportedModules(&printer) } @@ -858,15 +872,14 @@ extension JNISwift2JavaGenerator { /// Prints thunks for specific known types like Foundation.Date, Foundation.Data private func printSpecificTypeThunks(_ printer: inout CodePrinter, _ type: ImportedNominalType) { - guard let knownType = type.swiftNominal.knownTypeKind else { return } - - switch knownType { - case .foundationData, .essentialsData: - printFoundationDataThunks(&printer, type) - printer.println() - - default: - break + if type.swiftNominal.moduleName == "SwiftJava" { + switch type.swiftNominal.qualifiedName { + case "Data": + printFoundationDataThunks(&printer, type) + printer.println() + default: + break + } } } diff --git a/Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift b/Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift index 34cb7f458..246f8a8b1 100644 --- a/Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift +++ b/Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift @@ -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]) + } + /// The description of the type java.util.concurrent.CompletableFuture static func completableFuture(_ T: JavaType) -> JavaType { .class(package: "java.util.concurrent", name: "CompletableFuture", typeParameters: [T.boxedType]) @@ -59,4 +64,23 @@ extension JavaType { .class(package: "java.util", name: "UUID") } + static var swiftkitCoreFoundationDate: JavaType { + .class(package: "org.swift.swiftkit.core.foundation", name: "Date") + } + + static var swiftkitCoreFoundationData: JavaType { + .class(package: "org.swift.swiftkit.core.foundation", name: "Data") + } + + static var swiftkitCoreFoundationDataProtocol: JavaType { + .class(package: "org.swift.swiftkit.core.foundation", name: "DataProtocol") + } + + static var swiftkitFFMFoundationData: JavaType { + .class(package: "org.swift.swiftkit.ffm.foundation", name: "Data") + } + + static var swiftkitFFMFoundationDataProtocol: JavaType { + .class(package: "org.swift.swiftkit.ffm.foundation", name: "DataProtocol") + } } diff --git a/Sources/JExtractSwiftLib/Swift2JavaTranslator.swift b/Sources/JExtractSwiftLib/Swift2JavaTranslator.swift index 106247a48..5ac2384d7 100644 --- a/Sources/JExtractSwiftLib/Swift2JavaTranslator.swift +++ b/Sources/JExtractSwiftLib/Swift2JavaTranslator.swift @@ -127,39 +127,6 @@ extension Swift2JavaTranslator { // Apply any specializations registered after their target types were visited visitor.applyPendingSpecializations() - - self.visitFoundationDeclsIfNeeded(with: visitor) - } - - private func visitFoundationDeclsIfNeeded(with visitor: Swift2JavaVisitor) { - // If any API uses 'Foundation.Data' or 'FoundationEssentials.Data', - // import 'Data' as if it's declared in this module. - if let dataDecl = self.symbolTable[.foundationData] ?? self.symbolTable[.essentialsData] { - let dataProtocolDecl = (self.symbolTable[.foundationDataProtocol] ?? self.symbolTable[.essentialsDataProtocol])! - if self.isUsing(where: { $0 == dataDecl || $0 == dataProtocolDecl }) { - visitor.visit( - nominalDecl: dataDecl.syntax!.asNominal!, - in: nil, - sourceFilePath: "Foundation/FAKE_FOUNDATION_DATA.swift", - ) - visitor.visit( - nominalDecl: dataProtocolDecl.syntax!.asNominal!, - in: nil, - sourceFilePath: "Foundation/FAKE_FOUNDATION_DATAPROTOCOL.swift", - ) - } - } - - // Foundation.Date - if let dateDecl = self.symbolTable[.foundationDate] ?? self.symbolTable[.essentialsDate] { - if self.isUsing(where: { $0 == dateDecl }) { - visitor.visit( - nominalDecl: dateDecl.syntax!.asNominal!, - in: nil, - sourceFilePath: "Foundation/FAKE_FOUNDATION_DATE.swift", - ) - } - } } package func prepareForTranslation() { diff --git a/Sources/SwiftJavaRuntimeSupport/Foundation/Data+SwiftJava.swift b/Sources/SwiftJavaRuntimeSupport/Foundation/Data+SwiftJava.swift new file mode 100644 index 000000000..3e8c20d68 --- /dev/null +++ b/Sources/SwiftJavaRuntimeSupport/Foundation/Data+SwiftJava.swift @@ -0,0 +1,90 @@ +// ==== -------------------------------------------------- +// Thunks for Data + +// Generated by swift-java + +import SwiftJava +import SwiftJavaJNICore + +#if canImport(FoundationEssentials) +import FoundationEssentials +#else +import Foundation +#endif + +enum _JNI_Data { +} // printJNICache(_:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+SwiftThunkPrinting.swift:177 + + +#if compiler(>=6.3) +@used +#endif +@_cdecl("Java_org_swift_swiftkit_core_foundation_Data__00024init___3B") +public func Java_org_swift_swiftkit_core_foundation_Data__00024init___3B(environment: UnsafeMutablePointer!, thisClass: jclass, bytes: jbyteArray?) -> jlong { + let result$ = UnsafeMutablePointer.allocate(capacity: 1) + result$.initialize(to: Data.init([UInt8](fromJNI: bytes, in: environment))) + let resultBits$ = Int64(Int(bitPattern: result$)) + return resultBits$.getJNILocalRefValue(in: environment) +} // printCDecl(_:javaMethodName:parentName:parameters:resultType:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+SwiftThunkPrinting.swift:819 + + +#if compiler(>=6.3) +@used +#endif +@_cdecl("Java_org_swift_swiftkit_core_foundation_Data__00024getCount__J") +public func Java_org_swift_swiftkit_core_foundation_Data__00024getCount__J(environment: UnsafeMutablePointer!, thisClass: jclass, selfPointer: jlong) -> jlong { + assert(selfPointer != 0, "selfPointer memory address was null") + let selfPointerBits$ = Int(Int64(fromJNI: selfPointer, in: environment)) + let selfPointer$ = UnsafeMutablePointer(bitPattern: selfPointerBits$) + guard let selfPointer$ else { + fatalError("selfPointer memory address was null in call to \(#function)!") + } + return Int64(selfPointer$.pointee.count).getJNILocalRefValue(in: environment) +} // printCDecl(_:javaMethodName:parentName:parameters:resultType:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+SwiftThunkPrinting.swift:819 + +#if compiler(>=6.3) +@used +#endif +@_cdecl("Java_org_swift_swiftkit_core_foundation_Data__00024toByteArray__J") +public func Java_org_swift_swiftkit_core_foundation_Data__00024toByteArray__J(environment: UnsafeMutablePointer!, thisClass: jclass, selfPointer: jlong) -> jbyteArray? { + guard let env$ = environment else { + fatalError("Missing JNIEnv in downcall to \(#function)") + } + assert(selfPointer != 0, "selfPointer memory address was null") + let selfPointerBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) + guard let selfPointer$ = UnsafeMutablePointer(bitPattern: selfPointerBits$) else { + fatalError("selfPointer memory address was null in call to \(#function)!") + } + return selfPointer$.pointee.withUnsafeBytes { buffer in + buffer.getJNIValue(in: environment) + } +} // printCDecl(_:javaMethodName:parentName:parameters:resultType:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+SwiftThunkPrinting.swift:819 +#if compiler(>=6.3) +@used +#endif +@_cdecl("Java_org_swift_swiftkit_core_foundation_Data__00024toByteArrayIndirectCopy__J") +public func Java_org_swift_swiftkit_core_foundation_Data__00024toByteArrayIndirectCopy__J( + environment: UnsafeMutablePointer!, + thisClass: jclass, + selfPointer: jlong +) -> jbyteArray? { + guard let env$ = environment else { + fatalError("Missing JNIEnv in downcall to \(#function)") + } + assert(selfPointer != 0, "selfPointer memory address was null") + let selfPointerBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) + guard let selfPointer$ = UnsafeMutablePointer(bitPattern: selfPointerBits$) else { + fatalError("selfPointer memory address was null in call to \(#function)!") + } + // This is a double copy, we need to initialize the array and then copy into a JVM array in getJNIValue + return [UInt8](selfPointer$.pointee).getJNIValue(in: environment) +} // printCDecl(_:javaMethodName:parentName:parameters:resultType:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+SwiftThunkPrinting.swift:819 + +#if compiler(>=6.3) +@used +#endif +@_cdecl("Java_org_swift_swiftkit_core_foundation_Data__00024typeMetadataAddressDowncall__") +public func Java_org_swift_swiftkit_core_foundation_Data__00024typeMetadataAddressDowncall__(environment: UnsafeMutablePointer!, thisClass: jclass) -> jlong { + let metadataPointer = unsafeBitCast(Data.self, to: UnsafeRawPointer.self) + return Int64(Int(bitPattern: metadataPointer)).getJNIValue(in: environment) +} // printCDecl(_:javaMethodName:parentName:parameters:resultType:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+SwiftThunkPrinting.swift:819 diff --git a/Sources/SwiftJavaRuntimeSupport/Foundation/DataProtocol+SwiftJava.swift b/Sources/SwiftJavaRuntimeSupport/Foundation/DataProtocol+SwiftJava.swift new file mode 100644 index 000000000..ad62ac0a0 --- /dev/null +++ b/Sources/SwiftJavaRuntimeSupport/Foundation/DataProtocol+SwiftJava.swift @@ -0,0 +1,16 @@ +// ==== -------------------------------------------------- +// Thunks for DataProtocol + +// Generated by swift-java + +import SwiftJava +import SwiftJavaJNICore + +#if canImport(FoundationEssentials) +import FoundationEssentials +#else +import Foundation +#endif + +enum _JNI_DataProtocol { +} // printJNICache(_:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+SwiftThunkPrinting.swift:177 diff --git a/Sources/SwiftJavaRuntimeSupport/Foundation/Date+SwiftJava.swift b/Sources/SwiftJavaRuntimeSupport/Foundation/Date+SwiftJava.swift new file mode 100644 index 000000000..6a240919a --- /dev/null +++ b/Sources/SwiftJavaRuntimeSupport/Foundation/Date+SwiftJava.swift @@ -0,0 +1,54 @@ +// ==== -------------------------------------------------- +// Thunks for Date + +// Generated by swift-java + +import SwiftJava +import SwiftJavaJNICore + +#if canImport(FoundationEssentials) +import FoundationEssentials +#else +import Foundation +#endif + +enum _JNI_Date { +} // printJNICache(_:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+SwiftThunkPrinting.swift:177 + +#if compiler(>=6.3) +@used +#endif +@_cdecl("Java_org_swift_swiftkit_core_foundation_Date__00024init__D") +public func Java_org_swift_swiftkit_core_foundation_Date__00024init__D(environment: UnsafeMutablePointer!, thisClass: jclass, timeIntervalSince1970: jdouble) -> jlong { + let result$ = UnsafeMutablePointer.allocate(capacity: 1) + result$.initialize(to: Date.init(timeIntervalSince1970: Double(fromJNI: timeIntervalSince1970, in: environment))) + let resultBits$ = Int64(Int(bitPattern: result$)) + return resultBits$.getJNILocalRefValue(in: environment) +} // printCDecl(_:javaMethodName:parentName:parameters:resultType:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+SwiftThunkPrinting.swift:819 + +#if compiler(>=6.3) +@used +#endif +@_cdecl("Java_org_swift_swiftkit_core_foundation_Date__00024getTimeIntervalSince1970__J") +public func Java_org_swift_swiftkit_core_foundation_Date__00024getTimeIntervalSince1970__J( + environment: UnsafeMutablePointer!, + thisClass: jclass, + selfPointer: jlong +) -> jdouble { + assert(selfPointer != 0, "selfPointer memory address was null") + let selfPointerBits$ = Int(Int64(fromJNI: selfPointer, in: environment)) + let selfPointer$ = UnsafeMutablePointer(bitPattern: selfPointerBits$) + guard let selfPointer$ else { + fatalError("selfPointer memory address was null in call to \(#function)!") + } + return selfPointer$.pointee.timeIntervalSince1970.getJNILocalRefValue(in: environment) +} // printCDecl(_:javaMethodName:parentName:parameters:resultType:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+SwiftThunkPrinting.swift:819 + +#if compiler(>=6.3) +@used +#endif +@_cdecl("Java_org_swift_swiftkit_core_foundation_Date__00024typeMetadataAddressDowncall__") +public func Java_org_swift_swiftkit_core_foundation_Date__00024typeMetadataAddressDowncall__(environment: UnsafeMutablePointer!, thisClass: jclass) -> jlong { + let metadataPointer = unsafeBitCast(Date.self, to: UnsafeRawPointer.self) + return Int64(Int(bitPattern: metadataPointer)).getJNIValue(in: environment) +} // printCDecl(_:javaMethodName:parentName:parameters:resultType:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+SwiftThunkPrinting.swift:819 diff --git a/Sources/SwiftRuntimeFunctions/Foundation/Data+SwiftJava.swift b/Sources/SwiftRuntimeFunctions/Foundation/Data+SwiftJava.swift new file mode 100644 index 000000000..2f9970b8a --- /dev/null +++ b/Sources/SwiftRuntimeFunctions/Foundation/Data+SwiftJava.swift @@ -0,0 +1,51 @@ +// Generated by swift-java + + +#if canImport(FoundationEssentials) +import FoundationEssentials +#else +import Foundation +#endif + + +// ==== -------------------------------------------------- +// Thunks for Data + +@_cdecl("swiftjava_getType_SwiftRuntimeFunctions_Data") +public func swiftjava_getType_SwiftRuntimeFunctions_Data() -> UnsafeMutableRawPointer /* Any.Type */ { + unsafeBitCast(Data.self, to: UnsafeMutableRawPointer.self) +} + +@_cdecl("swiftjava_SwiftRuntimeFunctions_Data_init_bytes_count") +public func swiftjava_SwiftRuntimeFunctions_Data_init_bytes_count(_ bytes: UnsafeRawPointer, _ count: Int, _ _result: UnsafeMutableRawPointer) { + _result.assumingMemoryBound(to: Data.self).initialize(to: Data(bytes: bytes, count: count)) +} + +@_cdecl("swiftjava_SwiftRuntimeFunctions_Data_init__") +public func swiftjava_SwiftRuntimeFunctions_Data_init__(_ bytes_pointer: UnsafeRawPointer, _ bytes_count: Int, _ _result: UnsafeMutableRawPointer) { + _result.assumingMemoryBound(to: Data.self).initialize(to: Data([UInt8](UnsafeRawBufferPointer(start: bytes_pointer, count: bytes_count)))) +} + +@_cdecl("swiftjava_SwiftRuntimeFunctions_Data_count$get") +public func swiftjava_SwiftRuntimeFunctions_Data_count$get(_ self: UnsafeRawPointer) -> Int { + self.assumingMemoryBound(to: Data.self).pointee.count +} + +@_cdecl("swiftjava_SwiftRuntimeFunctions_Data_withUnsafeBytes__") +public func swiftjava_SwiftRuntimeFunctions_Data_withUnsafeBytes__(_ body: @convention(c) (UnsafeRawPointer?, Int) -> Void, _ self: UnsafeRawPointer) { + self.assumingMemoryBound(to: Data.self).pointee.withUnsafeBytes({ (_0) in + body(_0.baseAddress, _0.count) + }) +} + +@_cdecl("swiftjava_SwiftRuntimeFunctions_Data_copyBytes__") +public func swiftjava_SwiftRuntimeFunctions_Data_copyBytes__( + selfPointer: UnsafeRawPointer, + destinationPointer: UnsafeMutableRawPointer, + count: Int +) { + let data = selfPointer.assumingMemoryBound(to: Data.self).pointee + data.withUnsafeBytes { buffer in + destinationPointer.copyMemory(from: buffer.baseAddress!, byteCount: count) + } +} diff --git a/Sources/SwiftRuntimeFunctions/Foundation/DataProtocol+SwiftJava.swift b/Sources/SwiftRuntimeFunctions/Foundation/DataProtocol+SwiftJava.swift new file mode 100644 index 000000000..30db7ec84 --- /dev/null +++ b/Sources/SwiftRuntimeFunctions/Foundation/DataProtocol+SwiftJava.swift @@ -0,0 +1,17 @@ +// Generated by swift-java + + +#if canImport(FoundationEssentials) +import FoundationEssentials +#else +import Foundation +#endif + + +// ==== -------------------------------------------------- +// Thunks for DataProtocol + +@_cdecl("swiftjava_getType_SwiftRuntimeFunctions_DataProtocol") +public func swiftjava_getType_SwiftRuntimeFunctions_DataProtocol() -> UnsafeMutableRawPointer /* Any.Type */ { + unsafeBitCast(DataProtocol.self, to: UnsafeMutableRawPointer.self) +} diff --git a/Sources/SwiftRuntimeFunctions/generated/SwiftJavaError+SwiftJava.swift b/Sources/SwiftRuntimeFunctions/generated/SwiftJavaError+SwiftJava.swift index bdc2d8494..3faaa80b5 100644 --- a/Sources/SwiftRuntimeFunctions/generated/SwiftJavaError+SwiftJava.swift +++ b/Sources/SwiftRuntimeFunctions/generated/SwiftJavaError+SwiftJava.swift @@ -1,6 +1,5 @@ // Generated by swift-java -import SwiftRuntimeFunctions // ==== -------------------------------------------------- // Thunks for SwiftJavaError diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/foundation/Data.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/foundation/Data.java new file mode 100644 index 000000000..bd9afe7cb --- /dev/null +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/foundation/Data.java @@ -0,0 +1,176 @@ +// Generated by jextract-swift +// Swift module: SwiftJava + +package org.swift.swiftkit.core.foundation; + +import org.swift.swiftkit.core.*; +import org.swift.swiftkit.core.util.*; +import org.swift.swiftkit.core.collections.*; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import org.swift.swiftkit.core.annotations.*; + +public final class Data implements JNISwiftInstance, DataProtocol { + static final String LIB_NAME = "SwiftJava"; + + @SuppressWarnings("unused") + private static final boolean INITIALIZED_LIBS = initializeLibs(); + static boolean initializeLibs() { + System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_JAVA); + System.loadLibrary(LIB_NAME); + return true; + } + /** + * The designated constructor of any imported Swift types. + * + * @param selfPointer a pointer to the memory containing the value + * @param swiftArena the arena this object belongs to. When the arena goes out of scope, this value is destroyed. + */ + private Data(long selfPointer, SwiftArena swiftArena) { + SwiftObjects.requireNonZero(selfPointer, "selfPointer"); + this.selfPointer = selfPointer; + + // Only register once we have fully initialized the object since this will need the object pointer. + swiftArena.register(this); + } // printConcreteType(_:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+JavaBindingsPrinting.swift:241 + + /** + * Assume that the passed {@code long} represents a memory address of a {@link Data}. + *

+ * Warnings: + *

    + *
  • No checks are performed about the compatibility of the pointed at memory and the actual Data types.
  • + *
  • This operation does not copy, or retain, the pointed at pointer, so its lifetime must be ensured manually to be valid when wrapping.
  • + *
+ */ + public static Data wrapMemoryAddressUnsafe(long selfPointer, SwiftArena swiftArena) { + return new Data(selfPointer, swiftArena); + } + + public static Data wrapMemoryAddressUnsafe(long selfPointer) { + return new Data(selfPointer, SwiftMemoryManagement.DEFAULT_SWIFT_JAVA_AUTO_ARENA); + } + /** Pointer to the "self". */ + private final long selfPointer; + + /** Used to track additional state of the underlying object, e.g. if it was explicitly destroyed. */ + private final AtomicBoolean $state$destroyed = new AtomicBoolean(false); + + public long $memoryAddress() { + return this.selfPointer; + } + + @Override + public AtomicBoolean $statusDestroyedFlag() { + return $state$destroyed; + } + + + + // ==== -------------------------------------------------- + // Data.init + + /** + * Downcall to Swift: + * {@snippet lang=swift : + * public init(_ bytes: [UInt8]) + * } + */ + public static Data init(@Unsigned byte[] bytes, SwiftArena swiftArena) { + return Data.wrapMemoryAddressUnsafe(Data.$init(Objects.requireNonNull(bytes, "bytes must not be null")), swiftArena); + } // printJavaBindingWrapperMethod(_:_:importedFunc:skipMethodBody:) @ JExtractSwiftLib/JNISwift2JavaGenerator+JavaBindingsPrinting.swift:693 + private static native long $init(byte[] bytes); + + + + // ==== -------------------------------------------------- + // getter:Data.count + + /** + * Downcall to Swift: + * {@snippet lang=swift : + * public var count: Int + * } + */ + public long getCount() { + return Data.$getCount(this.$memoryAddress()); + } // printJavaBindingWrapperMethod(_:_:importedFunc:skipMethodBody:) @ JExtractSwiftLib/JNISwift2JavaGenerator+JavaBindingsPrinting.swift:693 + private static native long $getCount(long selfPointer); + + /** + * Creates a new Swift @{link Data} instance from a byte array. + * + * @param bytes The byte array to copy into the Data + * @param swiftArena The arena for memory management + * @return A new Data instance containing a copy of the bytes + */ + public static Data fromByteArray(byte[] bytes, SwiftArena swiftArena) { + Objects.requireNonNull(bytes, "bytes cannot be null"); + return Data.init(bytes, swiftArena); + } + /** + * Copies the contents of this Data to a new byte array. + * + * This is a relatively efficient implementation, which avoids native array copies, + * however it will still perform a copy of the data onto the JVM heap, so use this + * only when necessary. + * + *

When utmost performance is necessary, you may want to investigate the FFM mode + * of jextract which is able to map memory more efficiently. + * + * @return A byte array containing a copy of this Data's bytes + */ + public byte[] toByteArray() { + return $toByteArray(this.$memoryAddress()); + } + private static native byte[] $toByteArray(long selfPointer); + + /** + * Copies the contents of this Data to a new byte array. + * + * @deprecated Prefer using the `toByteArray` method as it is more performant. + * This implementation uses a naive conversion path from native bytes into jbytes + * and then copying them onto the jvm heap. + * + * @return A byte array containing a copy of this Data's bytes + */ + @Deprecated(forRemoval = true) + public byte[] toByteArrayIndirectCopy() { + return $toByteArrayIndirectCopy(this.$memoryAddress()); + } + + private static native byte[] $toByteArrayIndirectCopy(long selfPointer); + private static native long $typeMetadataAddressDowncall(); + @Override + public long $typeMetadataAddress() { + return Data.$typeMetadataAddressDowncall(); + } // printTypeMetadataAddressFunction(_:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+JavaBindingsPrinting.swift:785 + + public String toString() { + return SwiftObjects.toString(this.$memoryAddress(), this.$typeMetadataAddress()); + } + + public String toDebugString() { + return SwiftObjects.toDebugString(this.$memoryAddress(), this.$typeMetadataAddress()); + } + + @Override + public Runnable $createDestroyFunction() { + long self$ = this.$memoryAddress(); + long selfType$ = this.$typeMetadataAddress(); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall("Data.$createDestroyFunction", + "this", this, + "self", self$); + } + return new Runnable() { + @Override + public void run() { + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall("Data.$destroy", "self", self$); + } + SwiftObjects.destroy(self$, selfType$); + } + }; + } // printDestroyFunction(_:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+JavaBindingsPrinting.swift:799 +} // printNominal(_:_:body:) @ JExtractSwiftLib/JNISwift2JavaGenerator+JavaBindingsPrinting.swift:411 diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/foundation/DataProtocol.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/foundation/DataProtocol.java new file mode 100644 index 000000000..1a9f82f73 --- /dev/null +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/foundation/DataProtocol.java @@ -0,0 +1,14 @@ +// Generated by jextract-swift +// Swift module: SwiftJava + +package org.swift.swiftkit.core.foundation; + +import org.swift.swiftkit.core.*; +import org.swift.swiftkit.core.util.*; +import org.swift.swiftkit.core.collections.*; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import org.swift.swiftkit.core.annotations.*; + +public interface DataProtocol extends JNISwiftInstance { +} // printProtocol(_:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+JavaBindingsPrinting.swift:165 diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/foundation/Date.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/foundation/Date.java new file mode 100644 index 000000000..59368c852 --- /dev/null +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/foundation/Date.java @@ -0,0 +1,173 @@ +// Generated by jextract-swift +// Swift module: SwiftJava + +package org.swift.swiftkit.core.foundation; + +import org.swift.swiftkit.core.*; +import org.swift.swiftkit.core.util.*; +import org.swift.swiftkit.core.collections.*; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import org.swift.swiftkit.core.annotations.*; + +public final class Date implements JNISwiftInstance { + static final String LIB_NAME = "SwiftJava"; + + @SuppressWarnings("unused") + private static final boolean INITIALIZED_LIBS = initializeLibs(); + static boolean initializeLibs() { + System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_JAVA); + System.loadLibrary(LIB_NAME); + return true; + } + /** + * The designated constructor of any imported Swift types. + * + * @param selfPointer a pointer to the memory containing the value + * @param swiftArena the arena this object belongs to. When the arena goes out of scope, this value is destroyed. + */ + private Date(long selfPointer, SwiftArena swiftArena) { + SwiftObjects.requireNonZero(selfPointer, "selfPointer"); + this.selfPointer = selfPointer; + + // Only register once we have fully initialized the object since this will need the object pointer. + swiftArena.register(this); + } // printConcreteType(_:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+JavaBindingsPrinting.swift:241 + + /** + * Assume that the passed {@code long} represents a memory address of a {@link Date}. + *

+ * Warnings: + *

    + *
  • No checks are performed about the compatibility of the pointed at memory and the actual Date types.
  • + *
  • This operation does not copy, or retain, the pointed at pointer, so its lifetime must be ensured manually to be valid when wrapping.
  • + *
+ */ + public static Date wrapMemoryAddressUnsafe(long selfPointer, SwiftArena swiftArena) { + return new Date(selfPointer, swiftArena); + } + + public static Date wrapMemoryAddressUnsafe(long selfPointer) { + return new Date(selfPointer, SwiftMemoryManagement.DEFAULT_SWIFT_JAVA_AUTO_ARENA); + } + /** Pointer to the "self". */ + private final long selfPointer; + + /** Used to track additional state of the underlying object, e.g. if it was explicitly destroyed. */ + private final AtomicBoolean $state$destroyed = new AtomicBoolean(false); + + public long $memoryAddress() { + return this.selfPointer; + } + + @Override + public AtomicBoolean $statusDestroyedFlag() { + return $state$destroyed; + } + + + // ==== -------------------------------------------------- + // Date.init + + /** + * Downcall to Swift: + * {@snippet lang=swift : + * public init(timeIntervalSince1970: Double) + * } + */ + public static Date init(double timeIntervalSince1970, SwiftArena swiftArena) { + return Date.wrapMemoryAddressUnsafe(Date.$init(timeIntervalSince1970), swiftArena); + } // printJavaBindingWrapperMethod(_:_:importedFunc:skipMethodBody:) @ JExtractSwiftLib/JNISwift2JavaGenerator+JavaBindingsPrinting.swift:693 + private static native long $init(double timeIntervalSince1970); + + + // ==== -------------------------------------------------- + // getter:Date.timeIntervalSince1970 + + /** + * Downcall to Swift: + * {@snippet lang=swift : + * public var timeIntervalSince1970: Double + * } + */ + public double getTimeIntervalSince1970() { + return Date.$getTimeIntervalSince1970(this.$memoryAddress()); + } // printJavaBindingWrapperMethod(_:_:importedFunc:skipMethodBody:) @ JExtractSwiftLib/JNISwift2JavaGenerator+JavaBindingsPrinting.swift:693 + private static native double $getTimeIntervalSince1970(long selfPointer); + + /** + * Converts this wrapped date to a Java {@link java.time.Instant}. + *

+ * This method constructs the {@code Instant} using the underlying {@code double} value + * representing seconds since the Unix Epoch (January 1, 1970). + *

+ * + * @return A {@code java.time.Instant} derived from the floating-point timestamp. + */ + public java.time.Instant toInstant() { + long seconds = (long) this.getTimeIntervalSince1970(); + long nanos = Math.round((this.getTimeIntervalSince1970() - seconds) * 1_000_000_000); + return java.time.Instant.ofEpochSecond(seconds, nanos); + } + + /** + * Initializes a Swift {@code Foundation.Date} from a Java {@link java.time.Instant}. + * + *

Warning: Precision Loss

+ *

+ * The input precision will be degraded. + *

+ *

+ * Java's {@code Instant} stores time with nanosecond precision (9 decimal places). + * However, this class stores time as a 64-bit floating-point value. + *

+ *

+ * This leaves enough capacity for microsecond precision (approx. 6 decimal places). + *

+ *

+ * Consequently, the last ~3 digits of the {@code Instant}'s nanosecond field will be + * truncated or subjected to rounding errors during conversion. + *

+ * + * @param instant The source timestamp to convert. + * @return A date derived from the input instant with microsecond precision. + */ + public static Date fromInstant(java.time.Instant instant, SwiftArena swiftArena) { + Objects.requireNonNull(instant, "Instant cannot be null"); + double timeIntervalSince1970 = instant.getEpochSecond() + (instant.getNano() / 1_000_000_000.0); + return Date.init(timeIntervalSince1970, swiftArena); + } + private static native long $typeMetadataAddressDowncall(); + @Override + public long $typeMetadataAddress() { + return Date.$typeMetadataAddressDowncall(); + } // printTypeMetadataAddressFunction(_:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+JavaBindingsPrinting.swift:785 + + public String toString() { + return SwiftObjects.toString(this.$memoryAddress(), this.$typeMetadataAddress()); + } + + public String toDebugString() { + return SwiftObjects.toDebugString(this.$memoryAddress(), this.$typeMetadataAddress()); + } + + @Override + public Runnable $createDestroyFunction() { + long self$ = this.$memoryAddress(); + long selfType$ = this.$typeMetadataAddress(); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall("Date.$createDestroyFunction", + "this", this, + "self", self$); + } + return new Runnable() { + @Override + public void run() { + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall("Date.$destroy", "self", self$); + } + SwiftObjects.destroy(self$, selfType$); + } + }; + } // printDestroyFunction(_:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+JavaBindingsPrinting.swift:799 +} // printNominal(_:_:body:) @ JExtractSwiftLib/JNISwift2JavaGenerator+JavaBindingsPrinting.swift:411 diff --git a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/foundation/Data.java b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/foundation/Data.java new file mode 100644 index 000000000..04a9603e5 --- /dev/null +++ b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/foundation/Data.java @@ -0,0 +1,387 @@ +// Generated by jextract-swift +// Swift module: SwiftRuntimeFunctions + +package org.swift.swiftkit.ffm.foundation; + +import org.swift.swiftkit.core.*; +import org.swift.swiftkit.core.util.*; +import org.swift.swiftkit.ffm.*; +import org.swift.swiftkit.ffm.generated.*; +import org.swift.swiftkit.core.annotations.*; +import java.lang.foreign.*; +import java.lang.invoke.*; +import java.util.*; +import java.nio.charset.StandardCharsets; + +public final class Data extends FFMSwiftInstance implements SwiftValue { + static final String LIB_NAME = "SwiftRuntimeFunctions"; + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + @SuppressWarnings("unused") + private static final boolean INITIALIZED_LIBS = initializeLibs(); + static boolean initializeLibs() { + SwiftLibraries.loadLibraryWithFallbacks(SwiftLibraries.LIB_NAME_SWIFT_CORE); + SwiftLibraries.loadLibraryWithFallbacks(SwiftLibraries.LIB_NAME_SWIFT_JAVA); + SwiftLibraries.loadLibraryWithFallbacks(SwiftLibraries.LIB_NAME_SWIFT_RUNTIME_FUNCTIONS); + SwiftLibraries.loadLibraryWithFallbacks(LIB_NAME); + return true; + } + + public static final SwiftAnyType TYPE_METADATA = + new SwiftAnyType(SwiftRuntime.swiftjava.getType("SwiftRuntimeFunctions", "Data")); + public final SwiftAnyType $swiftType() { + return TYPE_METADATA; + } + + public static final GroupLayout $LAYOUT = (GroupLayout) SwiftValueWitnessTable.layoutOfSwiftType(TYPE_METADATA.$memorySegment()); + public final GroupLayout $layout() { + return $LAYOUT; + } + + private Data(MemorySegment segment, AllocatingSwiftArena arena) { + super(segment, arena); + } + + /** + * Assume that the passed {@code MemorySegment} represents a memory address of a {@link Data}. + *

+ * Warnings: + *

    + *
  • No checks are performed about the compatibility of the pointed at memory and the actual Data types.
  • + *
  • This operation does not copy, or retain, the pointed at pointer, so its lifetime must be ensured manually to be valid when wrapping.
  • + *
+ */ + public static Data wrapMemoryAddressUnsafe(MemorySegment selfPointer, AllocatingSwiftArena arena) { + return new Data(selfPointer, arena); + } + + // ==== -------------------------------------------------- + // Data.init + + /** + * {@snippet lang=c : + * void swiftjava_SwiftRuntimeFunctions_Data_init_bytes_count(const void *bytes, ptrdiff_t count, void *_result) + * } + */ + private static class swiftjava_SwiftRuntimeFunctions_Data_init_bytes_count { + private static final FunctionDescriptor DESC = FunctionDescriptor.ofVoid( + /* bytes: */SwiftValueLayout.SWIFT_POINTER, + /* count: */SwiftValueLayout.SWIFT_INT, + /* _result: */SwiftValueLayout.SWIFT_POINTER + ); + private static final MemorySegment ADDR = + SwiftRuntimeFunctions.findOrThrow("swiftjava_SwiftRuntimeFunctions_Data_init_bytes_count"); + private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); + public static void call(java.lang.foreign.MemorySegment bytes, long count, java.lang.foreign.MemorySegment _result) { + try { + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(bytes, count, _result); + } + HANDLE.invokeExact(bytes, count, _result); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } // printJavaBindingDescriptorClass(_:_:symbolLookup:additionalContent:) @ JExtractSwiftLib/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift:65 + /** + * Downcall to Swift: + * {@snippet lang=swift : + * public init(bytes: UnsafeRawPointer, count: Int) + * } + */ + public static Data init(java.lang.foreign.MemorySegment bytes, long count, AllocatingSwiftArena swiftArena) throws SwiftIntegerOverflowException { + MemorySegment result$ = swiftArena.allocate(Data.$LAYOUT); + if (SwiftValueLayout.has32bitSwiftInt) { + if (count < Integer.MIN_VALUE || count > Integer.MAX_VALUE) { + throw new SwiftIntegerOverflowException("Parameter 'count' overflow: " + count); + } // printDowncall(_:_:) @ JExtractSwiftLib/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift:506 + } // printDowncall(_:_:) @ JExtractSwiftLib/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift:498 + swiftjava_SwiftRuntimeFunctions_Data_init_bytes_count.call(bytes, count, result$); + return Data.wrapMemoryAddressUnsafe(result$, swiftArena); + } // printJavaBindingWrapperMethod(_:_:) @ JExtractSwiftLib/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift:403 + + // ==== -------------------------------------------------- + // Data.init + + /** + * {@snippet lang=c : + * void swiftjava_SwiftRuntimeFunctions_Data_init__(const void *bytes_pointer, ptrdiff_t bytes_count, void *_result) + * } + */ + private static class swiftjava_SwiftRuntimeFunctions_Data_init__ { + private static final FunctionDescriptor DESC = FunctionDescriptor.ofVoid( + /* bytes_pointer: */SwiftValueLayout.SWIFT_POINTER, + /* bytes_count: */SwiftValueLayout.SWIFT_INT, + /* _result: */SwiftValueLayout.SWIFT_POINTER + ); + private static final MemorySegment ADDR = + SwiftRuntimeFunctions.findOrThrow("swiftjava_SwiftRuntimeFunctions_Data_init__"); + private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); + public static void call(java.lang.foreign.MemorySegment bytes_pointer, long bytes_count, java.lang.foreign.MemorySegment _result) { + try { + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(bytes_pointer, bytes_count, _result); + } + HANDLE.invokeExact(bytes_pointer, bytes_count, _result); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } // printJavaBindingDescriptorClass(_:_:symbolLookup:additionalContent:) @ JExtractSwiftLib/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift:65 + /** + * Downcall to Swift: + * {@snippet lang=swift : + * public init(_ bytes: [UInt8]) + * } + */ + public static Data init(@Unsigned byte[] bytes, AllocatingSwiftArena swiftArena) { + try(var arena$ = Arena.ofConfined()) { + MemorySegment result$ = swiftArena.allocate(Data.$LAYOUT); + swiftjava_SwiftRuntimeFunctions_Data_init__.call(arena$.allocateFrom(ValueLayout.JAVA_BYTE, bytes), bytes.length, result$); + return Data.wrapMemoryAddressUnsafe(result$, swiftArena); + } + } // printJavaBindingWrapperMethod(_:_:) @ JExtractSwiftLib/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift:403 + + // ==== -------------------------------------------------- + // getter:Data.count + + /** + * {@snippet lang=c : + * ptrdiff_t swiftjava_SwiftRuntimeFunctions_Data_count$get(const void *self) + * } + */ + private static class swiftjava_SwiftRuntimeFunctions_Data_count$get { + private static final FunctionDescriptor DESC = FunctionDescriptor.of( + /* -> */SwiftValueLayout.SWIFT_INT, + /* self: */SwiftValueLayout.SWIFT_POINTER + ); + private static final MemorySegment ADDR = + SwiftRuntimeFunctions.findOrThrow("swiftjava_SwiftRuntimeFunctions_Data_count$get"); + private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); + public static long call(java.lang.foreign.MemorySegment self) { + try { + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(self); + } + return (long) HANDLE.invokeExact(self); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } // printJavaBindingDescriptorClass(_:_:symbolLookup:additionalContent:) @ JExtractSwiftLib/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift:65 + /** + * Downcall to Swift: + * {@snippet lang=swift : + * public var count: Int + * } + */ + public long getCount() throws SwiftIntegerOverflowException { + $ensureAlive(); + long result$checked = swiftjava_SwiftRuntimeFunctions_Data_count$get.call(this.$memorySegment()); + if (SwiftValueLayout.has32bitSwiftInt) { + if (result$checked < Integer.MIN_VALUE || result$checked > Integer.MAX_VALUE) { + throw new SwiftIntegerOverflowException("Return value overflow: " + result$checked); + } // printReturnWithOverflowCheck(_:value:overflowCheck:) @ JExtractSwiftLib/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift:603 + } // printReturnWithOverflowCheck(_:value:overflowCheck:) @ JExtractSwiftLib/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift:602 + return result$checked; + } // printJavaBindingWrapperMethod(_:_:) @ JExtractSwiftLib/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift:403 + + // ==== -------------------------------------------------- + // Data.withUnsafeBytes + + /** + * {@snippet lang=c : + * void swiftjava_SwiftRuntimeFunctions_Data_withUnsafeBytes__(void (*body)(const void *, ptrdiff_t), const void *self) + * } + */ + private static class swiftjava_SwiftRuntimeFunctions_Data_withUnsafeBytes__ { + private static final FunctionDescriptor DESC = FunctionDescriptor.ofVoid( + /* body: */SwiftValueLayout.SWIFT_POINTER, + /* self: */SwiftValueLayout.SWIFT_POINTER + ); + private static final MemorySegment ADDR = + SwiftRuntimeFunctions.findOrThrow("swiftjava_SwiftRuntimeFunctions_Data_withUnsafeBytes__"); + private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); + public static void call(java.lang.foreign.MemorySegment body, java.lang.foreign.MemorySegment self) { + try { + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(body, self); + } + HANDLE.invokeExact(body, self); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + /** + * {snippet lang=c : + * void (*)(const void *, ptrdiff_t) + * } + */ + private static class $body { + @FunctionalInterface + public interface Function { + void apply(java.lang.foreign.MemorySegment _0, long _1); + } + private static final FunctionDescriptor DESC = FunctionDescriptor.ofVoid( + /* _0: */SwiftValueLayout.SWIFT_POINTER, + /* _1: */SwiftValueLayout.SWIFT_INT + ); + private static final MethodHandle HANDLE = SwiftRuntime.upcallHandle(Function.class, "apply", DESC); + private static MemorySegment toUpcallStub(Function fi, Arena arena) { + return Linker.nativeLinker().upcallStub(HANDLE.bindTo(fi), DESC, arena); + } + } // printFunctionPointerParameterDescriptorClass(_:_:_:impl:) @ JExtractSwiftLib/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift:223 + } // printJavaBindingDescriptorClass(_:_:symbolLookup:additionalContent:) @ JExtractSwiftLib/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift:65 + public static class withUnsafeBytes { + @FunctionalInterface + public interface body { + void apply(java.lang.foreign.MemorySegment _0); + } + private static MemorySegment $toUpcallStub(body fi, Arena arena) { + return swiftjava_SwiftRuntimeFunctions_Data_withUnsafeBytes__.$body.toUpcallStub((_0_pointer, _0_count) -> { + fi.apply(_0_pointer.reinterpret(_0_count)); + }, arena); + } // printJavaBindingWrapperFunctionTypeHelper(_:_:_:) @ JExtractSwiftLib/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift:327 + } // printJavaBindingWrapperHelperClass(_:_:) @ JExtractSwiftLib/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift:280 + /** + * Downcall to Swift: + * {@snippet lang=swift : + * public func withUnsafeBytes(_ body: (UnsafeRawBufferPointer) -> Void) + * } + */ + public void withUnsafeBytes(withUnsafeBytes.body body) { + $ensureAlive(); + try(var arena$ = Arena.ofConfined()) { + swiftjava_SwiftRuntimeFunctions_Data_withUnsafeBytes__.call(withUnsafeBytes.$toUpcallStub(body, arena$), this.$memorySegment()); + } + } // printJavaBindingWrapperMethod(_:_:) @ JExtractSwiftLib/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift:403 + + // ==== -------------------------------------------------- + // Data helper methods + + /** + * Creates a new Swift {@link Data} instance from a byte array. + * + * @param bytes The byte array to copy into the Data + * @param arena The arena for memory management + * @return A new Data instance containing a copy of the bytes + */ + public static Data fromByteArray(byte[] bytes, AllocatingSwiftArena arena) { + Objects.requireNonNull(bytes, "bytes cannot be null"); + return Data.init(bytes, arena); + } + /** + * {@snippet lang=c : + * void swiftjava_SwiftRuntimeFunctions_Data_copyBytes__(void *const self, void *destination, ptrdiff_t count) + * } + */ + private static class swiftjava_SwiftRuntimeFunctions_Data_copyBytes__ { + private static final FunctionDescriptor DESC = FunctionDescriptor.ofVoid( + /* self: */SwiftValueLayout.SWIFT_POINTER, + /* destination: */SwiftValueLayout.SWIFT_POINTER, + /* count: */SwiftValueLayout.SWIFT_INT + ); + private static final MemorySegment ADDR = + SwiftRuntimeFunctions.findOrThrow("swiftjava_SwiftRuntimeFunctions_Data_copyBytes__"); + private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); + public static void call(java.lang.foreign.MemorySegment self, java.lang.foreign.MemorySegment destination, long count) { + try { + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(self, destination, count); + } + HANDLE.invokeExact(self, destination, count); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + } // printJavaBindingDescriptorClass(_:_:symbolLookup:additionalContent:) @ JExtractSwiftLib/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift:65 + /** + * Copies the contents of this Data to a new {@link MemorySegment}. + * + * This is the most efficient way to access Data bytes from Java when you don't + * need a {@code byte[]}. The returned segment is valid for the lifetime of the arena. + * + *

Copy count: 1 (Swift Data -> MemorySegment) + * + * @param arena The arena to allocate the segment in + * @return A MemorySegment containing a copy of this Data's bytes + */ + public MemorySegment toMemorySegment(AllocatingSwiftArena arena) { + $ensureAlive(); + long count = getCount(); + if (count == 0) return MemorySegment.NULL; + MemorySegment segment = arena.allocate(count); + swiftjava_SwiftRuntimeFunctions_Data_copyBytes__.call(this.$memorySegment(), segment, count); + return segment; + } + /** + * Copies the contents of this Data to a new {@link ByteBuffer}. + * + * The returned {@link java.nio.ByteBuffer} is a view over native memory and is valid for the + * lifetime of the arena. This avoids an additional copy to the Java heap. + * + *

Copy count: 1 (Swift Data -> native memory (managed by passed arena), then zero-copy view) + * + * @param arena The arena to allocate the underlying memory in + * @return A ByteBuffer view of the copied bytes + */ + public java.nio.ByteBuffer toByteBuffer(AllocatingSwiftArena arena) { + $ensureAlive(); + long count = getCount(); + if (count == 0) return java.nio.ByteBuffer.allocate(0); + MemorySegment segment = arena.allocate(count); + swiftjava_SwiftRuntimeFunctions_Data_copyBytes__.call(this.$memorySegment(), segment, count); + return segment.asByteBuffer(); + } + /** + * Copies the contents of this Data to a new byte array. + * The lifetime of the array is independent of the arena, the arena is just used for an intermediary copy. + * + *

Copy count: 2 (Swift Data -> MemorySegment -> byte[]) + * + *

For better performance when you can work with {@link MemorySegment} or + * {@link java.nio.ByteBuffer}, prefer {@link #toMemorySegment} or {@link #toByteBuffer}. + * + * @param arena The arena to use for temporary native memory allocation + * @return A byte array containing a copy of this Data's bytes + */ + public byte[] toByteArray(AllocatingSwiftArena arena) { + $ensureAlive(); + long count = getCount(); + if (count == 0) return new byte[0]; + MemorySegment segment = arena.allocate(count); + swiftjava_SwiftRuntimeFunctions_Data_copyBytes__.call(this.$memorySegment(), segment, count); + return segment.toArray(ValueLayout.JAVA_BYTE); + } + /** + * Copies the contents of this Data to a new byte array. + * The lifetime of the array is independent of the arena, the arena is just used for an intermediary copy. + * + * This is a convenience method that creates a temporary arena for the copy. + * For repeated calls, prefer {@link #toByteArray(AllocatingSwiftArena)} to reuse an arena. + * + *

Copy count: 2 (Swift Data -> MemorySegment -> byte[]) + * + *

For better performance when you can work with {@link MemorySegment} or + * {@link java.nio.ByteBuffer}, prefer {@link #toMemorySegment} or {@link #toByteBuffer}. + * + * @return A byte array containing a copy of this Data's bytes + */ + public byte[] toByteArray() { + $ensureAlive(); + long count = getCount(); + if (count == 0) return new byte[0]; + try (var arena = Arena.ofConfined()) { + MemorySegment segment = arena.allocate(count); + swiftjava_SwiftRuntimeFunctions_Data_copyBytes__.call(this.$memorySegment(), segment, count); + return segment.toArray(ValueLayout.JAVA_BYTE); + } + } + @Override + public String toString() { + return getClass().getSimpleName() + + "(" + + SwiftRuntime.nameOfSwiftType($swiftType().$memorySegment(), true) + + ")@" + + $memorySegment(); + } +} // printNominal(_:_:body:) @ JExtractSwiftLib/FFMSwift2JavaGenerator.swift:395 diff --git a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/foundation/DataProtocol.java b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/foundation/DataProtocol.java new file mode 100644 index 000000000..8d16ef379 --- /dev/null +++ b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/foundation/DataProtocol.java @@ -0,0 +1,64 @@ +// Generated by jextract-swift +// Swift module: SwiftRuntimeFunctions + +package org.swift.swiftkit.ffm.foundation; + +import org.swift.swiftkit.core.*; +import org.swift.swiftkit.core.util.*; +import org.swift.swiftkit.ffm.*; +import org.swift.swiftkit.ffm.generated.*; +import org.swift.swiftkit.core.annotations.*; +import java.lang.foreign.*; +import java.lang.invoke.*; +import java.util.*; +import java.nio.charset.StandardCharsets; + +public final class DataProtocol extends FFMSwiftInstance implements SwiftValue { + static final String LIB_NAME = "SwiftRuntimeFunctions"; + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + @SuppressWarnings("unused") + private static final boolean INITIALIZED_LIBS = initializeLibs(); + static boolean initializeLibs() { + SwiftLibraries.loadLibraryWithFallbacks(SwiftLibraries.LIB_NAME_SWIFT_CORE); + SwiftLibraries.loadLibraryWithFallbacks(SwiftLibraries.LIB_NAME_SWIFT_JAVA); + SwiftLibraries.loadLibraryWithFallbacks(SwiftLibraries.LIB_NAME_SWIFT_RUNTIME_FUNCTIONS); + SwiftLibraries.loadLibraryWithFallbacks(LIB_NAME); + return true; + } + + public static final SwiftAnyType TYPE_METADATA = + new SwiftAnyType(SwiftRuntime.swiftjava.getType("SwiftRuntimeFunctions", "DataProtocol")); + public final SwiftAnyType $swiftType() { + return TYPE_METADATA; + } + + public static final GroupLayout $LAYOUT = (GroupLayout) SwiftValueWitnessTable.layoutOfSwiftType(TYPE_METADATA.$memorySegment()); + public final GroupLayout $layout() { + return $LAYOUT; + } + + private DataProtocol(MemorySegment segment, AllocatingSwiftArena arena) { + super(segment, arena); + } + + /** + * Assume that the passed {@code MemorySegment} represents a memory address of a {@link DataProtocol}. + *

+ * Warnings: + *

    + *
  • No checks are performed about the compatibility of the pointed at memory and the actual DataProtocol types.
  • + *
  • This operation does not copy, or retain, the pointed at pointer, so its lifetime must be ensured manually to be valid when wrapping.
  • + *
+ */ + public static DataProtocol wrapMemoryAddressUnsafe(MemorySegment selfPointer, AllocatingSwiftArena arena) { + return new DataProtocol(selfPointer, arena); + } + @Override + public String toString() { + return getClass().getSimpleName() + + "(" + + SwiftRuntime.nameOfSwiftType($swiftType().$memorySegment(), true) + + ")@" + + $memorySegment(); + } +} // printNominal(_:_:body:) @ JExtractSwiftLib/FFMSwift2JavaGenerator.swift:395 diff --git a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/generated/SwiftJavaErrorException.java b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/generated/SwiftJavaErrorException.java index ce276caa7..aff2eccee 100644 --- a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/generated/SwiftJavaErrorException.java +++ b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/generated/SwiftJavaErrorException.java @@ -127,4 +127,4 @@ private static String fetchDescription(MemorySegment errorPointer) { return "Swift error (address: 0x" + Long.toHexString(errorPointer.address()) + ")"; } } -} // printNominal(_:_:body:) @ JExtractSwiftLib/FFMSwift2JavaGenerator.swift:385 +} // printNominal(_:_:body:) @ JExtractSwiftLib/FFMSwift2JavaGenerator.swift:395 diff --git a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/generated/SwiftRuntimeFunctions.java b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/generated/SwiftRuntimeFunctions.java index ec27f2a29..ff7765dfb 100644 --- a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/generated/SwiftRuntimeFunctions.java +++ b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/generated/SwiftRuntimeFunctions.java @@ -17,14 +17,14 @@ public final class SwiftRuntimeFunctions { private SwiftRuntimeFunctions() { // Should not be called directly } - + // Static enum to force initialization private static enum Initializer { FORCE; // Refer to this to force outer Class initialization (and static{} blocks to trigger) } static final String LIB_NAME = "SwiftRuntimeFunctions"; static final Arena LIBRARY_ARENA = Arena.ofAuto(); - static MemorySegment findOrThrow(String symbol) { + public static MemorySegment findOrThrow(String symbol) { return SYMBOL_LOOKUP.find(symbol) .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: %s".formatted(symbol))); } @@ -49,7 +49,7 @@ private static SymbolLookup getSymbolLookup() { SwiftLibraries.loadLibraryWithFallbacks(SwiftLibraries.LIB_NAME_SWIFT_RUNTIME_FUNCTIONS); SwiftLibraries.loadLibraryWithFallbacks(LIB_NAME); } - + if (PlatformUtils.isMacOS()) { return SymbolLookup.libraryLookup(System.mapLibraryName(LIB_NAME), LIBRARY_ARENA) .or(SymbolLookup.loaderLookup()) diff --git a/Tests/JExtractSwiftTests/DataImportTests.swift b/Tests/JExtractSwiftTests/DataImportTests.swift index e67a3db87..42149c5ee 100644 --- a/Tests/JExtractSwiftTests/DataImportTests.swift +++ b/Tests/JExtractSwiftTests/DataImportTests.swift @@ -95,36 +95,6 @@ final class DataImportTests { _result.assumingMemoryBound(to: Data.self).initialize(to: returnData()) } """, - - """ - @_cdecl("swiftjava_getType_SwiftModule_Data") - public func swiftjava_getType_SwiftModule_Data() -> UnsafeMutableRawPointer /* Any.Type */ { - return unsafeBitCast(Data.self, to: UnsafeMutableRawPointer.self) - } - """, - - """ - @_cdecl("swiftjava_SwiftModule_Data_init_bytes_count") - public func swiftjava_SwiftModule_Data_init_bytes_count(_ bytes: UnsafeRawPointer, _ count: Int, _ _result: UnsafeMutableRawPointer) { - _result.assumingMemoryBound(to: Data.self).initialize(to: Data(bytes: bytes, count: count)) - } - """, - - """ - @_cdecl("swiftjava_SwiftModule_Data_count$get") - public func swiftjava_SwiftModule_Data_count$get(_ self: UnsafeRawPointer) -> Int { - return self.assumingMemoryBound(to: Data.self).pointee.count - } - """, - - """ - @_cdecl("swiftjava_SwiftModule_Data_withUnsafeBytes__") - public func swiftjava_SwiftModule_Data_withUnsafeBytes__(_ body: @convention(c) (UnsafeRawPointer?, Int) -> Void, _ self: UnsafeRawPointer) { - self.assumingMemoryBound(to: Data.self).pointee.withUnsafeBytes({ (_0) in - return body(_0.baseAddress, _0.count) - }) - } - """, ] ) } @@ -174,7 +144,7 @@ final class DataImportTests { * public func receiveData(dat: Data) * } */ - public static void receiveData(Data dat) { + public static void receiveData(org.swift.swiftkit.ffm.foundation.Data dat) { swiftjava_SwiftModule_receiveData_dat.call(dat.$memorySegment()); } """, @@ -212,178 +182,10 @@ final class DataImportTests { * public func returnData() -> Data * } */ - public static Data returnData(AllocatingSwiftArena swiftArena) { - MemorySegment result$ = swiftArena.allocate(Data.$LAYOUT); + public static org.swift.swiftkit.ffm.foundation.Data returnData(AllocatingSwiftArena swiftArena) { + MemorySegment result$ = swiftArena.allocate(org.swift.swiftkit.ffm.foundation.Data.$LAYOUT); swiftjava_SwiftModule_returnData.call(result$); - return Data.wrapMemoryAddressUnsafe(result$, swiftArena); - } - """, - - """ - /** - * {@snippet lang=c : - * void swiftjava_SwiftModule_Data_init_bytes_count(const void *bytes, ptrdiff_t count, void *_result) - * } - */ - private static class swiftjava_SwiftModule_Data_init_bytes_count { - private static final FunctionDescriptor DESC = FunctionDescriptor.ofVoid( - /* bytes: */SwiftValueLayout.SWIFT_POINTER, - /* count: */SwiftValueLayout.SWIFT_INT, - /* _result: */SwiftValueLayout.SWIFT_POINTER - ); - private static final MemorySegment ADDR = - SwiftModule.findOrThrow("swiftjava_SwiftModule_Data_init_bytes_count"); - private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); - public static void call(java.lang.foreign.MemorySegment bytes, long count, java.lang.foreign.MemorySegment _result) { - try { - if (CallTraces.TRACE_DOWNCALLS) { - CallTraces.traceDowncall(bytes, count, _result); - } - HANDLE.invokeExact(bytes, count, _result); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - } - """, - - """ - /** - * Downcall to Swift: - * {@snippet lang=swift : - * public init(bytes: UnsafeRawPointer, count: Int) - * } - */ - public static Data init(java.lang.foreign.MemorySegment bytes, long count, AllocatingSwiftArena swiftArena) throws SwiftIntegerOverflowException { - MemorySegment result$ = swiftArena.allocate(Data.$LAYOUT); - if (SwiftValueLayout.has32bitSwiftInt) { - if (count < Integer.MIN_VALUE || count > Integer.MAX_VALUE) { - throw new SwiftIntegerOverflowException("Parameter 'count' overflow: " + count); - } - } - swiftjava_SwiftModule_Data_init_bytes_count.call(bytes, count, result$); - return Data.wrapMemoryAddressUnsafe(result$, swiftArena); - } - """, - - """ - /** - * {@snippet lang=c : - * ptrdiff_t swiftjava_SwiftModule_Data_count$get(const void *self) - * } - */ - private static class swiftjava_SwiftModule_Data_count$get { - private static final FunctionDescriptor DESC = FunctionDescriptor.of( - /* -> */SwiftValueLayout.SWIFT_INT, - /* self: */SwiftValueLayout.SWIFT_POINTER - ); - private static final MemorySegment ADDR = - SwiftModule.findOrThrow("swiftjava_SwiftModule_Data_count$get"); - private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); - public static long call(java.lang.foreign.MemorySegment self) { - try { - if (CallTraces.TRACE_DOWNCALLS) { - CallTraces.traceDowncall(self); - } - return (long) HANDLE.invokeExact(self); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - } - """, - - """ - /** - * Downcall to Swift: - * {@snippet lang=swift : - * public var count: Int - * } - */ - public long getCount() throws SwiftIntegerOverflowException { - $ensureAlive(); - long result$checked = swiftjava_SwiftModule_Data_count$get.call(this.$memorySegment()); - if (SwiftValueLayout.has32bitSwiftInt) { - if (result$checked < Integer.MIN_VALUE || result$checked > Integer.MAX_VALUE) { - throw new SwiftIntegerOverflowException("Return value overflow: " + result$checked); - } - } - return result$checked; - } - """, - - """ - /** - * {@snippet lang=c : - * void swiftjava_SwiftModule_Data_withUnsafeBytes__(void (*body)(const void *, ptrdiff_t), const void *self) - * } - */ - private static class swiftjava_SwiftModule_Data_withUnsafeBytes__ { - private static final FunctionDescriptor DESC = FunctionDescriptor.ofVoid( - /* body: */SwiftValueLayout.SWIFT_POINTER, - /* self: */SwiftValueLayout.SWIFT_POINTER - ); - private static final MemorySegment ADDR = - SwiftModule.findOrThrow("swiftjava_SwiftModule_Data_withUnsafeBytes__"); - private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); - public static void call(java.lang.foreign.MemorySegment body, java.lang.foreign.MemorySegment self) { - try { - if (CallTraces.TRACE_DOWNCALLS) { - CallTraces.traceDowncall(body, self); - } - HANDLE.invokeExact(body, self); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - /** - * {snippet lang=c : - * void (*)(const void *, ptrdiff_t) - * } - */ - private static class $body { - @FunctionalInterface - public interface Function { - void apply(java.lang.foreign.MemorySegment _0, long _1); - } - private static final FunctionDescriptor DESC = FunctionDescriptor.ofVoid( - /* _0: */SwiftValueLayout.SWIFT_POINTER, - /* _1: */SwiftValueLayout.SWIFT_INT - ); - private static final MethodHandle HANDLE = SwiftRuntime.upcallHandle(Function.class, "apply", DESC); - private static MemorySegment toUpcallStub(Function fi, Arena arena) { - return Linker.nativeLinker().upcallStub(HANDLE.bindTo(fi), DESC, arena); - } - } - } - """, - - """ - public static class withUnsafeBytes { - @FunctionalInterface - public interface body { - void apply(java.lang.foreign.MemorySegment _0); - } - private static MemorySegment $toUpcallStub(body fi, Arena arena) { - return swiftjava_SwiftModule_Data_withUnsafeBytes__.$body.toUpcallStub((_0_pointer, _0_count) -> { - fi.apply(_0_pointer.reinterpret(_0_count)); - }, arena); - } - } - """, - - """ - /** - * Downcall to Swift: - * {@snippet lang=swift : - * public func withUnsafeBytes(_ body: (UnsafeRawBufferPointer) -> Void) - * } - */ - public void withUnsafeBytes(withUnsafeBytes.body body) { - $ensureAlive(); - try(var arena$ = Arena.ofConfined()) { - swiftjava_SwiftModule_Data_withUnsafeBytes__.call(withUnsafeBytes.$toUpcallStub(body, arena$), this.$memorySegment()); - } + return org.swift.swiftkit.ffm.foundation.Data.wrapMemoryAddressUnsafe(result$, swiftArena); } """, ] @@ -413,11 +215,6 @@ final class DataImportTests { receiveDataProtocol(dat: dat.assumingMemoryBound(to: Data.self).pointee, dat2: dat2?.assumingMemoryBound(to: Data.self).pointee) } """, - - // Just to make sure 'Data' is imported. - """ - @_cdecl("swiftjava_getType_SwiftModule_Data") - """, ] ) } @@ -470,15 +267,10 @@ final class DataImportTests { * public func receiveDataProtocol(dat: some DataProtocol, dat2: T?) * } */ - public static void receiveDataProtocol(Data dat, Optional dat2) { + public static void receiveDataProtocol(org.swift.swiftkit.ffm.foundation.Data dat, java.util.Optional dat2) { swiftjava_SwiftModule_receiveDataProtocol_dat_dat2.call(dat.$memorySegment(), SwiftRuntime.toOptionalSegmentInstance(dat2)); } """, - - // Just to make sure 'Data' is imported. - """ - public final class Data extends FFMSwiftInstance implements SwiftValue { - """, ] ) } @@ -499,7 +291,7 @@ final class DataImportTests { detectChunkByInitialLines: 1, expectedChunks: [ """ - public static void acceptData(Data data) { + public static void acceptData(org.swift.swiftkit.core.foundation.Data data) { SwiftModule.$acceptData(data.$memoryAddress()); } """ @@ -533,7 +325,7 @@ final class DataImportTests { .java, expectedChunks: [ """ - public static Data returnData(SwiftArena swiftArena) { + public static org.swift.swiftkit.core.foundation.Data returnData(SwiftArena swiftArena) { """ ] ) @@ -551,33 +343,6 @@ final class DataImportTests { ) } - @Test("Import Data: JNI Data class") - func data_jni_class() throws { - let text = """ - import Foundation - public func f() -> Data - """ - - try assertOutput( - input: text, - .jni, - .java, - detectChunkByInitialLines: 1, - expectedChunks: [ - "public final class Data implements JNISwiftInstance, DataProtocol {", - "public long getCount() {", - - "public static Data fromByteArray(byte[] bytes, SwiftArena swiftArena) {", - - "public byte[] toByteArray() {", - "private static native byte[] $toByteArray(long selfPointer);", - - "public byte[] toByteArrayIndirectCopy() {", - "private static native byte[] $toByteArrayIndirectCopy(long selfPointer);", - ] - ) - } - // ==== ----------------------------------------------------------------------- // MARK: JNI DataProtocol generic parameter @@ -599,7 +364,7 @@ final class DataImportTests { detectChunkByInitialLines: 2, expectedChunks: [ """ - public static MyResult processData(D data, SwiftArena swiftArena) { + public static MyResult processData(D data, SwiftArena swiftArena) { """ ] ) @@ -620,7 +385,7 @@ final class DataImportTests { detectChunkByInitialLines: 2, expectedChunks: [ """ - public static boolean verify(D1 first, D2 second) { + public static boolean verify(D1 first, D2 second) { """ ] ) diff --git a/Tests/JExtractSwiftTests/DateTests.swift b/Tests/JExtractSwiftTests/DateTests.swift index bf5e9ef8e..7e694640c 100644 --- a/Tests/JExtractSwiftTests/DateTests.swift +++ b/Tests/JExtractSwiftTests/DateTests.swift @@ -17,34 +17,8 @@ import SwiftJavaConfigurationShared import Testing struct DateTests { - @Test( - "Import: accept Date", - arguments: [ - ( - JExtractGenerationMode.jni, - /* expected Java chunks */ - [ - """ - public static void acceptDate(Date date) { - SwiftModule.$acceptDate(date.$memoryAddress()); - } - """ - ], - /* expected Swift chunks */ - [ - """ - @_cdecl("Java_com_example_swift_SwiftModule__00024acceptDate__J") - public func Java_com_example_swift_SwiftModule__00024acceptDate__J(environment: UnsafeMutablePointer!, thisClass: jclass, date: jlong) { - """ - ], - ) - ] - ) - func func_accept_date( - mode: JExtractGenerationMode, - expectedJavaChunks: [String], - expectedSwiftChunks: [String] - ) throws { + @Test("Import: accept Date") + func func_accept_date() throws { let text = """ import Foundation @@ -54,47 +28,34 @@ struct DateTests { try assertOutput( input: text, - mode, + .jni, .java, detectChunkByInitialLines: 1, - expectedChunks: expectedJavaChunks + expectedChunks: [ + """ + public static void acceptDate(org.swift.swiftkit.core.foundation.Date date) { + SwiftModule.$acceptDate(date.$memoryAddress()); + } + """ + ] ) try assertOutput( input: text, - mode, + .jni, .swift, detectChunkByInitialLines: 1, - expectedChunks: expectedSwiftChunks + expectedChunks: [ + """ + @_cdecl("Java_com_example_swift_SwiftModule__00024acceptDate__J") + public func Java_com_example_swift_SwiftModule__00024acceptDate__J(environment: UnsafeMutablePointer!, thisClass: jclass, date: jlong) { + """ + ] ) } - @Test( - "Import: return Date", - arguments: [ - ( - JExtractGenerationMode.jni, - /* expected Java chunks */ - [ - """ - public static Date returnDate(SwiftArena swiftArena) { - """ - ], - /* expected Swift chunks */ - [ - """ - @_cdecl("Java_com_example_swift_SwiftModule__00024returnDate__") - public func Java_com_example_swift_SwiftModule__00024returnDate__(environment: UnsafeMutablePointer!, thisClass: jclass) -> jlong { - """ - ] - ) - ] - ) - func func_return_Date( - mode: JExtractGenerationMode, - expectedJavaChunks: [String], - expectedSwiftChunks: [String] - ) throws { + @Test("Import: return Date") + func func_return_Date() throws { let text = """ import Foundation @@ -103,75 +64,25 @@ struct DateTests { try assertOutput( input: text, - mode, + .jni, .java, - expectedChunks: expectedJavaChunks + expectedChunks: [ + """ + public static org.swift.swiftkit.core.foundation.Date returnDate(SwiftArena swiftArena) { + """ + ], ) try assertOutput( input: text, - mode, + .jni, .swift, - expectedChunks: expectedSwiftChunks - ) - } - - @Test( - "Import: Date type", - arguments: [ - ( - JExtractGenerationMode.jni, - /* expected Java chunks */ - [ - """ - public final class Date implements JNISwiftInstance { - """, - """ - public static Date init(double timeIntervalSince1970, SwiftArena swiftArena) { - """, - """ - public double getTimeIntervalSince1970() { - """, - """ - public static Date fromInstant(java.time.Instant instant, SwiftArena swiftArena) { - """, - """ - public java.time.Instant toInstant() { - """, - ], - /* expected Swift chunks */ - [ - """ - @_cdecl("Java_com_example_swift_Date__00024init__D") - public func Java_com_example_swift_Date__00024init__D(environment: UnsafeMutablePointer!, thisClass: jclass, timeIntervalSince1970: jdouble) -> jlong { - """, - """ - @_cdecl("Java_com_example_swift_Date__00024getTimeIntervalSince1970__J") - public func Java_com_example_swift_Date__00024getTimeIntervalSince1970__J(environment: UnsafeMutablePointer!, thisClass: jclass, selfPointer: jlong) -> jdouble { - """, - ] - ) - ] - ) - func date_class(mode: JExtractGenerationMode, expectedJavaChunks: [String], expectedSwiftChunks: [String]) throws { - let text = - """ - import Foundation - public func f() -> Date - """ - - try assertOutput( - input: text, - mode, - .java, - expectedChunks: expectedJavaChunks - ) - - try assertOutput( - input: text, - mode, - .swift, - expectedChunks: expectedSwiftChunks + expectedChunks: [ + """ + @_cdecl("Java_com_example_swift_SwiftModule__00024returnDate__") + public func Java_com_example_swift_SwiftModule__00024returnDate__(environment: UnsafeMutablePointer!, thisClass: jclass) -> jlong { + """ + ] ) } } diff --git a/Tests/JExtractSwiftTests/JNI/JNIDictionaryTest.swift b/Tests/JExtractSwiftTests/JNI/JNIDictionaryTest.swift index 0690ee01d..ebb8ed163 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIDictionaryTest.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIDictionaryTest.swift @@ -28,7 +28,7 @@ struct JNIDictionaryTest { expectedChunks: [ """ public static org.swift.swiftkit.core.collections.SwiftDictionaryMap f(SwiftArena swiftArena) { - return SwiftDictionaryMap.wrapMemoryAddressUnsafe(SwiftModule.$f(), swiftArena); + return org.swift.swiftkit.core.collections.SwiftDictionaryMap.wrapMemoryAddressUnsafe(SwiftModule.$f(), swiftArena); } """, """ @@ -104,7 +104,7 @@ struct JNIDictionaryTest { expectedChunks: [ """ public static org.swift.swiftkit.core.collections.SwiftDictionaryMap f(org.swift.swiftkit.core.collections.SwiftDictionaryMap dict, SwiftArena swiftArena) { - return SwiftDictionaryMap.wrapMemoryAddressUnsafe(SwiftModule.$f(Objects.requireNonNull(dict, "dict must not be null").$memoryAddress()), swiftArena); + return org.swift.swiftkit.core.collections.SwiftDictionaryMap.wrapMemoryAddressUnsafe(SwiftModule.$f(Objects.requireNonNull(dict, "dict must not be null").$memoryAddress()), swiftArena); } """, """ @@ -142,7 +142,7 @@ struct JNIDictionaryTest { expectedChunks: [ """ public static org.swift.swiftkit.core.collections.SwiftDictionaryMap f(org.swift.swiftkit.core.collections.SwiftDictionaryMap dict, SwiftArena swiftArena) { - return SwiftDictionaryMap.wrapMemoryAddressUnsafe(SwiftModule.$f(Objects.requireNonNull(dict, "dict must not be null").$memoryAddress()), swiftArena); + return org.swift.swiftkit.core.collections.SwiftDictionaryMap.wrapMemoryAddressUnsafe(SwiftModule.$f(Objects.requireNonNull(dict, "dict must not be null").$memoryAddress()), swiftArena); } """, """ @@ -183,7 +183,7 @@ struct JNIDictionaryTest { expectedChunks: [ """ public static org.swift.swiftkit.core.collections.SwiftDictionaryMap f(SwiftArena swiftArena) { - return SwiftDictionaryMap.wrapMemoryAddressUnsafe(SwiftModule.$f(), swiftArena); + return org.swift.swiftkit.core.collections.SwiftDictionaryMap.wrapMemoryAddressUnsafe(SwiftModule.$f(), swiftArena); } """ ] @@ -200,7 +200,7 @@ struct JNIDictionaryTest { expectedChunks: [ """ public static org.swift.swiftkit.core.collections.SwiftDictionaryMap f(SwiftArena swiftArena) { - return SwiftDictionaryMap.wrapMemoryAddressUnsafe(SwiftModule.$f(), swiftArena); + return org.swift.swiftkit.core.collections.SwiftDictionaryMap.wrapMemoryAddressUnsafe(SwiftModule.$f(), swiftArena); } """ ] @@ -217,7 +217,7 @@ struct JNIDictionaryTest { expectedChunks: [ """ public static org.swift.swiftkit.core.collections.SwiftDictionaryMap f(SwiftArena swiftArena) { - return SwiftDictionaryMap.wrapMemoryAddressUnsafe(SwiftModule.$f(), swiftArena); + return org.swift.swiftkit.core.collections.SwiftDictionaryMap.wrapMemoryAddressUnsafe(SwiftModule.$f(), swiftArena); } """ ] @@ -234,7 +234,7 @@ struct JNIDictionaryTest { expectedChunks: [ """ public static org.swift.swiftkit.core.collections.SwiftDictionaryMap f(SwiftArena swiftArena) { - return SwiftDictionaryMap.wrapMemoryAddressUnsafe(SwiftModule.$f(), swiftArena); + return org.swift.swiftkit.core.collections.SwiftDictionaryMap.wrapMemoryAddressUnsafe(SwiftModule.$f(), swiftArena); } """ ] @@ -295,7 +295,7 @@ struct JNIDictionaryTest { expectedChunks: [ """ public static org.swift.swiftkit.core.collections.SwiftDictionaryMap f(org.swift.swiftkit.core.collections.SwiftDictionaryMap dict, java.lang.String key, long value, SwiftArena swiftArena) { - return SwiftDictionaryMap.wrapMemoryAddressUnsafe(SwiftModule.$f(Objects.requireNonNull(dict, "dict must not be null").$memoryAddress(), key, value), swiftArena); + return org.swift.swiftkit.core.collections.SwiftDictionaryMap.wrapMemoryAddressUnsafe(SwiftModule.$f(Objects.requireNonNull(dict, "dict must not be null").$memoryAddress(), key, value), swiftArena); } """, """ diff --git a/Tests/JExtractSwiftTests/JNI/JNIEnumTests.swift b/Tests/JExtractSwiftTests/JNI/JNIEnumTests.swift index e09c215ca..0f3db0ca0 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIEnumTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIEnumTests.swift @@ -268,7 +268,7 @@ struct JNIEnumTests { detectChunkByInitialLines: 1, expectedChunks: [ """ - public Optional getAsFirst() { + public java.util.Optional getAsFirst() { if (getDiscriminator() != Discriminator.FIRST) { return Optional.empty(); } @@ -276,7 +276,7 @@ struct JNIEnumTests { } """, """ - public Optional getAsSecond() { + public java.util.Optional getAsSecond() { if (getDiscriminator() != Discriminator.SECOND) { return Optional.empty(); } @@ -285,7 +285,7 @@ struct JNIEnumTests { } """, """ - public Optional getAsThird() { + public java.util.Optional getAsThird() { if (getDiscriminator() != Discriminator.THIRD) { return Optional.empty(); } diff --git a/Tests/JExtractSwiftTests/JNI/JNIGenericCombinationTests.swift b/Tests/JExtractSwiftTests/JNI/JNIGenericCombinationTests.swift index 57651e1e1..45b4cb2ec 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIGenericCombinationTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIGenericCombinationTests.swift @@ -55,7 +55,7 @@ struct JNIGenericCombinationTests { detectChunkByInitialLines: 2, expectedChunks: [ """ - public static Optional> makeStringIDOptional(java.lang.String value, SwiftArena swiftArena) { + public static java.util.Optional> makeStringIDOptional(java.lang.String value, SwiftArena swiftArena) { byte[] result$_discriminator$ = new byte[1]; org.swift.swiftkit.core._OutSwiftGenericInstance resultWrapped$ = new org.swift.swiftkit.core._OutSwiftGenericInstance(); SwiftModule.$makeStringIDOptional(value, result$_discriminator$, resultWrapped$); @@ -113,7 +113,7 @@ struct JNIGenericCombinationTests { detectChunkByInitialLines: 2, expectedChunks: [ """ - public static void takeStringIDOptional(Optional> value) { + public static void takeStringIDOptional(java.util.Optional> value) { SwiftModule.$takeStringIDOptional(value.map(MyID::$memoryAddress).orElse(0L)); } """, diff --git a/Tests/JExtractSwiftTests/JNI/JNIOptionalTests.swift b/Tests/JExtractSwiftTests/JNI/JNIOptionalTests.swift index 728165bf8..d01c4b103 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIOptionalTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIOptionalTests.swift @@ -155,7 +155,7 @@ struct JNIOptionalTests { * public func optionalClass(_ arg: MyClass?) -> MyClass? * } */ - public static Optional optionalClass(Optional arg, SwiftArena swiftArena) { + public static java.util.Optional optionalClass(java.util.Optional arg, SwiftArena swiftArena) { byte[] result$_discriminator$ = new byte[1]; long result$ = SwiftModule.$optionalClass(arg.map(MyClass::$memoryAddress).orElse(0L), result$_discriminator$); return (result$_discriminator$[0] == 1) ? Optional.of(MyClass.wrapMemoryAddressUnsafe(result$, swiftArena)) : Optional.empty(); diff --git a/Tests/JExtractSwiftTests/JNI/JNISetTest.swift b/Tests/JExtractSwiftTests/JNI/JNISetTest.swift index e654344d2..8adec8d58 100644 --- a/Tests/JExtractSwiftTests/JNI/JNISetTest.swift +++ b/Tests/JExtractSwiftTests/JNI/JNISetTest.swift @@ -28,7 +28,7 @@ struct JNISetTest { expectedChunks: [ """ public static org.swift.swiftkit.core.collections.SwiftSet f(SwiftArena swiftArena) { - return SwiftSet.wrapMemoryAddressUnsafe(SwiftModule.$f(), swiftArena); + return org.swift.swiftkit.core.collections.SwiftSet.wrapMemoryAddressUnsafe(SwiftModule.$f(), swiftArena); } """, """ @@ -104,7 +104,7 @@ struct JNISetTest { expectedChunks: [ """ public static org.swift.swiftkit.core.collections.SwiftSet f(org.swift.swiftkit.core.collections.SwiftSet set, SwiftArena swiftArena) { - return SwiftSet.wrapMemoryAddressUnsafe(SwiftModule.$f(Objects.requireNonNull(set, "set must not be null").$memoryAddress()), swiftArena); + return org.swift.swiftkit.core.collections.SwiftSet.wrapMemoryAddressUnsafe(SwiftModule.$f(Objects.requireNonNull(set, "set must not be null").$memoryAddress()), swiftArena); } """, """ @@ -145,7 +145,7 @@ struct JNISetTest { expectedChunks: [ """ public static org.swift.swiftkit.core.collections.SwiftSet f(SwiftArena swiftArena) { - return SwiftSet.wrapMemoryAddressUnsafe(SwiftModule.$f(), swiftArena); + return org.swift.swiftkit.core.collections.SwiftSet.wrapMemoryAddressUnsafe(SwiftModule.$f(), swiftArena); } """ ] @@ -162,7 +162,7 @@ struct JNISetTest { expectedChunks: [ """ public static org.swift.swiftkit.core.collections.SwiftSet f(SwiftArena swiftArena) { - return SwiftSet.wrapMemoryAddressUnsafe(SwiftModule.$f(), swiftArena); + return org.swift.swiftkit.core.collections.SwiftSet.wrapMemoryAddressUnsafe(SwiftModule.$f(), swiftArena); } """ ] @@ -179,7 +179,7 @@ struct JNISetTest { expectedChunks: [ """ public static org.swift.swiftkit.core.collections.SwiftSet f(SwiftArena swiftArena) { - return SwiftSet.wrapMemoryAddressUnsafe(SwiftModule.$f(), swiftArena); + return org.swift.swiftkit.core.collections.SwiftSet.wrapMemoryAddressUnsafe(SwiftModule.$f(), swiftArena); } """ ] @@ -240,7 +240,7 @@ struct JNISetTest { expectedChunks: [ """ public static org.swift.swiftkit.core.collections.SwiftSet f(org.swift.swiftkit.core.collections.SwiftSet set, java.lang.String element, SwiftArena swiftArena) { - return SwiftSet.wrapMemoryAddressUnsafe(SwiftModule.$f(Objects.requireNonNull(set, "set must not be null").$memoryAddress(), element), swiftArena); + return org.swift.swiftkit.core.collections.SwiftSet.wrapMemoryAddressUnsafe(SwiftModule.$f(Objects.requireNonNull(set, "set must not be null").$memoryAddress(), element), swiftArena); } """, """ diff --git a/Tests/JExtractSwiftTests/OptionalImportTests.swift b/Tests/JExtractSwiftTests/OptionalImportTests.swift index fc169fe53..60473bd3a 100644 --- a/Tests/JExtractSwiftTests/OptionalImportTests.swift +++ b/Tests/JExtractSwiftTests/OptionalImportTests.swift @@ -146,7 +146,7 @@ final class OptionalImportTests { * public func receiveOptionalDataProto(_ arg: (some DataProtocol)?) * } */ - public static void receiveOptionalDataProto(Optional arg) { + public static void receiveOptionalDataProto(java.util.Optional arg) { swiftjava_SwiftModule_receiveOptionalDataProto__.call(SwiftRuntime.toOptionalSegmentInstance(arg)); } """, diff --git a/Tests/JExtractSwiftTests/SwiftSymbolTableTests.swift b/Tests/JExtractSwiftTests/SwiftSymbolTableTests.swift index bdf00de18..a2b1fc9e3 100644 --- a/Tests/JExtractSwiftTests/SwiftSymbolTableTests.swift +++ b/Tests/JExtractSwiftTests/SwiftSymbolTableTests.swift @@ -52,8 +52,8 @@ struct SwiftSymbolTableSuite { #expect(symbolTable.lookupType("Z", parent: nil) == nil) } - @Test(arguments: [JExtractGenerationMode.jni, .ffm]) - func resolveSelfModuleName(mode: JExtractGenerationMode) throws { + @Test + func resolveSelfModuleName() throws { try assertOutput( input: """ import Foundation @@ -62,13 +62,13 @@ struct SwiftSymbolTableSuite { public func fullyQualifiedType() -> MyModule.MyValue public func fullyQualifiedType2() -> Foundation.Data """, - mode, + .jni, .java, swiftModuleName: "MyModule", detectChunkByInitialLines: 1, expectedChunks: [ "public static MyValue fullyQualifiedType(", - "public static Data fullyQualifiedType2(", + "public static org.swift.swiftkit.core.foundation.Data fullyQualifiedType2(", ], ) } diff --git a/scripts/swiftkit-ffm-generate-bindings.sh b/scripts/swiftkit-ffm-generate-bindings.sh index 9f706a77c..43cb277e9 100755 --- a/scripts/swiftkit-ffm-generate-bindings.sh +++ b/scripts/swiftkit-ffm-generate-bindings.sh @@ -23,15 +23,18 @@ set -euo pipefail REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" JAVA_OUTPUT="${REPO_ROOT}/SwiftKitFFM/src/main/java" -JAVA_PACKAGE="org.swift.swiftkit.ffm.generated" +PACKAGE_GENERATED="org.swift.swiftkit.ffm.generated" +PACKAGE_FOUNDATION="org.swift.swiftkit.ffm.foundation" -# Declare types to generate: SWIFT_MODULE SINGLE_TYPE INPUT_SWIFT_DIR OUTPUT_SWIFT_DIR +# Declare types to generate: SWIFT_MODULE SINGLE_TYPE JAVA_PACKAGE INPUT_SWIFT_DIR OUTPUT_SWIFT_DIR TYPES=( - "SwiftRuntimeFunctions SwiftJavaError Sources/SwiftRuntimeFunctions Sources/SwiftRuntimeFunctions/generated" + "SwiftRuntimeFunctions SwiftJavaError ${PACKAGE_GENERATED} Sources/SwiftRuntimeFunctions Sources/SwiftRuntimeFunctions/generated" + "SwiftRuntimeFunctions Data ${PACKAGE_FOUNDATION} Sources/FakeFoundation Sources/SwiftRuntimeFunctions/foundation" + "SwiftRuntimeFunctions DataProtocol ${PACKAGE_FOUNDATION} Sources/FakeFoundation Sources/SwiftRuntimeFunctions/foundation" ) for entry in "${TYPES[@]}"; do - read -r MODULE SINGLE_TYPE INPUT_SWIFT OUTPUT_SWIFT <<< "$entry" + read -r MODULE SINGLE_TYPE JAVA_PACKAGE INPUT_SWIFT OUTPUT_SWIFT <<< "$entry" echo "==> Generating ${SINGLE_TYPE} (module: ${MODULE})..." diff --git a/scripts/swiftkit-jni-generate-bindings.sh b/scripts/swiftkit-jni-generate-bindings.sh new file mode 100755 index 000000000..285350b64 --- /dev/null +++ b/scripts/swiftkit-jni-generate-bindings.sh @@ -0,0 +1,53 @@ +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift.org open source project +## +## Copyright (c) 2026 Apple Inc. and the Swift.org project authors +## Licensed under Apache License v2.0 +## +## See LICENSE.txt for license information +## See CONTRIBUTORS.txt for the list of Swift.org project authors +## +## SPDX-License-Identifier: Apache-2.0 +## +##===----------------------------------------------------------------------===## + +# Regenerate FFM bindings for types in SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/generated/ +# +# Run from the swift-java repository root: +# ./scripts/swiftkit-ffm-generate-bindings.sh + +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" + +JAVA_OUTPUT="${REPO_ROOT}/SwiftKitCore/src/main/java" +JAVA_PACKAGE="org.swift.swiftkit.core.foundation" + +# Declare types to generate: SWIFT_MODULE SINGLE_TYPE INPUT_SWIFT_DIR OUTPUT_SWIFT_DIR +TYPES=( + "SwiftJava Data Sources/FakeFoundation Sources/SwiftJavaRuntimeSupport/foundation" + "SwiftJava DataProtocol Sources/FakeFoundation Sources/SwiftJavaRuntimeSupport/foundation" + "SwiftJava Date Sources/FakeFoundation Sources/SwiftJavaRuntimeSupport/foundation" +) + +for entry in "${TYPES[@]}"; do + read -r MODULE SINGLE_TYPE INPUT_SWIFT OUTPUT_SWIFT <<< "$entry" + + echo "==> Generating ${INPUT_SWIFT} ${SINGLE_TYPE}..." + + xcrun swift run swift-java jextract \ + --mode jni \ + --single-type "$SINGLE_TYPE" \ + --swift-module "$MODULE" \ + --input-swift "${REPO_ROOT}/${INPUT_SWIFT}" \ + --output-swift "${REPO_ROOT}/${OUTPUT_SWIFT}" \ + --output-java "$JAVA_OUTPUT" \ + --java-package "$JAVA_PACKAGE" + + echo " Swift thunks: ${OUTPUT_SWIFT}/" + echo " Java output: SwiftKitCore/src/main/java/$(echo "$JAVA_PACKAGE" | tr '.' '/')/" +done + +echo "==> Done."