Skip to content

Commit 5019f5d

Browse files
committed
add support for date
1 parent 0685f55 commit 5019f5d

File tree

14 files changed

+364
-60
lines changed

14 files changed

+364
-60
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift.org project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift.org project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#if canImport(FoundationEssentials)
16+
import FoundationEssentials
17+
#else
18+
import Foundation
19+
#endif
20+
import SwiftJava
21+
22+
public func compareDates(date1: Date, date2: Date) -> Bool {
23+
return date1 == date2
24+
}
25+
26+
public func dateFromSeconds(_ seconds: Double) -> Date {
27+
return Date(timeIntervalSince1970: seconds)
28+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift.org project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift.org project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
package com.example.swift;
16+
17+
import org.junit.jupiter.api.Test;
18+
19+
import java.time.Instant;
20+
21+
import static org.junit.jupiter.api.Assertions.*;
22+
23+
public class DateTest {
24+
@Test
25+
void date() {
26+
assertEquals(Instant.ofEpochSecond(1000), MySwiftLibrary.dateFromSeconds(1000.0));
27+
assertEquals(Instant.ofEpochSecond(1000, 500_000_000), MySwiftLibrary.dateFromSeconds(1000.50));
28+
assertTrue(MySwiftLibrary.compareDates(Instant.ofEpochSecond(5000), Instant.ofEpochSecond(5000)));
29+
assertFalse(MySwiftLibrary.compareDates(Instant.ofEpochSecond(4999, 500_000_000), Instant.ofEpochSecond(5000)));
30+
assertTrue(MySwiftLibrary.compareDates(MySwiftLibrary.dateFromSeconds(1000.5), Instant.ofEpochSecond(1000, 500_000_000)));
31+
32+
var date = MySwiftLibrary.dateFromSeconds(50000.5);
33+
assertEquals(50_000, date.getEpochSecond());
34+
assertEquals(500_000_000, date.getNano());
35+
}
36+
}

Sources/JExtractSwiftLib/FFM/CDeclLowering/CRepresentation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ extension SwiftKnownTypeDeclKind {
129129
case .void: .void
130130
case .unsafePointer, .unsafeMutablePointer, .unsafeRawBufferPointer, .unsafeMutableRawBufferPointer,
131131
.unsafeBufferPointer, .unsafeMutableBufferPointer, .string, .foundationData, .foundationDataProtocol,
132-
.essentialsData, .essentialsDataProtocol, .optional:
132+
.essentialsData, .essentialsDataProtocol, .optional, .foundationDate, .essentialsDate:
133133
nil
134134
}
135135
}

Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift

Lines changed: 2 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ extension FFMSwift2JavaGenerator {
111111
112112
""")
113113

114-
printSwiftThunkImports(&printer)
114+
self.lookupContext.symbolTable.printImportedModules(&printer)
115115

116116
for thunk in stt.renderGlobalThunks() {
117117
printer.print(thunk)
@@ -140,67 +140,13 @@ extension FFMSwift2JavaGenerator {
140140
"""
141141
)
142142

143-
printSwiftThunkImports(&printer)
143+
self.lookupContext.symbolTable.printImportedModules(&printer)
144144

145145
for thunk in stt.renderThunks(forType: ty) {
146146
printer.print("\(thunk)")
147147
printer.print("")
148148
}
149149
}
150-
151-
func printSwiftThunkImports(_ printer: inout CodePrinter) {
152-
let mainSymbolSourceModules = Set(
153-
self.lookupContext.symbolTable.importedModules.values.filter { $0.alternativeModules?.isMainSourceOfSymbols ?? false }.map(\.moduleName)
154-
)
155-
156-
for module in self.lookupContext.symbolTable.importedModules.keys.sorted() {
157-
guard module != "Swift" else {
158-
continue
159-
}
160-
161-
guard let alternativeModules = self.lookupContext.symbolTable.importedModules[module]?.alternativeModules else {
162-
printer.print("import \(module)")
163-
continue
164-
}
165-
166-
// Try to print only on main module from relation chain as it has every other module.
167-
guard !mainSymbolSourceModules.isDisjoint(with: alternativeModules.moduleNames) || alternativeModules.isMainSourceOfSymbols else {
168-
if !alternativeModules.isMainSourceOfSymbols {
169-
printer.print("import \(module)")
170-
}
171-
continue
172-
}
173-
174-
var importGroups: [String: [String]] = [:]
175-
for name in alternativeModules.moduleNames {
176-
guard let otherModule = self.lookupContext.symbolTable.importedModules[name] else { continue }
177-
178-
let groupKey = otherModule.requiredAvailablityOfModuleWithName ?? otherModule.moduleName
179-
importGroups[groupKey, default: []].append(otherModule.moduleName)
180-
}
181-
182-
for (index, group) in importGroups.keys.sorted().enumerated() {
183-
if index > 0 && importGroups.keys.count > 1 {
184-
printer.print("#elseif canImport(\(group))")
185-
} else {
186-
printer.print("#if canImport(\(group))")
187-
}
188-
189-
for groupModule in importGroups[group] ?? [] {
190-
printer.print("import \(groupModule)")
191-
}
192-
}
193-
194-
if (importGroups.keys.isEmpty) {
195-
printer.print("import \(module)")
196-
} else {
197-
printer.print("#else")
198-
printer.print("import \(module)")
199-
printer.print("#endif")
200-
}
201-
}
202-
printer.println()
203-
}
204150
}
205151

206152
struct SwiftThunkTranslator {

Sources/JExtractSwiftLib/JNI/JNIJavaTypeTranslator.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ enum JNIJavaTypeTranslator {
4444
.unsafePointer, .unsafeMutablePointer,
4545
.unsafeRawBufferPointer, .unsafeMutableRawBufferPointer,
4646
.unsafeBufferPointer, .unsafeMutableBufferPointer,
47-
.optional, .foundationData, .foundationDataProtocol, .essentialsData, .essentialsDataProtocol, .array:
47+
.optional, .foundationData, .foundationDataProtocol, .essentialsData, .essentialsDataProtocol, .array, .foundationDate, .essentialsDate:
4848
return nil
4949
}
5050
}

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,12 @@ extension JNISwift2JavaGenerator {
389389
parameterName: parameterName
390390
)
391391

