Skip to content

Commit 0eefeab

Browse files
authored
jextract: remove unsigned integers mode, remove wrap-guava mode (#485)
1 parent 5ff12b1 commit 0eefeab

File tree

15 files changed

+60
-418
lines changed

15 files changed

+60
-418
lines changed

Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ public func echoUnsignedInt(i: UInt32, j: UInt64) -> UInt64 {
5252
return UInt64(i) + j
5353
}
5454

55+
public func returnUnsignedByte(b: UInt8) -> UInt8 {
56+
return b
57+
}
58+
59+
public func returnLargestUnsignedByte() -> UInt8 {
60+
return UInt8.max
61+
}
62+
5563
// ==== Internal helpers
5664

5765
func p(_ msg: String, file: String = #fileID, line: UInt = #line, function: String = #function) {

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,14 @@ void globalUnsignedIntEcho() {
6868
long l = 1200;
6969
assertEquals(1212, MySwiftLibrary.echoUnsignedInt(12, 1200));
7070
}
71+
72+
@Test
73+
void returnUnsignedByte_negative() {
74+
assertEquals(-50, MySwiftLibrary.returnUnsignedByte((byte) -50));
75+
}
76+
77+
@Test
78+
void returnLargestUnsignedByte() {
79+
assertEquals(-1, MySwiftLibrary.returnLargestUnsignedByte());
80+
}
7181
}

Sources/JExtractSwiftLib/Common/TypeAnnotations.swift

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,12 @@ import SwiftJavaConfigurationShared
1818
/// Determine if the given type needs any extra annotations that should be included
1919
/// in Java sources when the corresponding Java type is rendered.
2020
func getTypeAnnotations(swiftType: SwiftType, config: Configuration) -> [JavaAnnotation] {
21-
if config.effectiveUnsignedNumbersMode == .annotate {
22-
switch swiftType {
23-
case .array(let wrapped) where wrapped.isUnsignedInteger:
24-
return [JavaAnnotation.unsigned]
25-
case _ where swiftType.isUnsignedInteger:
26-
return [JavaAnnotation.unsigned]
27-
default:
28-
break
29-
}
21+
switch swiftType {
22+
case .array(let wrapped) where wrapped.isUnsignedInteger:
23+
return [JavaAnnotation.unsigned]
24+
case _ where swiftType.isUnsignedInteger:
25+
return [JavaAnnotation.unsigned]
26+
default:
27+
return []
3028
}
31-
32-
return []
3329
}

Sources/JExtractSwiftLib/Configuration+Extensions.swift

Lines changed: 0 additions & 25 deletions
This file was deleted.

Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -336,16 +336,6 @@ extension FFMSwift2JavaGenerator {
336336
// If the result type should cause any annotations on the method, include them here.
337337
let parameterAnnotations: [JavaAnnotation] = getTypeAnnotations(swiftType: swiftType, config: config)
338338

339-
// If we need to handle unsigned integers do so here
340-
if config.effectiveUnsignedNumbersMode.needsConversion {
341-
if let unsignedWrapperType = JavaType.unsignedWrapper(for: swiftType) {
342-
return TranslatedParameter(
343-
javaParameters: [
344-
JavaParameter(name: parameterName, type: unsignedWrapperType, annotations: parameterAnnotations)
345-
], conversion: .call(.placeholder, function: "UnsignedNumbers.toPrimitive", withArena: false))
346-
}
347-
}
348-
349339
// If there is a 1:1 mapping between this Swift type and a C type, that can
350340
// be expressed as a Java primitive type.
351341
if let cType = try? CType(cdeclType: swiftType) {
@@ -593,57 +583,12 @@ extension FFMSwift2JavaGenerator {
593583
}
594584
}
595585

596-
func unsignedResultConversion(_ from: SwiftType, to javaType: JavaType,
597-
mode: JExtractUnsignedIntegerMode) -> JavaConversionStep {
598-
switch mode {
599-
case .annotate:
600-
return .placeholder // no conversions
601-
602-
case .wrapGuava:
603-
guard let typeName = javaType.fullyQualifiedClassName else {
604-
fatalError("Missing target class name for result conversion step from \(from) to \(javaType)")
605-
}
606-
607-
switch from {
608-
case .nominal(let nominal):
609-
switch nominal.nominalTypeDecl.knownTypeKind {
610-
case .uint8:
611-
return .call(.placeholder, function: "\(typeName).fromIntBits", withArena: false)
612-
case .uint16:
613-
return .placeholder // no conversion, UInt16 can be returned as-is and will be seen as char by Java
614-
case .uint32:
615-
return .call(.placeholder, function: "\(typeName).fromIntBits", withArena: false)
616-
case .uint64:
617-
return .call(.placeholder, function: "\(typeName).fromLongBits", withArena: false)
618-
default:
619-
fatalError("unsignedResultConversion: Unsupported conversion from \(from) to \(javaType)")
620-
}
621-
default:
622-
fatalError("unsignedResultConversion: Unsupported conversion from \(from) to \(javaType)")
623-
}
624-
}
625-
}
626-
627586
/// Translate a Swift API result to the user-facing Java API result.
628587
func translateResult(
629588
swiftResult: SwiftResult,
630589
loweredResult: LoweredResult
631590
) throws -> TranslatedResult {
632591
let swiftType = swiftResult.type
633-
634-
// If we need to handle unsigned integers do so here
635-
if config.effectiveUnsignedNumbersMode.needsConversion {
636-
if let unsignedWrapperType = JavaType.unsignedWrapper(for: swiftType) /* and we're in safe wrapper mode */ {
637-
return TranslatedResult(
638-
javaResultType: unsignedWrapperType,
639-
outParameters: [],
640-
conversion: unsignedResultConversion(
641-
swiftType, to: unsignedWrapperType,
642-
mode: self.config.effectiveUnsignedNumbersMode)
643-
)
644-
}
645-
}
646-
647592
// If the result type should cause any annotations on the method, include them here.
648593
let resultAnnotations: [JavaAnnotation] = getTypeAnnotations(swiftType: swiftType, config: config)
649594

Sources/JExtractSwiftLib/JNI/JNIJavaTypeTranslator.swift

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,6 @@ import SwiftJavaConfigurationShared
1818
enum JNIJavaTypeTranslator {
1919

2020
static func translate(knownType: SwiftKnownTypeDeclKind, config: Configuration) -> JavaType? {
21-
let unsigned = config.effectiveUnsignedNumbersMode
22-
guard unsigned == .annotate else {
23-
// We do not support wrap mode in JNI mode currently;
24-
// In the future this is where it would be interesting to implement Kotlin UInt support.
25-
return nil
26-
}
27-
2821
switch knownType {
2922
case .bool: return .boolean
3023

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -365,18 +365,6 @@ extension JNISwift2JavaGenerator {
365365
// If the result type should cause any annotations on the method, include them here.
366366
let parameterAnnotations: [JavaAnnotation] = getTypeAnnotations(swiftType: swiftType, config: config)
367367

368-
// If we need to handle unsigned integers do so here
369-
if config.effectiveUnsignedNumbersMode.needsConversion {
370-
if let unsignedWrapperType = JavaType.unsignedWrapper(for: swiftType) {
371-
return TranslatedParameter(
372-
parameter: JavaParameter(name: parameterName, type: unsignedWrapperType, annotations: parameterAnnotations),
373-
conversion: unsignedResultConversion(
374-
swiftType, to: unsignedWrapperType,
375-
mode: self.config.effectiveUnsignedNumbersMode)
376-
)
377-
}
378-
}
379-
380368
switch swiftType {
381369
case .nominal(let nominalType):
382370
let nominalTypeName = nominalType.nominalTypeDecl.qualifiedName
@@ -489,20 +477,6 @@ extension JNISwift2JavaGenerator {
489477
}
490478
}
491479

492-
func unsignedResultConversion(
493-
_ from: SwiftType,
494-
to javaType: JavaType,
495-
mode: JExtractUnsignedIntegerMode
496-
) -> JavaNativeConversionStep {
497-
switch mode {
498-
case .annotate:
499-
return .placeholder // no conversions
500-
501-
case .wrapGuava:
502-
fatalError("JExtract in JNI mode does not support the \(JExtractUnsignedIntegerMode.wrapGuava) unsigned numerics mode")
503-
}
504-
}
505-
506480
func convertToAsync(
507481
translatedFunctionSignature: inout TranslatedFunctionSignature,
508482
nativeFunctionSignature: inout NativeFunctionSignature,

Sources/JExtractSwiftLib/JavaTypes/JavaType+SwiftKit.swift

Lines changed: 0 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -16,75 +16,6 @@ import JavaTypes
1616

1717
extension JavaType {
1818

19-
/// Try to map a Swift type name (e.g., from the module Swift) over to a
20-
/// primitive Java type, or fail otherwise.
21-
public init?(swiftTypeName: String, WHT_unsigned unsigned: UnsignedNumericsMode) {
22-
switch swiftTypeName {
23-
case "Bool": self = .boolean
24-
25-
case "Int8": self = .byte
26-
case "UInt8":
27-
self = switch unsigned {
28-
case .ignoreSign: .byte
29-
case .wrapUnsignedGuava: JavaType.guava.primitives.UnsignedInteger
30-
}
31-
32-
case "Int16": self = .short
33-
case "UInt16": self = .char
34-
35-
case "Int32": self = .int
36-
case "UInt32":
37-
self = switch unsigned {
38-
case .ignoreSign: .int
39-
case .wrapUnsignedGuava: JavaType.guava.primitives.UnsignedInteger
40-
}
41-
42-
case "Int64": self = .long
43-
case "UInt64":
44-
self = switch unsigned {
45-
case .ignoreSign: .long
46-
case .wrapUnsignedGuava: JavaType.guava.primitives.UnsignedLong
47-
}
48-
49-
case "Float": self = .float
50-
case "Double": self = .double
51-
case "Void": self = .void
52-
default: return nil
53-
}
54-
}
55-
}
56-
57-
extension JavaType {
58-
59-
static func unsignedWrapper(for swiftType: SwiftType) -> JavaType? {
60-
switch swiftType {
61-
case .nominal(let nominal):
62-
switch nominal.nominalTypeDecl.knownTypeKind {
63-
case .uint8: return guava.primitives.UnsignedInteger
64-
case .uint16: return .char // no wrapper necessary, we can express it as 'char' natively in Java
65-
case .uint32: return guava.primitives.UnsignedInteger
66-
case .uint64: return guava.primitives.UnsignedLong
67-
default: return nil
68-
}
69-
default: return nil
70-
}
71-
}
72-
73-
/// Known types from the Google Guava library
74-
enum guava {
75-
enum primitives {
76-
static let package = "com.google.common.primitives"
77-
78-
static var UnsignedInteger: JavaType {
79-
.class(package: primitives.package, name: "UnsignedInteger")
80-
}
81-
82-
static var UnsignedLong: JavaType {
83-
.class(package: primitives.package, name: "UnsignedLong")
84-
}
85-
}
86-
}
87-
8819
/// The description of the type org.swift.swiftkit.core.SimpleCompletableFuture<T>
8920
static func simpleCompletableFuture(_ T: JavaType) -> JavaType {
9021
.class(package: "org.swift.swiftkit.core", name: "SimpleCompletableFuture", typeParameters: [T.boxedType])

Sources/SwiftJava/BridgedValues/JavaValue+Integers.swift

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ extension UInt8: JavaValue {
2222
public static var javaType: JavaType { .byte }
2323

2424
/// Retrieve the JNI value.
25-
public func getJNIValue(in environment: JNIEnvironment) -> JNIType { JNIType(self) }
25+
public func getJNIValue(in environment: JNIEnvironment) -> JNIType { JNIType(bitPattern: self) }
2626

2727
/// Initialize from a JNI value.
2828
public init(fromJNI value: JNIType, in environment: JNIEnvironment) {
29-
self = Self(value)
29+
self = Self(bitPattern: value)
3030
}
3131

3232
public static func jniMethodCall(
@@ -238,11 +238,11 @@ extension UInt32: JavaValue {
238238
public static var javaType: JavaType { .int }
239239

240240
/// Retrieve the JNI value.
241-
public func getJNIValue(in environment: JNIEnvironment) -> JNIType { JNIType(self) }
241+
public func getJNIValue(in environment: JNIEnvironment) -> JNIType { JNIType(bitPattern: self) }
242242

243243
/// Initialize from a JNI value.
244244
public init(fromJNI value: JNIType, in environment: JNIEnvironment) {
245-
self = Self(value)
245+
self = Self(bitPattern: value)
246246
}
247247

248248
public static func jniMethodCall(
@@ -353,10 +353,36 @@ extension UInt64: JavaValue {
353353

354354
public static var jvalueKeyPath: WritableKeyPath<jvalue, JNIType> { \.j }
355355

356-
public func getJNIValue(in environment: JNIEnvironment) -> JNIType { JNIType(self) }
356+
public func getJNIValue(in environment: JNIEnvironment) -> JNIType {
357+
// `jlong` is always 64-bit, no matter the system pointer size.
358+
// Due to differences in JNI headers between Android, JDK and how Swift sees these type imports
359+
// we have to handle this a bit differently.
360+
//
361+
// On 32-bit, the standard JDK jlong is defined in C as `long long`, which yields Swift `Int64`
362+
// On 64-bit, the standard JDK jlong is defined in C as `long`, which yields Swift `Int`
363+
// On Android it's correctly marked as int64_t, always yielding `Int64` in Swift.
364+
#if os(Android) || _pointerBitWidth(_32)
365+
return Int64(bitPattern: self)
366+
#else
367+
return Int(bitPattern: UInt(self))
368+
#endif
369+
}
357370

358371
public init(fromJNI value: JNIType, in environment: JNIEnvironment) {
359-
self = UInt64(value)
372+
// `jlong` is always 64-bit, no matter the system pointer size.
373+
// Due to differences in JNI headers between Android, JDK and how Swift sees these type imports
374+
// we have to handle this a bit differently.
375+
//
376+
// On 32-bit, the standard JDK jlong is defined in C as `long long`, which yields Swift `Int64`
377+
// On 64-bit, the standard JDK jlong is defined in C as `long`, which yields Swift `Int`
378+
// On Android it's correctly marked as int64_t, always yielding `Int64` in Swift.
379+
#if os(Android) || _pointerBitWidth(_32)
380+
// In this case `jlong` is seen in Swift as `Int64`.
381+
self = UInt64(bitPattern: value)
382+
#else
383+
// In this case `jlong` is since as just `Int`, which is always Int64
384+
self = UInt64(bitPattern: Int64(value))
385+
#endif
360386
}
361387

362388
public static var javaType: JavaType { .long }

Sources/SwiftJavaConfigurationShared/Configuration.swift

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,6 @@ public struct Configuration: Codable {
4545

4646
public var writeEmptyFiles: Bool? // FIXME: default it to false, but that plays not nice with Codable
4747

48-
public var unsignedNumbersMode: JExtractUnsignedIntegerMode?
49-
public var effectiveUnsignedNumbersMode: JExtractUnsignedIntegerMode {
50-
unsignedNumbersMode ?? .default
51-
}
52-
5348
public var minimumInputAccessLevelMode: JExtractMinimumAccessLevelMode?
5449
public var effectiveMinimumInputAccessLevelMode: JExtractMinimumAccessLevelMode {
5550
minimumInputAccessLevelMode ?? .default

0 commit comments

Comments
 (0)