Skip to content

JNI: support Swift Range parameters and results - #15

Closed
teamhimeh wants to merge 1 commit into
qoncept-forkfrom
codex/jni-range
Closed

teamhimeh wants to merge 1 commit into
qoncept-forkfrom
codex/jni-range

Conversation

@teamhimeh

Copy link
Copy Markdown
Collaborator

Problem

JNI extraction does not expose APIs using Swift's half-open Range<Bound>: the built-in Swift type catalog and JNI conversions have no range mapping.

For example:

public func int64Range(_ range: Range<Int64>) -> Range<Int64> {
  range
}

With this change, Java callers can construct a range, pass it to Swift, and read its bounds:

SwiftRange<Long> range = MySwiftLibrary.int64Range(new SwiftRange<>(-5L, 10L));
long lower = range.getLowerBound(); // -5, inclusive
long upper = range.getUpperBound(); // 10, exclusive

Equal bounds represent an empty range. Invalid bounds are rejected before constructing a Swift range or calling the target function.

Changes

  • Recognize Swift.Range and its bound type in the Swift type catalog and JNI generator.
  • Add an immutable org.swift.swiftkit.core.SwiftRange<T> Java container and copy bounds through the existing JobjectBridge conversions.
  • Check erased Java bound types and validate ordering using Swift's Comparable. Java's comparison rules can differ, and wrappers of Swift-comparable types need not implement Java's Comparable.
  • Return IllegalArgumentException for invalid types, reversed bounds, and unordered floating-point bounds. Reject null ranges and constructor bounds with NullPointerException. Stop argument conversion immediately when range conversion posts a Java exception.
  • Preserve unsigned-bound annotations and document the representation, lifetime rules, and supported scope.
  • Add generator regressions and Java runtime coverage for signed and unsigned integers, floating-point values, strings, custom Swift-comparable bounds, empty ranges, half-open endpoints, and invalid inputs.

Scope

This adds direct JNI range parameters and results with concrete, bridgeable bound types. The Java container itself requires no SwiftArena; bounds wrapping Swift objects retain their usual lifetime requirements.

FFM, ClosedRange, partial ranges, Optional/collection nesting, tuple parameters containing ranges, and protocol callback conversions remain outside this feature. This does not add unrestricted generic-bound API support.

Validation

  • swift test --disable-sandbox --disable-experimental-prebuilts --filter 'JExtractSwiftTests|SwiftExtractTests': all 642 extraction and generator tests passed.
  • ./gradlew :Samples:SwiftJavaExtractJNISampleApp:test: all 307 Java tests passed with no failures or skips, including 11 new range tests. Runtime coverage includes Int, Int32, Int64, UInt64, Double, String, and a custom Swift-comparable struct.
  • Verified Swift string comparison using canonically equivalent bounds that compare differently in Java, and verified Java exceptions for invalid ranges with object, primitive, and void return types.
  • swift format lint --strict on changed Swift files and git diff --check passed.

Tested with Apple Swift 6.4 and JetBrains Runtime 25.0.2 on macOS.

@teamhimeh teamhimeh closed this Oct 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant