Skip to content

Commit b2f527e

Browse files
committed
Add generic equals method
1 parent b96f649 commit b2f527e

5 files changed

Lines changed: 127 additions & 0 deletions

File tree

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2026 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+
public class EquatableClass: Equatable {
16+
public let value: Int
17+
public init(value: Int) {
18+
self.value = value
19+
}
20+
21+
public static func == (lhs: EquatableClass, rhs: EquatableClass) -> Bool {
22+
lhs.value == rhs.value
23+
}
24+
}
25+
26+
public class EquatableSubclass: EquatableClass {
27+
public override init(value: Int) {
28+
super.init(value: value)
29+
}
30+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2026 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+
package com.example.swift;
16+
17+
import org.junit.jupiter.api.Test;
18+
import org.swift.swiftkit.core.SwiftArena;
19+
20+
import static org.junit.jupiter.api.Assertions.*;
21+
22+
@SuppressWarnings({"AssertBetweenInconvertibleTypes", "EqualsWithItself"})
23+
public class EquatableTest {
24+
@Test
25+
void genericStructType() {
26+
try (var arena = SwiftArena.ofConfined()) {
27+
var a = MyIDs.makeIntID(42, arena);
28+
var b = MyIDs.makeIntID(42, arena);
29+
var c = MyIDs.makeIntID(0, arena);
30+
var d = MyIDs.makeStringID("42", arena);
31+
assertEquals(a, a);
32+
assertEquals(a, b);
33+
assertNotEquals(a, c);
34+
assertNotEquals(a, d);
35+
assertNotEquals("foo", a);
36+
}
37+
}
38+
39+
@Test
40+
void classType() {
41+
try (var arena = SwiftArena.ofConfined()) {
42+
var a = EquatableClass.init(42, arena);
43+
var b = EquatableSubclass.init(42, arena);
44+
var c = EquatableSubclass.init(0, arena);
45+
assertEquals(a, b);
46+
assertEquals(b, a);
47+
assertEquals(b, b);
48+
assertNotEquals(a, c);
49+
assertNotEquals(b, c);
50+
}
51+
}
52+
}

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,13 @@ extension JNISwift2JavaGenerator {
373373

374374
printer.print(
375375
"""
376+
public boolean equals(Object obj) {
377+
if (obj instanceof JNISwiftInstance rhs) {
378+
return SwiftObjects.equals(this.$memoryAddress(), this.$typeMetadataAddress(), rhs.$memoryAddress(), rhs.$typeMetadataAddress());
379+
}
380+
return false;
381+
}
382+
376383
public java.lang.String toString() {
377384
return SwiftObjects.toString(this.$memoryAddress(), this.$typeMetadataAddress());
378385
}

Sources/SwiftJava/SwiftObjects.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,41 @@ extension SwiftObjects {
9898
let typeMetadata = unsafeBitCast(selfType$, to: Any.Type.self)
9999
return String(describing: typeMetadata)
100100
}
101+
102+
@JavaMethod
103+
public static func equals(environment: UnsafeMutablePointer<JNIEnv?>!, lhsPointer: Int64, lhsTypePointer: Int64, rhsPointer: Int64, rhsTypePointer: Int64) -> Bool {
104+
guard let lhsType$ = UnsafeRawPointer(bitPattern: Int(lhsTypePointer)) else {
105+
fatalError("lhsType metadata address was null")
106+
}
107+
let lhsMetatype = unsafeBitCast(lhsType$, to: Any.Type.self)
108+
guard let lhsMetatype = lhsMetatype as? (any Equatable.Type) else {
109+
return false
110+
}
111+
112+
guard let rhsType$ = UnsafeRawPointer(bitPattern: Int(rhsTypePointer)) else {
113+
fatalError("rhsType metadata address was null")
114+
}
115+
let rhsMetatype = unsafeBitCast(rhsType$, to: Any.Type.self)
116+
guard let rhsMetatype = rhsMetatype as? (any Equatable.Type) else {
117+
return false
118+
}
119+
120+
func perform<L: Equatable, R: Equatable>(lhsType: L.Type, rhsType: R.Type) -> Bool {
121+
guard let lhs$ = UnsafeMutablePointer<L>(bitPattern: Int(lhsPointer)) else {
122+
fatalError("lhs memory address was null")
123+
}
124+
guard let rhs$ = UnsafeMutablePointer<R>(bitPattern: Int(rhsPointer)) else {
125+
fatalError("rhs memory address was null")
126+
}
127+
if lhsType == rhsType {
128+
return lhs$.pointee == rhs$.pointee as! L
129+
} else if let lhs = lhs$.pointee as? R {
130+
return lhs == rhs$.pointee
131+
} else if let rhs = rhs$.pointee as? L {
132+
return lhs$.pointee == rhs
133+
}
134+
return false
135+
}
136+
return perform(lhsType: lhsMetatype, rhsType: rhsMetatype)
137+
}
101138
}

SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftObjects.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,5 @@ public static void requireNonZero(long number, String name) {
2929
public static native String toDebugString(long selfPointer, long selfTypePointer);
3030
public static native void destroy(long selfPointer, long selfTypePointer);
3131
public static native String typeDescription(long selfTypePointer);
32+
public static native boolean equals(long lhsPointer, long lhsTypePointer, long rhsPointer, long rhsTypePointer);
3233
}

0 commit comments

Comments
 (0)