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
@@ -0,0 +1,33 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

public struct MySwiftStruct {
private var cap: Int64
public var len: Int64

public init(cap: Int64, len: Int64) {
self.cap = cap
self.len = len
}

public func getCapacity() -> Int64 {
self.cap
}

public mutating func increaseCap(by value: Int64) -> Int64 {
precondition(value > 0)
self.cap += value
return self.cap
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ static void examples() {
} catch (Exception e) {
System.out.println("Caught exception: " + e.getMessage());
}

MySwiftStruct myStruct = MySwiftStruct.init(12, 34, arena);
System.out.println("myStruct.cap: " + myStruct.getCapacity());
System.out.println("myStruct.len: " + myStruct.getLen());
myStruct.increaseCap(10);
System.out.println("myStruct.cap after increase: " + myStruct.getCapacity());
}

System.out.println("DONE.");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//===----------------------------------------------------------------------===//
//
// 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 static org.junit.jupiter.api.Assertions.*;

public class MySwiftStructTest {
@Test
void init() {
try (var arena = new ConfinedSwiftMemorySession()) {
MySwiftStruct s = MySwiftStruct.init(1337, 42, arena);
assertEquals(1337, s.getCapacity());
assertEquals(42, s.getLen());
}
}

@Test
void getAndSetLen() {
try (var arena = new ConfinedSwiftMemorySession()) {
MySwiftStruct s = MySwiftStruct.init(1337, 42, arena);
s.setLen(100);
assertEquals(100, s.getLen());
}
}

@Test
void increaseCap() {
try (var arena = new ConfinedSwiftMemorySession()) {
MySwiftStruct s = MySwiftStruct.init(1337, 42, arena);
long newCap = s.increaseCap(10);
assertEquals(1347, newCap);
assertEquals(1347, s.getCapacity());
}
}
}
188 changes: 188 additions & 0 deletions Tests/JExtractSwiftTests/JNI/JNIStructTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

import JExtractSwiftLib
import Testing

@Suite
struct JNIStructTests {
let source = """
public struct MyStruct {
let x: Int64
let y: Int64

public init(x: Int64, y: Int64) {
self.x = y
self.y = y
}

public func doSomething(x: Int64) {}
}
"""

@Test
func generatesJavaClass() throws {
try assertOutput(input: source, .jni, .java, expectedChunks: [
"""
// Generated by jextract-swift
// Swift module: SwiftModule

package com.example.swift;

import org.swift.swiftkit.core.*;
import org.swift.swiftkit.core.util.*;

public final class MyStruct extends JNISwiftInstance {
static final String LIB_NAME = "SwiftModule";

@SuppressWarnings("unused")
private static final boolean INITIALIZED_LIBS = initializeLibs();
static boolean initializeLibs() {
System.loadLibrary(LIB_NAME);
return true;
}

public MyStruct(long selfPointer, SwiftArena swiftArena) {
super(selfPointer, swiftArena);
}
""",
"""
private static native void $destroy(long selfPointer);
""",
"""
@Override
protected Runnable $createDestroyFunction() {
long $selfPointer = this.pointer();
return new Runnable() {
@Override
public void run() {
MyStruct.$destroy($selfPointer);
}
};
}
"""
])
}

@Test
func initializer_javaBindings() throws {
try assertOutput(
input: source,
.jni,
.java,
expectedChunks: [
"""
/**
* Downcall to Swift:
* {@snippet lang=swift :
* public init(x: Int64, y: Int64)
* }
*/
public static MyStruct init(long x, long y, SwiftArena swiftArena$) {
long selfPointer = MyStruct.allocatingInit(x, y);
return new MyStruct(selfPointer, swiftArena$);
}
""",
"""
private static native long allocatingInit(long x, long y);
""",
]
)
}

@Test
func initializer_swiftThunks() throws {
try assertOutput(
input: source,
.jni,
.swift,
detectChunkByInitialLines: 1,
expectedChunks: [
"""
@_cdecl("Java_com_example_swift_MyStruct_allocatingInit__JJ")
func Java_com_example_swift_MyStruct_allocatingInit__JJ(environment: UnsafeMutablePointer<JNIEnv?>!, thisClass: jclass, x: jlong, y: jlong) -> jlong {
let selfPointer = UnsafeMutablePointer<MyStruct>.allocate(capacity: 1)
selfPointer.initialize(to: MyStruct(x: Int64(fromJNI: x, in: environment!), y: Int64(fromJNI: y, in: environment!)))
return Int64(Int(bitPattern: selfPointer)).getJNIValue(in: environment)
}
"""
]
)
}

@Test
func destroyFunction_swiftThunks() throws {
try assertOutput(
input: source,
.jni,
.swift,
detectChunkByInitialLines: 1,
expectedChunks: [
"""
@_cdecl("Java_com_example_swift_MyStruct__00024destroy__J")
func Java_com_example_swift_MyStruct__00024destroy__J(environment: UnsafeMutablePointer<JNIEnv?>!, thisClass: jclass, selfPointer: jlong) {
let pointer = UnsafeMutablePointer<MyStruct>(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))!
pointer.deinitialize(count: 1)
pointer.deallocate()
}
"""
]
)
}

@Test
func memberMethod_javaBindings() throws {
try assertOutput(
input: source,
.jni,
.java,
expectedChunks: [
"""
/**
* Downcall to Swift:
* {@snippet lang=swift :
* public func doSomething(x: Int64)
* }
*/
public void doSomething(long x) {
long selfPointer = this.pointer();
MyStruct.$doSomething(x, selfPointer);
}
""",
"""
private static native void $doSomething(long x, long selfPointer);
"""
]
)
}

@Test
func memberMethod_swiftThunks() throws {
try assertOutput(
input: source,
.jni,
.swift,
detectChunkByInitialLines: 1,
expectedChunks: [
"""
@_cdecl("Java_com_example_swift_MyStruct__00024doSomething__JJ")
func Java_com_example_swift_MyStruct__00024doSomething__JJ(environment: UnsafeMutablePointer<JNIEnv?>!, thisClass: jclass, x: jlong, selfPointer: jlong) {
let self$ = UnsafeMutablePointer<MyStruct>(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))!
self$.pointee.doSomething(x: Int64(fromJNI: x, in: environment!))
}
""",
]
)
}
}
Loading