Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ public func echoUnsignedInt(i: UInt32, j: UInt64) -> UInt64 {
return UInt64(i) + j
}

public func returnUnsignedByte(b: UInt8) -> UInt8 {
return b
}

public func returnLargestUnsignedByte() -> UInt8 {
return UInt8.max
}

// ==== Internal helpers

func p(_ msg: String, file: String = #fileID, line: UInt = #line, function: String = #function) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,14 @@ void globalUnsignedIntEcho() {
long l = 1200;
assertEquals(1212, MySwiftLibrary.echoUnsignedInt(12, 1200));
}

@Test
void returnUnsignedByte_negative() {
assertEquals(-50, MySwiftLibrary.returnUnsignedByte((byte) -50));
}

@Test
void returnLargestUnsignedByte() {
assertEquals(-1, MySwiftLibrary.returnLargestUnsignedByte());
}
}
18 changes: 7 additions & 11 deletions Sources/JExtractSwiftLib/Common/TypeAnnotations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,12 @@ import SwiftJavaConfigurationShared
/// Determine if the given type needs any extra annotations that should be included
/// in Java sources when the corresponding Java type is rendered.
func getTypeAnnotations(swiftType: SwiftType, config: Configuration) -> [JavaAnnotation] {
if config.effectiveUnsignedNumbersMode == .annotate {
switch swiftType {
case .array(let wrapped) where wrapped.isUnsignedInteger:
return [JavaAnnotation.unsigned]
case _ where swiftType.isUnsignedInteger:
return [JavaAnnotation.unsigned]
default:
break
}
switch swiftType {
case .array(let wrapped) where wrapped.isUnsignedInteger:
return [JavaAnnotation.unsigned]
case _ where swiftType.isUnsignedInteger:
return [JavaAnnotation.unsigned]
default:
return []
}

return []
}
25 changes: 0 additions & 25 deletions Sources/JExtractSwiftLib/Configuration+Extensions.swift

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -336,16 +336,6 @@ extension FFMSwift2JavaGenerator {
// If the result type should cause any annotations on the method, include them here.
let parameterAnnotations: [JavaAnnotation] = getTypeAnnotations(swiftType: swiftType, config: config)

// If we need to handle unsigned integers do so here
if config.effectiveUnsignedNumbersMode.needsConversion {
if let unsignedWrapperType = JavaType.unsignedWrapper(for: swiftType) {
return TranslatedParameter(
javaParameters: [
JavaParameter(name: parameterName, type: unsignedWrapperType, annotations: parameterAnnotations)
], conversion: .call(.placeholder, function: "UnsignedNumbers.toPrimitive", withArena: false))
}
}

// If there is a 1:1 mapping between this Swift type and a C type, that can
// be expressed as a Java primitive type.
if let cType = try? CType(cdeclType: swiftType) {
Expand Down Expand Up @@ -593,57 +583,12 @@ extension FFMSwift2JavaGenerator {
}
}

func unsignedResultConversion(_ from: SwiftType, to javaType: JavaType,
mode: JExtractUnsignedIntegerMode) -> JavaConversionStep {
switch mode {
case .annotate:
return .placeholder // no conversions

case .wrapGuava:
guard let typeName = javaType.fullyQualifiedClassName else {
fatalError("Missing target class name for result conversion step from \(from) to \(javaType)")
}

switch from {
case .nominal(let nominal):
switch nominal.nominalTypeDecl.knownTypeKind {
case .uint8:
return .call(.placeholder, function: "\(typeName).fromIntBits", withArena: false)
case .uint16:
return .placeholder // no conversion, UInt16 can be returned as-is and will be seen as char by Java
case .uint32:
return .call(.placeholder, function: "\(typeName).fromIntBits", withArena: false)
case .uint64:
return .call(.placeholder, function: "\(typeName).fromLongBits", withArena: false)
default:
fatalError("unsignedResultConversion: Unsupported conversion from \(from) to \(javaType)")
}
default:
fatalError("unsignedResultConversion: Unsupported conversion from \(from) to \(javaType)")
}
}
}

/// Translate a Swift API result to the user-facing Java API result.
func translateResult(
swiftResult: SwiftResult,
loweredResult: LoweredResult
) throws -> TranslatedResult {
let swiftType = swiftResult.type

// If we need to handle unsigned integers do so here
if config.effectiveUnsignedNumbersMode.needsConversion {
if let unsignedWrapperType = JavaType.unsignedWrapper(for: swiftType) /* and we're in safe wrapper mode */ {
return TranslatedResult(
javaResultType: unsignedWrapperType,
outParameters: [],
conversion: unsignedResultConversion(
swiftType, to: unsignedWrapperType,
mode: self.config.effectiveUnsignedNumbersMode)
)
}
}

// If the result type should cause any annotations on the method, include them here.
let resultAnnotations: [JavaAnnotation] = getTypeAnnotations(swiftType: swiftType, config: config)

Expand Down
7 changes: 0 additions & 7 deletions Sources/JExtractSwiftLib/JNI/JNIJavaTypeTranslator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,6 @@ import SwiftJavaConfigurationShared
enum JNIJavaTypeTranslator {

static func translate(knownType: SwiftKnownTypeDeclKind, config: Configuration) -> JavaType? {
let unsigned = config.effectiveUnsignedNumbersMode
guard unsigned == .annotate else {
// We do not support wrap mode in JNI mode currently;
// In the future this is where it would be interesting to implement Kotlin UInt support.
return nil
}

switch knownType {
case .bool: return .boolean

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,18 +365,6 @@ extension JNISwift2JavaGenerator {
// If the result type should cause any annotations on the method, include them here.
let parameterAnnotations: [JavaAnnotation] = getTypeAnnotations(swiftType: swiftType, config: config)

// If we need to handle unsigned integers do so here
if config.effectiveUnsignedNumbersMode.needsConversion {
if let unsignedWrapperType = JavaType.unsignedWrapper(for: swiftType) {
return TranslatedParameter(
parameter: JavaParameter(name: parameterName, type: unsignedWrapperType, annotations: parameterAnnotations),
conversion: unsignedResultConversion(
swiftType, to: unsignedWrapperType,
mode: self.config.effectiveUnsignedNumbersMode)
)
}
}

switch swiftType {
case .nominal(let nominalType):
let nominalTypeName = nominalType.nominalTypeDecl.qualifiedName
Expand Down Expand Up @@ -489,20 +477,6 @@ extension JNISwift2JavaGenerator {
}
}

func unsignedResultConversion(
_ from: SwiftType,
to javaType: JavaType,
mode: JExtractUnsignedIntegerMode
) -> JavaNativeConversionStep {
switch mode {
case .annotate:
return .placeholder // no conversions

case .wrapGuava:
fatalError("JExtract in JNI mode does not support the \(JExtractUnsignedIntegerMode.wrapGuava) unsigned numerics mode")
}
}

func convertToAsync(
translatedFunctionSignature: inout TranslatedFunctionSignature,
nativeFunctionSignature: inout NativeFunctionSignature,
Expand Down
69 changes: 0 additions & 69 deletions Sources/JExtractSwiftLib/JavaTypes/JavaType+SwiftKit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,75 +16,6 @@ import JavaTypes

extension JavaType {

/// Try to map a Swift type name (e.g., from the module Swift) over to a
/// primitive Java type, or fail otherwise.
public init?(swiftTypeName: String, WHT_unsigned unsigned: UnsignedNumericsMode) {
switch swiftTypeName {
case "Bool": self = .boolean

case "Int8": self = .byte
case "UInt8":
self = switch unsigned {
case .ignoreSign: .byte
case .wrapUnsignedGuava: JavaType.guava.primitives.UnsignedInteger
}

case "Int16": self = .short
case "UInt16": self = .char

case "Int32": self = .int
case "UInt32":
self = switch unsigned {
case .ignoreSign: .int
case .wrapUnsignedGuava: JavaType.guava.primitives.UnsignedInteger
}

case "Int64": self = .long
case "UInt64":
self = switch unsigned {
case .ignoreSign: .long
case .wrapUnsignedGuava: JavaType.guava.primitives.UnsignedLong
}

case "Float": self = .float
case "Double": self = .double
case "Void": self = .void
default: return nil
}
}
}

extension JavaType {

static func unsignedWrapper(for swiftType: SwiftType) -> JavaType? {
switch swiftType {
case .nominal(let nominal):
switch nominal.nominalTypeDecl.knownTypeKind {
case .uint8: return guava.primitives.UnsignedInteger
case .uint16: return .char // no wrapper necessary, we can express it as 'char' natively in Java
case .uint32: return guava.primitives.UnsignedInteger
case .uint64: return guava.primitives.UnsignedLong
default: return nil
}
default: return nil
}
}

/// Known types from the Google Guava library
enum guava {
enum primitives {
static let package = "com.google.common.primitives"

static var UnsignedInteger: JavaType {
.class(package: primitives.package, name: "UnsignedInteger")
}

static var UnsignedLong: JavaType {
.class(package: primitives.package, name: "UnsignedLong")
}
}
}

/// The description of the type org.swift.swiftkit.core.SimpleCompletableFuture<T>
static func simpleCompletableFuture(_ T: JavaType) -> JavaType {
.class(package: "org.swift.swiftkit.core", name: "SimpleCompletableFuture", typeParameters: [T.boxedType])
Expand Down
38 changes: 32 additions & 6 deletions Sources/SwiftJava/BridgedValues/JavaValue+Integers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ extension UInt8: JavaValue {
public static var javaType: JavaType { .byte }

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

/// Initialize from a JNI value.
public init(fromJNI value: JNIType, in environment: JNIEnvironment) {
self = Self(value)
self = Self(bitPattern: value)
}

public static func jniMethodCall(
Expand Down Expand Up @@ -238,11 +238,11 @@ extension UInt32: JavaValue {
public static var javaType: JavaType { .int }

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

/// Initialize from a JNI value.
public init(fromJNI value: JNIType, in environment: JNIEnvironment) {
self = Self(value)
self = Self(bitPattern: value)
}

public static func jniMethodCall(
Expand Down Expand Up @@ -353,10 +353,36 @@ extension UInt64: JavaValue {

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

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

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

public static var javaType: JavaType { .long }
Expand Down
5 changes: 0 additions & 5 deletions Sources/SwiftJavaConfigurationShared/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,6 @@ public struct Configuration: Codable {

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

public var unsignedNumbersMode: JExtractUnsignedIntegerMode?
public var effectiveUnsignedNumbersMode: JExtractUnsignedIntegerMode {
unsignedNumbersMode ?? .default
}

public var minimumInputAccessLevelMode: JExtractMinimumAccessLevelMode?
public var effectiveMinimumInputAccessLevelMode: JExtractMinimumAccessLevelMode {
minimumInputAccessLevelMode ?? .default
Expand Down
Loading
Loading