Skip to content

Commit 5f31cd1

Browse files
committed
some jextract work
1 parent c7499cc commit 5f31cd1

File tree

11 files changed

+257
-16
lines changed

11 files changed

+257
-16
lines changed

Samples/SwiftKitSampleApp/Sources/MySwiftLibrary/MySwiftClass.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,13 @@ public class MySwiftClass {
6060
public func makeRandomIntMethod() -> Int {
6161
return Int.random(in: 1..<256)
6262
}
63+
64+
public func takeUnsignedByte(arg: UInt8) -> UInt8 {
65+
p("\(UInt32.self) = \(arg)")
66+
return arg
67+
}
68+
69+
public func takeUnsignedInt(arg: UInt32) {
70+
p("\(UInt32.self) = \(arg)")
71+
}
6372
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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+
import org.swift.swiftkit.core.primitives.*;
19+
import org.swift.swiftkit.ffm.AllocatingSwiftArena;
20+
21+
import static org.junit.jupiter.api.Assertions.*;
22+
23+
public class UnsignedTest {
24+
@Test
25+
void take_unsigned_int32() {
26+
try (var arena = AllocatingSwiftArena.ofConfined()) {
27+
var c = MySwiftClass.init(1, 2, arena);
28+
c.takeUnsignedInt(UnsignedInteger.valueOf(128));
29+
}
30+
}
31+
32+
@Test
33+
void take_uint8() {
34+
try (var arena = AllocatingSwiftArena.ofConfined()) {
35+
var c = MySwiftClass.init(1, 2, arena);
36+
byte got = c.takeUnsignedByte(UnsignedByte.valueOf(200)); // FIXME: should return UnsignedByte
37+
assertEquals(UnsignedByte.representedByBitsOf(got).intValue(), got);
38+
}
39+
}
40+
}

Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,14 @@ extension FFMSwift2JavaGenerator {
298298
methodName: String
299299
) throws -> TranslatedParameter {
300300

301+
// If we need to handle unsigned integers "safely" do so here
302+
if let unsignedWrapperType = JavaType.unsignedWrapper(for: swiftType) /* and we're in safe wrapper mode */ {
303+
return TranslatedParameter(
304+
javaParameters: [
305+
JavaParameter(name: parameterName, type: unsignedWrapperType)
306+
], conversion: .call(.placeholder, function: "UnsignedNumbers.toPrimitive", withArena: false))
307+
}
308+
301309
// If there is a 1:1 mapping between this Swift type and a C type, that can
302310
// be expressed as a Java primitive type.
303311
if let cType = try? CType(cdeclType: swiftType) {

Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ extension FFMSwift2JavaGenerator {
9898
"org.swift.swiftkit.ffm.*",
9999
"org.swift.swiftkit.ffm.SwiftRuntime",
100100

101+
// Unsigned numerics support
102+
"org.swift.swiftkit.core.primitives.*",
103+
101104
// Necessary for native calls and type mapping
102105
"java.lang.foreign.*",
103106
"java.lang.invoke.*",
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 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+
import JavaTypes
16+
17+
extension JavaType {
18+
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, 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: .char
29+
case .wrapAsUnsignedNumbers: JavaType.swiftkit.primitives.UnsignedByte
30+
}
31+
32+
case "Int16": self = .short
33+
case "UInt16":
34+
self = switch unsigned {
35+
case .ignoreSign: .short
36+
case .wrapAsUnsignedNumbers: JavaType.swiftkit.primitives.UnsignedShort
37+
}
38+
39+
case "Int32": self = .int
40+
case "UInt32":
41+
self = switch unsigned {
42+
case .ignoreSign: .int
43+
case .wrapAsUnsignedNumbers: JavaType.swiftkit.primitives.UnsignedInteger
44+
}
45+
46+
case "Int64": self = .long
47+
case "UInt64":
48+
self = switch unsigned {
49+
case .ignoreSign: .long
50+
case .wrapAsUnsignedNumbers: JavaType.swiftkit.primitives.UnsignedLong
51+
}
52+
53+
case "Float": self = .float
54+
case "Double": self = .double
55+
case "Void": self = .void
56+
default: return nil
57+
}
58+
}
59+
}
60+
61+
extension JavaType {
62+
63+
static func unsignedWrapper(for swiftType: SwiftType) -> JavaType? {
64+
switch swiftType {
65+
case .nominal(let nominal):
66+
switch nominal.nominalTypeDecl.knownTypeKind {
67+
case .uint8: return swiftkit.primitives.UnsignedByte
68+
case .uint16: return swiftkit.primitives.UnsignedShort
69+
case .uint32: return swiftkit.primitives.UnsignedInteger
70+
case .uint64: return swiftkit.primitives.UnsignedLong
71+
default: return nil
72+
}
73+
default: return nil
74+
}
75+
}
76+
77+
enum swiftkit {
78+
enum primitives {
79+
static let package = "org.swift.swiftkit.core.primitives"
80+
static var UnsignedShort: JavaType {
81+
.class(package: primitives.package, name: "UnsignedShort")
82+
}
83+
84+
static var UnsignedByte: JavaType {
85+
.class(package: primitives.package, name: "UnsignedByte")
86+
}
87+
88+
static var UnsignedInteger: JavaType {
89+
.class(package: primitives.package, name: "UnsignedInteger")
90+
}
91+
92+
static var UnsignedLong: JavaType {
93+
.class(package: primitives.package, name: "UnsignedLong")
94+
}
95+
}
96+
}
97+
98+
}

Sources/JExtractSwiftLib/SwiftTypes/SwiftType.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,17 @@ enum SwiftType: Equatable {
9090
return false
9191
}
9292
}
93+
94+
var isUnsignedInteger: Bool {
95+
switch self {
96+
case .nominal(let nominal):
97+
switch nominal.nominalTypeDecl.knownTypeKind {
98+
case .uint8, .uint16, .uint32, .uint64: true
99+
default: false
100+
}
101+
default: false
102+
}
103+
}
93104
}
94105

95106
extension SwiftType: CustomStringConvertible {

Sources/JavaTypes/JavaType+SwiftNames.swift

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -85,20 +85,9 @@ extension JavaType {
8585
}
8686
}
8787

88-
/// Try to map a Swift type name (e.g., from the module Swift) over to a
89-
/// primitive Java type, or fail otherwise.
90-
public init?(swiftTypeName: String) {
91-
switch swiftTypeName {
92-
case "Bool": self = .boolean
93-
case "Int8": self = .byte
94-
case "UInt16": self = .char
95-
case "Int16": self = .short
96-
case "Int32": self = .int
97-
case "Int64": self = .long
98-
case "Float": self = .float
99-
case "Double": self = .double
100-
case "Void": self = .void
101-
default: return nil
102-
}
103-
}
10488
}
89+
90+
public enum UnsignedNumericsMode {
91+
case ignoreSign
92+
case wrapAsUnsignedNumbers
93+
}

Sources/JavaTypes/JavaType.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,4 @@ extension JavaType {
5757
}
5858
}
5959
}
60+
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 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 org.swift.swiftkit.core.primitives;
16+
17+
import java.math.BigInteger;
18+
import java.util.Objects;
19+
20+
/**
21+
* Represents an 32-bit unsigned integer, with a value between 0 and (@{@code 2^32 - 1}).
22+
*
23+
* <p> Equivalent to the {@code UInt32} Swift type.
24+
*/
25+
public final class UnsignedNumbers {
26+
27+
public static byte toPrimitive(UnsignedByte value) {
28+
return value.value;
29+
}
30+
31+
public static short toPrimitive(UnsignedShort value) {
32+
return value.value;
33+
}
34+
35+
public static int toPrimitive(UnsignedInteger value) {
36+
return value.value;
37+
}
38+
39+
public static long toPrimitive(UnsignedLong value) {
40+
return value.value;
41+
}
42+
}

0 commit comments

Comments
 (0)