392+
case .foundationDate, .essentialsDate:
393+
return TranslatedParameter(
394+
parameter: JavaParameter(name: parameterName, type: .javaTimeInstant, annotations: parameterAnnotations),
395+
conversion: .instantToDouble
396+
)
397+
392398
default:
393399
guard let javaType = JNIJavaTypeTranslator.translate(knownType: knownType, config: self.config) else {
394400
throw JavaTranslationError.unsupportedSwiftType(swiftType)
@@ -671,6 +677,14 @@ extension JNISwift2JavaGenerator {
671677
elementType: elementType
672678
)
673679

680+
case .foundationDate, .essentialsDate:
681+
return TranslatedResult(
682+
javaType: .javaTimeInstant,
683+
annotations: resultAnnotations,
684+
outParameters: [],
685+
conversion: .doubleToInstant
686+
)
687+
674688
default:
675689
guard let javaType = JNIJavaTypeTranslator.translate(knownType: knownType, config: self.config) else {
676690
throw JavaTranslationError.unsupportedSwiftType(swiftType)
@@ -1109,6 +1123,12 @@ extension JNISwift2JavaGenerator {
11091123
.method(.constant("Arrays"), function: "stream", arguments: [argument])
11101124
}
11111125

1126+
/// Convert a `java.time.Instant` to a seconds double
1127+
case instantToDouble
1128+
1129+
/// Convert a double to `java.time.Instant`
1130+
case doubleToInstant
1131+
11121132
/// Returns the conversion string applied to the placeholder.
11131133
func render(_ printer: inout CodePrinter, _ placeholder: String) -> String {
11141134
// NOTE: 'printer' is used if the conversion wants to cause side-effects.
@@ -1242,13 +1262,26 @@ extension JNISwift2JavaGenerator {
12421262
case .requireNonNull(let inner, let message):
12431263
let inner = inner.render(&printer, placeholder)
12441264
return #"Objects.requireNonNull(\#(inner), "\#(message)")"#
1265+
1266+
case .instantToDouble:
1267+
return "(\(placeholder).getEpochSecond() + (\(placeholder).getNano() / 1_000_000_000.0))"
1268+
1269+
case .doubleToInstant:
1270+
printer.print(
1271+
"""
1272+
double $instant = \(placeholder);
1273+
long $seconds = (long) $instant;
1274+
long $nanos = (long) (($instant - $seconds) * 1_000_000_000);
1275+
"""
1276+
)
1277+
return "java.time.Instant.ofEpochSecond($seconds, $nanos)"
12451278
}
12461279
}
12471280

12481281
/// Whether the conversion uses SwiftArena.
12491282
var requiresSwiftArena: Bool {
12501283
switch self {
1251-
case .placeholder, .constant, .isOptionalPresent, .combinedName:
1284+
case .placeholder, .constant, .isOptionalPresent, .combinedName, .instantToDouble, .doubleToInstant:
12521285
return false
12531286

12541287
case .constructSwiftValue, .wrapMemoryAddressUnsafe:

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,20 @@ extension JNISwift2JavaGenerator {
9898
}
9999
return try translateArrayParameter(elementType: elementType, parameterName: parameterName)
100100

101+
case .foundationDate, .essentialsDate:
102+
return NativeParameter(
103+
parameters: [
104+
JavaParameter(name: parameterName, type: .double)
105+
],
106+
conversion: .method(
107+
.constant("Date"),
108+
function: "init",
109+
arguments: [
110+
("timeIntervalSince1970", .initFromJNI(.placeholder, swiftType: self.knownTypes.double))
111+
]
112+
)
113+
)
114+
101115
default:
102116
guard let javaType = JNIJavaTypeTranslator.translate(knownType: knownType, config: self.config),
103117
javaType.implementsJavaValue else {
@@ -484,6 +498,13 @@ extension JNISwift2JavaGenerator {
484498
}
485499
return try translateArrayResult(elementType: elementType, resultName: resultName)
486500

501+
case .foundationDate, .essentialsDate:
502+
return NativeResult(
503+
javaType: .double,
504+
conversion: .getJNIValue(.member(.placeholder, member: "timeIntervalSince1970")),
505+
outParameters: []
506+
)
507+
487508
default:
488509
guard let javaType = JNIJavaTypeTranslator.translate(knownType: knownType, config: self.config), javaType.implementsJavaValue else {
489510
throw JavaTranslationError.unsupportedSwiftType(swiftResult.type)
@@ -1111,4 +1132,4 @@ extension JNISwift2JavaGenerator {
11111132
}
11121133
}
11131134
}
1114-
}
1135+
}

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,8 @@ extension JNISwift2JavaGenerator {
710710
711711
"""
712712
)
713+
714+
self.lookupContext.symbolTable.printImportedModules(&printer)
713715
}
714716

715717
private func printTypeMetadataAddressThunk(_ printer: inout CodePrinter, _ type: ImportedNominalType) {

Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,8 @@ extension JavaType {
5555
static func future(_ T: JavaType) -> JavaType {
5656
.class(package: "java.util.concurrent", name: "Future", typeParameters: [T.boxedType])
5757
}
58+
59+
static var javaTimeInstant: JavaType {
60+
.class(package: "java.time", name: "Instant")
61+
}
5862
}

Sources/JExtractSwiftLib/SwiftTypes/SwiftKnownModules.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ private let foundationEssentialsSourceFile: SourceFileSyntax = """
113113
public var count: Int { get }
114114
public func withUnsafeBytes(_ body: (UnsafeRawBufferPointer) -> Void)
115115
}
116+
117+
public struct Date {}
116118
"""
117119

118120
private var foundationSourceFile: SourceFileSyntax {

0 commit comments

Comments
 (0)