Skip to content

Commit 0965209

Browse files
committed
add tests and correct char handling for jextractign unsigned params
1 parent bdc5219 commit 0965209

File tree

9 files changed

+302
-46
lines changed

9 files changed

+302
-46
lines changed

Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -505,13 +505,46 @@ extension FFMSwift2JavaGenerator {
505505
}
506506
}
507507

508+
func unsignedResultConversion(_ from: SwiftType, to javaType: JavaType) -> JavaConversionStep {
509+
guard let className = javaType.className else {
510+
fatalError("Missing target class name for result conversion step from \(from) to \(javaType)")
511+
}
512+
513+
switch from {
514+
case .nominal(let nominal):
515+
switch nominal.nominalTypeDecl.knownTypeKind {
516+
case .uint8:
517+
return .call(.placeholder, function: "\(className).fromIntBits", withArena: false)
518+
case .uint16:
519+
return .placeholder // no conversion, UInt16 can be returned as-is and will be seen as char by Java
520+
case .uint32:
521+
return .call(.placeholder, function: "\(className).fromIntBits", withArena: false)
522+
case .uint64:
523+
return .call(.placeholder, function: "\(className).fromLongBits", withArena: false)
524+
default:
525+
fatalError("unsignedResultConversion: Unsupported conversion from \(from) to \(javaType)")
526+
}
527+
default:
528+
fatalError("unsignedResultConversion: Unsupported conversion from \(from) to \(javaType)")
529+
}
530+
}
531+
508532
/// Translate a Swift API result to the user-facing Java API result.
509533
func translate(
510534
swiftResult: SwiftResult,
511535
loweredResult: LoweredResult
512536
) throws -> TranslatedResult {
513537
let swiftType = swiftResult.type
514538

539+
// If we need to handle unsigned integers "safely" do so here
540+
if let unsignedWrapperType = JavaType.unsignedWrapper(for: swiftType) /* and we're in safe wrapper mode */ {
541+
return TranslatedResult(
542+
javaResultType: unsignedWrapperType,
543+
outParameters: [],
544+
conversion: unsignedResultConversion(swiftType, to: unsignedWrapperType)
545+
)
546+
}
547+
515548
// If there is a 1:1 mapping between this Swift type and a C type, that can
516549
// be expressed as a Java primitive type.
517550
if let cType = try? CType(cdeclType: swiftType) {
@@ -720,10 +753,10 @@ extension CType {
720753
case .integral(.signed(bits: 32)): return .SwiftInt32
721754
case .integral(.signed(bits: 64)): return .SwiftInt64
722755

723-
case .integral(.unsigned(bits: 8)): return .SwiftInt8
724-
case .integral(.unsigned(bits: 16)): return .SwiftInt16
725-
case .integral(.unsigned(bits: 32)): return .SwiftInt32
726-
case .integral(.unsigned(bits: 64)): return .SwiftInt64
756+
case .integral(.unsigned(bits: 8)): return .SwiftUInt8
757+
case .integral(.unsigned(bits: 16)): return .SwiftUInt16
758+
case .integral(.unsigned(bits: 32)): return .SwiftUInt32
759+
case .integral(.unsigned(bits: 64)): return .SwiftUInt64
727760

728761
case .floating(.double): return .SwiftDouble
729762
case .floating(.float): return .SwiftFloat

Sources/JExtractSwiftLib/FFM/ForeignValueLayouts.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,19 @@ extension ForeignValueLayout {
6767
public static let SwiftBool = Self(javaConstant: "SWIFT_BOOL")
6868

6969
public static let SwiftInt = Self(javaConstant: "SWIFT_INT")
70+
public static let SwiftUInt = Self(javaConstant: "SWIFT_UINT")
71+
7072
public static let SwiftInt64 = Self(javaConstant: "SWIFT_INT64")
73+
public static let SwiftUInt64 = Self(javaConstant: "SWIFT_UINT64")
74+
7175
public static let SwiftInt32 = Self(javaConstant: "SWIFT_INT32")
76+
public static let SwiftUInt32 = Self(javaConstant: "SWIFT_UINT32")
77+
7278
public static let SwiftInt16 = Self(javaConstant: "SWIFT_INT16")
7379
public static let SwiftUInt16 = Self(javaConstant: "SWIFT_UINT16")
80+
7481
public static let SwiftInt8 = Self(javaConstant: "SWIFT_INT8")
82+
public static let SwiftUInt8 = Self(javaConstant: "SWIFT_UINT8")
7583

7684
public static let SwiftFloat = Self(javaConstant: "SWIFT_FLOAT")
7785
public static let SwiftDouble = Self(javaConstant: "SWIFT_DOUBLE")

Sources/JExtractSwiftLib/JavaTypes/JavaType+SwiftKit.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ extension JavaType {
6161
case .nominal(let nominal):
6262
switch nominal.nominalTypeDecl.knownTypeKind {
6363
case .uint8: return swiftkit.primitives.UnsignedByte
64-
case .uint16: return swiftkit.primitives.UnsignedShort
64+
case .uint16: return .char // no wrapper necessary, we can express it as 'char' natively in Java
6565
case .uint32: return swiftkit.primitives.UnsignedInteger
6666
case .uint64: return swiftkit.primitives.UnsignedLong
6767
default: return nil

SwiftKitCore/src/main/java/org/swift/swiftkit/core/primitives/UnsignedLong.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
import java.math.BigInteger;
3535

36+
import com.sun.source.doctree.AttributeTree;
3637
import org.swift.swiftkit.core.annotations.Nullable;
3738

3839
/**
@@ -277,3 +278,58 @@ public String toString(int radix) {
277278
return UnsignedLongs.toString(value, radix);
278279
}
279280
}
281+
282+
283+
284+
285+
286+
287+
288+
289+
290+
291+
292+
293+
294+
295+
296+
// enum V {
297+
// case car(name: String)
298+
// case bicycle(int: Int)
299+
// }
300+
301+
302+
class Vehicle {
303+
enum VK {
304+
CAR,
305+
BIKE;
306+
}
307+
308+
Vehicle() {
309+
}
310+
311+
public VK getKind() {
312+
return null;
313+
}
314+
}
315+
316+
void test(Vehicle v) {
317+
v.getKind()
318+
}
319+
320+
321+
322+
323+
324+
325+
326+
327+
328+
329+
330+
331+
332+
333+
334+
335+

SwiftKitCore/src/main/java/org/swift/swiftkit/core/primitives/UnsignedNumbers.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@
2525
*/
2626
public final class UnsignedNumbers {
2727

28+
@Deprecated(forRemoval = true)
29+
public static int toPrimitive(char value) {
30+
return value; // TODO: remove this, we should not be generating a conversion for 'char'
31+
}
32+
2833
/**
2934
* Returns the primitive {@code int}, value of the passed in {@link UnsignedInteger}.
3035
*/
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package org.swift.swiftkit.core.primitives;
2+
3+
public class VK {
4+
}

SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/SwiftValueLayout.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,19 @@ public static long addressByteSize() {
3434
}
3535

3636
public static final ValueLayout.OfBoolean SWIFT_BOOL = ValueLayout.JAVA_BOOLEAN;
37+
3738
public static final ValueLayout.OfByte SWIFT_INT8 = ValueLayout.JAVA_BYTE;
38-
public static final ValueLayout.OfChar SWIFT_UINT16 = ValueLayout.JAVA_CHAR;
39+
public static final ValueLayout.OfByte SWIFT_UINT8 = SWIFT_INT8;
40+
3941
public static final ValueLayout.OfShort SWIFT_INT16 = ValueLayout.JAVA_SHORT;
42+
public static final ValueLayout.OfChar SWIFT_UINT16 = ValueLayout.JAVA_CHAR;
43+
4044
public static final ValueLayout.OfInt SWIFT_INT32 = ValueLayout.JAVA_INT;
45+
public static final ValueLayout.OfInt SWIFT_UINT32 = SWIFT_INT32;
46+
4147
public static final ValueLayout.OfLong SWIFT_INT64 = ValueLayout.JAVA_LONG;
48+
public static final ValueLayout.OfLong SWIFT_UINT64 = SWIFT_INT64;
49+
4250
public static final ValueLayout.OfFloat SWIFT_FLOAT = ValueLayout.JAVA_FLOAT;
4351
public static final ValueLayout.OfDouble SWIFT_DOUBLE = ValueLayout.JAVA_DOUBLE;
4452

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
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 JExtractSwiftLib
16+
import Testing
17+
18+
final class UnsignedNumberTests {
19+
20+
@Test("Import: UInt8")
21+
func unsignedByte() throws {
22+
try assertOutput(
23+
input: "public func unsignedByte(_ arg: UInt8)",
24+
.ffm, .java,
25+
detectChunkByInitialLines: 2,
26+
expectedChunks: [
27+
"""
28+
/**
29+
* {@snippet lang=c :
30+
* void swiftjava_SwiftModule_unsignedByte__(uint8_t arg)
31+
* }
32+
*/
33+
private static class swiftjava_SwiftModule_unsignedByte__ {
34+
private static final FunctionDescriptor DESC = FunctionDescriptor.ofVoid(
35+
/* arg: */SwiftValueLayout.SWIFT_UINT8
36+
);
37+
""",
38+
"""
39+
public static void unsignedByte(org.swift.swiftkit.core.primitives.UnsignedByte arg) {
40+
swiftjava_SwiftModule_unsignedByte__.call(UnsignedNumbers.toPrimitive(arg));
41+
}
42+
""",
43+
]
44+
)
45+
}
46+
47+
@Test("Import: UInt16")
48+
func unsignedChar() throws {
49+
try assertOutput(
50+
input: "public func unsignedChar(_ arg: UInt16)",
51+
.ffm, .java,
52+
detectChunkByInitialLines: 2,
53+
expectedChunks: [
54+
"""
55+
/**
56+
* {@snippet lang=c :
57+
* void swiftjava_SwiftModule_unsignedChar__(uint16_t arg)
58+
* }
59+
*/
60+
private static class swiftjava_SwiftModule_unsignedChar__ {
61+
private static final FunctionDescriptor DESC = FunctionDescriptor.ofVoid(
62+
/* arg: */SwiftValueLayout.SWIFT_UINT16
63+
);
64+
""",
65+
"""
66+
public static void unsignedChar(char arg) {
67+
swiftjava_SwiftModule_unsignedChar__.call(UnsignedNumbers.toPrimitive(arg));
68+
}
69+
""",
70+
]
71+
)
72+
}
73+
74+
@Test("Import: UInt32")
75+
func unsignedInt() throws {
76+
try assertOutput(
77+
input: "public func unsignedInt(_ arg: UInt32)",
78+
.ffm, .java,
79+
detectChunkByInitialLines: 2,
80+
expectedChunks: [
81+
"""
82+
/**
83+
* {@snippet lang=c :
84+
* void swiftjava_SwiftModule_unsignedInt__(uint32_t arg)
85+
* }
86+
*/
87+
private static class swiftjava_SwiftModule_unsignedInt__ {
88+
private static final FunctionDescriptor DESC = FunctionDescriptor.ofVoid(
89+
/* arg: */SwiftValueLayout.SWIFT_UINT32
90+
);
91+
""",
92+
"""
93+
public static void unsignedInt(org.swift.swiftkit.core.primitives.UnsignedInteger arg) {
94+
swiftjava_SwiftModule_unsignedInt__.call(UnsignedNumbers.toPrimitive(arg));
95+
}
96+
""",
97+
]
98+
)
99+
}
100+
101+
@Test("Import: return UInt32")
102+
func returnUnsignedInt() throws {
103+
try assertOutput(
104+
input: "public func returnUnsignedInt() -> UInt32",
105+
.ffm, .java,
106+
detectChunkByInitialLines: 2,
107+
expectedChunks: [
108+
"""
109+
/**
110+
* {@snippet lang=c :
111+
* uint32_t swiftjava_SwiftModule_returnUnsignedInt(void)
112+
* }
113+
*/
114+
private static class swiftjava_SwiftModule_returnUnsignedInt {
115+
private static final FunctionDescriptor DESC = FunctionDescriptor.of(
116+
/* -> */SwiftValueLayout.SWIFT_UINT32
117+
);
118+
""",
119+
"""
120+
public static org.swift.swiftkit.core.primitives.UnsignedInteger returnUnsignedInt() {
121+
return UnsignedInteger.fromIntBits(swiftjava_SwiftModule_returnUnsignedInt.call());
122+
}
123+
""",
124+
]
125+
)
126+
}
127+
128+
@Test("Import: UInt64")
129+
func unsignedLong() throws {
130+
try assertOutput(
131+
input: "public func unsignedLong(_ arg: UInt64)",
132+
.ffm, .java,
133+
detectChunkByInitialLines: 2,
134+
expectedChunks: [
135+
"""
136+
/**
137+
* {@snippet lang=c :
138+
* void swiftjava_SwiftModule_unsignedLong__(uint64_t arg)
139+
* }
140+
*/
141+
private static class swiftjava_SwiftModule_unsignedLong__ {
142+
private static final FunctionDescriptor DESC = FunctionDescriptor.ofVoid(
143+
/* arg: */SwiftValueLayout.SWIFT_UINT64
144+
);
145+
""",
146+
"""
147+
public static void unsignedLong(org.swift.swiftkit.core.primitives.UnsignedLong arg) {
148+
swiftjava_SwiftModule_unsignedLong__.call(UnsignedNumbers.toPrimitive(arg));
149+
}
150+
""",
151+
]
152+
)
153+
}
154+
155+
@Test("Import: return UInt64")
156+
func returnUnsignedLong() throws {
157+
try assertOutput(
158+
input: "public func returnUnsignedLong() -> UInt64",
159+
.ffm, .java,
160+
detectChunkByInitialLines: 2,
161+
expectedChunks: [
162+
"""
163+
/**
164+
* {@snippet lang=c :
165+
* uint64_t swiftjava_SwiftModule_returnUnsignedLong(void)
166+
* }
167+
*/
168+
private static class swiftjava_SwiftModule_returnUnsignedLong {
169+
private static final FunctionDescriptor DESC = FunctionDescriptor.of(
170+
/* -> */SwiftValueLayout.SWIFT_UINT64
171+
);
172+
""",
173+
"""
174+
public static org.swift.swiftkit.core.primitives.UnsignedLong returnUnsignedLong() {
175+
return UnsignedLong.fromLongBits(swiftjava_SwiftModule_returnUnsignedLong.call());
176+
}
177+
""",
178+
]
179+
)
180+
}
181+
182+
}

0 commit comments

Comments
 (0)