Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift.org project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Swift.org project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

public func optionalBool(input: Optional<Bool>) -> Bool? {
return input
}

public func optionalByte(input: Optional<Int8>) -> Int8? {
return input
}

public func optionalChar(input: Optional<UInt16>) -> UInt16? {
return input
}

public func optionalShort(input: Optional<Int16>) -> Int16? {
return input
}

public func optionalInt(input: Optional<Int32>) -> Int32? {
return input
}

public func optionalLong(input: Optional<Int64>) -> Int64? {
return input
}

public func optionalFloat(input: Optional<Float>) -> Float? {
return input
}

public func optionalDouble(input: Optional<Double>) -> Double? {
return input
}

public func optionalString(input: Optional<String>) -> String? {
return input
}

public func optionalClass(input: Optional<MySwiftClass>) -> MySwiftClass? {
return input
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
import org.junit.jupiter.api.Test;
import org.swift.swiftkit.core.ConfinedSwiftMemorySession;

import java.util.Optional;
import java.util.OptionalInt;
import java.util.OptionalLong;

import static org.junit.jupiter.api.Assertions.*;

public class MySwiftClassTest {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift.org project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Swift.org project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

package com.example.swift;

import org.junit.jupiter.api.Test;
import org.swift.swiftkit.core.ConfinedSwiftMemorySession;

import java.util.Optional;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.OptionalLong;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class OptionalsTest {
@Test
void optionalBool() {
assertEquals(Optional.empty(), MySwiftLibrary.optionalBool(Optional.empty()));
assertEquals(Optional.of(true), MySwiftLibrary.optionalBool(Optional.of(true)));
}

@Test
void optionalByte() {
assertEquals(Optional.empty(), MySwiftLibrary.optionalByte(Optional.empty()));
assertEquals(Optional.of((byte) 1) , MySwiftLibrary.optionalByte(Optional.of((byte) 1)));
}

@Test
void optionalChar() {
assertEquals(Optional.empty(), MySwiftLibrary.optionalChar(Optional.empty()));
assertEquals(Optional.of((char) 42), MySwiftLibrary.optionalChar(Optional.of((char) 42)));
}

@Test
void optionalShort() {
assertEquals(Optional.empty(), MySwiftLibrary.optionalShort(Optional.empty()));
assertEquals(Optional.of((short) -250), MySwiftLibrary.optionalShort(Optional.of((short) -250)));
}

@Test
void optionalInt() {
assertEquals(OptionalInt.empty(), MySwiftLibrary.optionalInt(OptionalInt.empty()));
assertEquals(OptionalInt.of(999), MySwiftLibrary.optionalInt(OptionalInt.of(999)));
}

@Test
void optionalLong() {
assertEquals(OptionalLong.empty(), MySwiftLibrary.optionalLong(OptionalLong.empty()));
assertEquals(OptionalLong.of(999), MySwiftLibrary.optionalLong(OptionalLong.of(999)));
}

@Test
void optionalFloat() {
assertEquals(Optional.empty(), MySwiftLibrary.optionalFloat(Optional.empty()));
assertEquals(Optional.of(3.14f), MySwiftLibrary.optionalFloat(Optional.of(3.14f)));
}

@Test
void optionalDouble() {
assertEquals(OptionalDouble.empty(), MySwiftLibrary.optionalDouble(OptionalDouble.empty()));
assertEquals(OptionalDouble.of(2.718), MySwiftLibrary.optionalDouble(OptionalDouble.of(2.718)));
}

@Test
void optionalString() {
assertEquals(Optional.empty(), MySwiftLibrary.optionalString(Optional.empty()));
assertEquals(Optional.of("Hello Swift!"), MySwiftLibrary.optionalString(Optional.of("Hello Swift!")));
}

@Test
void optionalClass() {
try (var arena = new ConfinedSwiftMemorySession()) {
MySwiftClass c = MySwiftClass.init(arena);
assertEquals(Optional.empty(), MySwiftLibrary.optionalClass(Optional.empty(), arena));
Optional<MySwiftClass> optionalClass = MySwiftLibrary.optionalClass(Optional.of(c), arena);
assertTrue(optionalClass.isPresent());
assertEquals(c.getX(), optionalClass.get().getX());
}
}
}
10 changes: 10 additions & 0 deletions Sources/JExtractSwiftLib/Convenience/JavaType+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,14 @@ extension JavaType {
case .void: fatalError("There is no type signature for 'void'")
}
}

/// Returns the next integral type with space for self and an additional byte.
var nextIntergralTypeWithSpaceForByte: (java: JavaType, swift: String, valueBytes: Int)? {
switch self {
case .boolean, .byte: (.short, "Int16", 1)
case .char, .short: (.int, "Int32", 2)
case .int: (.long, "Int64", 4)
default: nil
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//

import JavaTypes

// MARK: Defaults

Expand All @@ -20,6 +21,7 @@ extension JNISwift2JavaGenerator {
static let defaultJavaImports: Array<String> = [
"org.swift.swiftkit.core.*",
"org.swift.swiftkit.core.util.*",
"java.util.*",

// NonNull, Unsigned and friends
"org.swift.swiftkit.core.annotations.*",
Expand Down Expand Up @@ -276,11 +278,15 @@ extension JNISwift2JavaGenerator {
let translatedDecl = translatedDecl(for: decl)! // Will always call with valid decl
let nativeSignature = translatedDecl.nativeFunctionSignature
let resultType = nativeSignature.result.javaType
var parameters = nativeSignature.parameters
if let selfParameter = nativeSignature.selfParameter {
parameters.append(selfParameter)
var parameters = nativeSignature.parameters.flatMap(\.parameters)
if let selfParameter = nativeSignature.selfParameter?.parameters {
parameters += selfParameter
}
let renderedParameters = parameters.map { "\($0.javaType) \($0.name)"}.joined(separator: ", ")
parameters += nativeSignature.result.outParameters

let renderedParameters = parameters.map { javaParameter in
"\(javaParameter.type) \(javaParameter.name)"
}.joined(separator: ", ")

printer.print("private static native \(resultType) \(translatedDecl.nativeFunctionName)(\(renderedParameters));")
}
Expand All @@ -305,6 +311,12 @@ extension JNISwift2JavaGenerator {
arguments.append(lowered)
}

// Indirect return receivers
for outParameter in translatedFunctionSignature.resultType.outParameters {
printer.print("\(outParameter.type) \(outParameter.name) = \(outParameter.allocation.render());")
arguments.append(outParameter.name)
}

//=== Part 3: Downcall.
// TODO: If we always generate a native method and a "public" method, we can actually choose our own thunk names
// using the registry?
Expand Down
Loading
Loading