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 @@ -28,6 +28,11 @@ public protocol CallbackProtocol {
func withObject(_ input: MySwiftClass) -> MySwiftClass
func withOptionalInt64(_ input: Int64?) -> Int64?
func withOptionalObject(_ input: MySwiftClass?) -> Optional<MySwiftClass>
func withInt64Array(_ input: [Int64]) -> [Int64]
func withStringArray(_ input: [String]) -> [String]
func withObjectArray(_ input: [MySwiftClass]) -> [MySwiftClass]
func successfulThrowingFunction() throws
func throwingFunction() throws
}

public struct CallbackOutput {
Expand All @@ -43,6 +48,21 @@ public struct CallbackOutput {
public let object: MySwiftClass
public let optionalInt64: Int64?
public let optionalObject: MySwiftClass?
public let int64Array: [Int64]
public let stringArray: [String]
public let objectArray: [MySwiftClass]
}

public func callProtocolVoid(_ callbacks: some CallbackProtocol) {
callbacks.withVoid();
}

public func callProtocolWithFailedThrowingFunction(_ callbacks: some CallbackProtocol) throws {
try callbacks.throwingFunction();
}

public func callProtocolWithSuccessfulThrowingFunction(_ callbacks: some CallbackProtocol) throws {
try callbacks.successfulThrowingFunction();
}

public func outputCallbacks(
Expand All @@ -58,7 +78,10 @@ public func outputCallbacks(
string: String,
object: MySwiftClass,
optionalInt64: Int64?,
optionalObject: MySwiftClass?
optionalObject: MySwiftClass?,
int64Array: [Int64],
stringArray: [String],
objectArray: [MySwiftClass]
) -> CallbackOutput {
return CallbackOutput(
bool: callbacks.withBool(bool),
Expand All @@ -72,6 +95,9 @@ public func outputCallbacks(
string: callbacks.withString(string),
object: callbacks.withObject(object),
optionalInt64: callbacks.withOptionalInt64(optionalInt64),
optionalObject: callbacks.withOptionalObject(optionalObject)
optionalObject: callbacks.withOptionalObject(optionalObject),
int64Array: callbacks.withInt64Array(int64Array),
stringArray: callbacks.withStringArray(stringArray),
objectArray: callbacks.withObjectArray(objectArray)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,50 @@ public OptionalLong withOptionalInt64(OptionalLong input) {
public Optional<MySwiftClass> withOptionalObject(Optional<MySwiftClass> input, SwiftArena swiftArena$) {
return input;
}

@Override
public long[] withInt64Array(long[] input) {
return input;
}

@Override
public String[] withStringArray(String[] input) {
return input;
}

@Override
public MySwiftClass[] withObjectArray(MySwiftClass[] input, SwiftArena swiftArena$) {
return input;
}

@Override
public void throwingFunction() throws Exception {
throw new Exception("Failed in Java");
}

@Override
public void successfulThrowingFunction() throws Exception {

}
}

@Test
void voidTest() {
JavaCallbacks callbacks = new JavaCallbacks();
MySwiftLibrary.callProtocolVoid(callbacks);
}

@Test
void throwingFunction_thatDoesNotThrow() {
JavaCallbacks callbacks = new JavaCallbacks();
assertDoesNotThrow(() -> MySwiftLibrary.callProtocolWithSuccessfulThrowingFunction(callbacks));
}

@Test
void throwingFunction_thatThrows() {
JavaCallbacks callbacks = new JavaCallbacks();
Exception exception = assertThrows(Exception.class, () -> MySwiftLibrary.callProtocolWithFailedThrowingFunction(callbacks));
assertEquals("Failed in Java", exception.getMessage());
}

@Test
Expand All @@ -95,7 +139,28 @@ void primitiveCallbacks() {
JavaCallbacks callbacks = new JavaCallbacks();
var object = MySwiftClass.init(5, 3, arena);
var optionalObject = Optional.of(MySwiftClass.init(10, 10, arena));
var output = MySwiftLibrary.outputCallbacks(callbacks, true, (byte) 1, (char) 16, (short) 16, (int) 32, 64L, 1.34f, 1.34, "Hello from Java!", object, OptionalLong.empty(), optionalObject, arena);
var int64Array = new long[]{1, 2, 3};
var stringArray = new String[]{"Hey", "there"};
var objectArray = new MySwiftClass[]{MySwiftClass.init(1, 1, arena), MySwiftClass.init(2, 2, arena)};
var output = MySwiftLibrary.outputCallbacks(
callbacks,
true,
(byte) 1,
(char) 16,
(short) 16,
(int) 32,
64L,
1.34f,
1.34,
"Hello from Java!",
object,
OptionalLong.empty(),
optionalObject,
int64Array,
stringArray,
objectArray,
arena
);

assertEquals(1, output.getInt8());
assertEquals(16, output.getUint16());
Expand All @@ -112,6 +177,14 @@ void primitiveCallbacks() {
var optionalObjectOutput = output.getOptionalObject(arena);
assertTrue(optionalObjectOutput.isPresent());
assertEquals(10, optionalObjectOutput.get().getX());

assertArrayEquals(new long[]{1, 2,3}, output.getInt64Array());
assertArrayEquals(new String[]{"Hey", "there"}, output.getStringArray());

var objectArrayOutput = output.getObjectArray(arena);
assertEquals(2, objectArrayOutput.length);
assertEquals(1, objectArrayOutput[0].getX());
assertEquals(2, objectArrayOutput[1].getX());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ extension JNISwift2JavaGenerator {

private func translateParameter(parameterName: String, type: SwiftType) throws -> UpcallConversionStep {

if type.isDirectlyTranslatedToWrapJava {
return .placeholder
}

switch type {
case .nominal(let nominalType):
if let knownType = nominalType.nominalTypeDecl.knownTypeKind {
Expand All @@ -146,12 +150,17 @@ extension JNISwift2JavaGenerator {
wrappedType: genericArgs[0]
)

default:
guard knownType.isDirectlyTranslatedToWrapJava else {
case .array:
guard let genericArgs = nominalType.genericArguments, genericArgs.count == 1 else {
throw JavaTranslationError.unsupportedSwiftType(type)
}
return try translateArrayParameter(
name: parameterName,
elementType: genericArgs[0]
)

return .placeholder
default:
throw JavaTranslationError.unsupportedSwiftType(type)
}
}

Expand All @@ -171,11 +180,32 @@ extension JNISwift2JavaGenerator {
wrappedType: wrappedType
)

case .genericParameter, .function, .metatype, .tuple, .existential, .opaque, .composite, .array:
case .array(let elementType):
return try translateArrayParameter(name: parameterName, elementType: elementType)

case .genericParameter, .function, .metatype, .tuple, .existential, .opaque, .composite:
throw JavaTranslationError.unsupportedSwiftType(type)
}
}

private func translateArrayParameter(name: String, elementType: SwiftType) throws -> UpcallConversionStep {
switch elementType {
case .nominal(let nominalType):
// We assume this is a JExtracted type
return .map(
.placeholder,
body: .toJavaWrapper(
.placeholder,
name: "arrayElement",
nominalType: nominalType
)
)

case .array, .composite, .existential, .function, .genericParameter, .metatype, .opaque, .optional, .tuple:
throw JavaTranslationError.unsupportedSwiftType(.array(elementType))
}
}

private func translateOptionalParameter(name: String, wrappedType: SwiftType) throws -> UpcallConversionStep {
let wrappedConversion = try translateParameter(parameterName: name, type: wrappedType)
return .toJavaOptional(.map(.placeholder, body: wrappedConversion))
Expand All @@ -190,6 +220,10 @@ extension JNISwift2JavaGenerator {
methodName: String,
allowNilForObjects: Bool = false
) throws -> UpcallConversionStep {
if type.isDirectlyTranslatedToWrapJava {
return .placeholder
}

switch type {
case .nominal(let nominalType):
if let knownType = nominalType.nominalTypeDecl.knownTypeKind {
Expand All @@ -203,11 +237,14 @@ extension JNISwift2JavaGenerator {
methodName: methodName
)

default:
guard knownType.isDirectlyTranslatedToWrapJava else {
case .array:
guard let genericArgs = nominalType.genericArguments, genericArgs.count == 1 else {
throw JavaTranslationError.unsupportedSwiftType(type)
}
return .placeholder
return try self.translateArrayResult(elementType: genericArgs[0])

default:
throw JavaTranslationError.unsupportedSwiftType(type)
}
}

Expand All @@ -228,11 +265,32 @@ extension JNISwift2JavaGenerator {
case .optional(let wrappedType):
return try self.translateOptionalResult(wrappedType: wrappedType, methodName: methodName)

case .genericParameter, .function, .metatype, .tuple, .existential, .opaque, .composite, .array:
case .array(let elementType):
return try self.translateArrayResult(elementType: elementType)

case .genericParameter, .function, .metatype, .tuple, .existential, .opaque, .composite:
throw JavaTranslationError.unsupportedSwiftType(type)
}
}

private func translateArrayResult(elementType: SwiftType) throws -> UpcallConversionStep {
switch elementType {
case .nominal(let nominalType):
// We assume this is a JExtracted type
return .map(
.placeholder,
body: .toSwiftClass(
.unwrapOptional(.placeholder, message: "Element of array was nil"),
name: "arrayElement",
nominalType: nominalType
)
)

case .array, .composite, .existential, .function, .genericParameter, .metatype, .opaque, .optional, .tuple:
throw JavaTranslationError.unsupportedSwiftType(.array(elementType))
}
}

private func translateOptionalResult(wrappedType: SwiftType, methodName: String) throws -> UpcallConversionStep {
// The `fromJavaOptional` will handle the nullability
let wrappedConversion = try translateResult(
Expand Down Expand Up @@ -340,3 +398,31 @@ extension JNISwift2JavaGenerator {
}
}
}

extension SwiftType {
/// Indicates whether this type is translated by `wrap-java`
/// into the same type as `jextract`.
///
/// This means we do not have to perform any mapping when passing
/// this type between jextract and wrap-java
var isDirectlyTranslatedToWrapJava: Bool {
switch self {
case .nominal(let swiftNominalType):
guard let knownType = swiftNominalType.nominalTypeDecl.knownTypeKind else {
return false
}
switch knownType {
case .bool, .int, .uint, .int8, .uint8, .int16, .uint16, .int32, .uint32, .int64, .uint64, .float, .double, .string, .void:
return true
default:
return false
}

case .array(let elementType):
return elementType.isDirectlyTranslatedToWrapJava

case .genericParameter, .function, .metatype, .optional, .tuple, .existential, .opaque, .composite:
return false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,8 @@ extension JNISwift2JavaGenerator {
conversion.render(&printer, param.parameterName!)
}

let javaUpcall = "\(wrapper.javaInterfaceVariableName).\(function.swiftFunctionName)(\(upcallArguments.joined(separator: ", ")))"
let tryClause = function.originalFunctionSignature.isThrowing ? "try " : ""
let javaUpcall = "\(tryClause)\(wrapper.javaInterfaceVariableName).\(function.swiftFunctionName)(\(upcallArguments.joined(separator: ", ")))"

let resultType = function.originalFunctionSignature.result.type
let result = function.resultConversion.render(&printer, javaUpcall)
Expand Down
Loading