Skip to content

Commit 84d0886

Browse files
committed
add kotlin equality and tests
1 parent cf9b0f2 commit 84d0886

File tree

9 files changed

+586
-63
lines changed

9 files changed

+586
-63
lines changed

packages/pigeon/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 25.2.0
2+
3+
* [kotlin] Adds equality methods to generated data classes.
4+
15
## 25.1.0
26

37
* [dart] Adds equality methods to generated data classes.

packages/pigeon/example/app/android/app/src/main/kotlin/dev/flutter/pigeon_example_app/EventChannelMessages.g.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,18 @@ data class IntEvent(val data: Long) : PlatformEvent() {
3131
data,
3232
)
3333
}
34+
35+
override fun equals(other: Any?): Boolean {
36+
if (other !is IntEvent) {
37+
return false
38+
}
39+
if (this === other) {
40+
return true
41+
}
42+
return data == other.data
43+
}
44+
45+
override fun hashCode(): Int = toList().hashCode()
3446
}
3547

3648
/** Generated class from Pigeon that represents data sent in messages. */
@@ -47,6 +59,18 @@ data class StringEvent(val data: String) : PlatformEvent() {
4759
data,
4860
)
4961
}
62+
63+
override fun equals(other: Any?): Boolean {
64+
if (other !is StringEvent) {
65+
return false
66+
}
67+
if (this === other) {
68+
return true
69+
}
70+
return data == other.data
71+
}
72+
73+
override fun hashCode(): Int = toList().hashCode()
5074
}
5175

5276
private open class EventChannelMessagesPigeonCodec : StandardMessageCodec() {

packages/pigeon/example/app/android/app/src/main/kotlin/dev/flutter/pigeon_example_app/Messages.g.kt

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,29 @@ class FlutterError(
4646
val details: Any? = null
4747
) : Throwable()
4848

49+
private fun deepEqualsMessages(a: Any?, b: Any?): Boolean {
50+
if (a is ByteArray && b is ByteArray) {
51+
return a.contentEquals(b)
52+
}
53+
if (a is IntArray && b is IntArray) {
54+
return a.contentEquals(b)
55+
}
56+
if (a is LongArray && b is LongArray) {
57+
return a.contentEquals(b)
58+
}
59+
if (a is DoubleArray && b is DoubleArray) {
60+
return a.contentEquals(b)
61+
}
62+
if (a is Array<*> && b is Array<*>) {
63+
return a.size == b.size && a.indices.all { deepEqualsMessages(a[it], b[it]) }
64+
}
65+
if (a is Map<*, *> && b is Map<*, *>) {
66+
return a.size == b.size &&
67+
a.keys.all { (b as Map<Any?, Any?>).containsKey(it) && deepEqualsMessages(a[it], b[it]) }
68+
}
69+
return a == b
70+
}
71+
4972
enum class Code(val raw: Int) {
5073
ONE(0),
5174
TWO(1);
@@ -82,6 +105,21 @@ data class MessageData(
82105
data,
83106
)
84107
}
108+
109+
override fun equals(other: Any?): Boolean {
110+
if (other !is MessageData) {
111+
return false
112+
}
113+
if (this === other) {
114+
return true
115+
}
116+
return name == other.name &&
117+
description == other.description &&
118+
code == other.code &&
119+
deepEqualsMessages(data, other.data)
120+
}
121+
122+
override fun hashCode(): Int = toList().hashCode()
85123
}
86124

87125
private open class MessagesPigeonCodec : StandardMessageCodec() {

packages/pigeon/lib/src/generator_tools.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import 'ast.dart';
1414
/// The current version of pigeon.
1515
///
1616
/// This must match the version in pubspec.yaml.
17-
const String pigeonVersion = '25.1.0';
17+
const String pigeonVersion = '25.2.0';
1818

1919
/// Read all the content from [stdin] to a String.
2020
String readStdin() {

packages/pigeon/lib/src/kotlin/kotlin_generator.dart

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,9 +291,48 @@ class KotlinGenerator extends StructuredGenerator<InternalKotlinOptions> {
291291
classDefinition,
292292
dartPackageName: dartPackageName,
293293
);
294+
writeClassEquality(
295+
generatorOptions,
296+
root,
297+
indent,
298+
classDefinition,
299+
dartPackageName: dartPackageName,
300+
);
294301
});
295302
}
296303

304+
@override
305+
void writeClassEquality(
306+
InternalKotlinOptions generatorOptions,
307+
Root root,
308+
Indent indent,
309+
Class classDefinition, {
310+
required String dartPackageName,
311+
}) {
312+
indent.writeScoped('override fun equals(other: Any?): Boolean {', '}', () {
313+
indent.writeScoped('if (other !is ${classDefinition.name}) {', '}', () {
314+
indent.writeln('return false');
315+
});
316+
indent.writeScoped('if (this === other) {', '}', () {
317+
indent.writeln('return true');
318+
});
319+
indent.write('return ');
320+
indent.format(classDefinition.fields
321+
.map((NamedType field) => field.type.baseName == 'List' ||
322+
field.type.baseName == 'Float64List' ||
323+
field.type.baseName == 'Int32List' ||
324+
field.type.baseName == 'Int64List' ||
325+
field.type.baseName == 'Uint8List' ||
326+
field.type.baseName == 'Map'
327+
? 'deepEquals${generatorOptions.fileSpecificClassNameComponent}(${field.name}, other.${field.name})'
328+
: '${field.name} == other.${field.name}')
329+
.join('\n&& '));
330+
});
331+
332+
indent.newln();
333+
indent.writeln('override fun hashCode(): Int = toList().hashCode()');
334+
}
335+
297336
void _writeDataClassSignature(
298337
Indent indent,
299338
Class classDefinition, {
@@ -507,7 +546,7 @@ class KotlinGenerator extends StructuredGenerator<InternalKotlinOptions> {
507546
indent.newln();
508547
if (root.containsEventChannel) {
509548
indent.writeln(
510-
'val ${generatorOptions.fileSpecificClassNameComponent}$_pigeonMethodChannelCodec = StandardMethodCodec(${generatorOptions.fileSpecificClassNameComponent}$_codecName());');
549+
'val ${generatorOptions.fileSpecificClassNameComponent}$_pigeonMethodChannelCodec = StandardMethodCodec(${generatorOptions.fileSpecificClassNameComponent}$_codecName())');
511550
indent.newln();
512551
}
513552
}
@@ -1219,6 +1258,36 @@ if (wrapped == null) {
12191258
});
12201259
}
12211260

1261+
void _writeDeepEquals(InternalKotlinOptions generatorOptions, Indent indent) {
1262+
indent.format('''
1263+
private fun deepEquals${generatorOptions.fileSpecificClassNameComponent}(a: Any?, b: Any?): Boolean {
1264+
if (a is ByteArray && b is ByteArray) {
1265+
return a.contentEquals(b)
1266+
}
1267+
if (a is IntArray && b is IntArray) {
1268+
return a.contentEquals(b)
1269+
}
1270+
if (a is LongArray && b is LongArray) {
1271+
return a.contentEquals(b)
1272+
}
1273+
if (a is DoubleArray && b is DoubleArray) {
1274+
return a.contentEquals(b)
1275+
}
1276+
if (a is Array<*> && b is Array<*>) {
1277+
return a.size == b.size &&
1278+
a.indices.all{ deepEquals${generatorOptions.fileSpecificClassNameComponent}(a[it], b[it]) }
1279+
}
1280+
if (a is Map<*, *> && b is Map<*, *>) {
1281+
return a.size == b.size && a.keys.all {
1282+
(b as Map<Any?, Any?>).containsKey(it) &&
1283+
deepEquals${generatorOptions.fileSpecificClassNameComponent}(a[it], b[it])
1284+
}
1285+
}
1286+
return a == b;
1287+
}
1288+
''');
1289+
}
1290+
12221291
@override
12231292
void writeGeneralUtilities(
12241293
InternalKotlinOptions generatorOptions,
@@ -1236,6 +1305,13 @@ if (wrapped == null) {
12361305
if (generatorOptions.includeErrorClass) {
12371306
_writeErrorClass(generatorOptions, indent);
12381307
}
1308+
if (root.classes.isNotEmpty &&
1309+
root.classes.any((Class dataClass) => dataClass.fields.any(
1310+
(NamedType field) =>
1311+
field.type.baseName.startsWith('List') ||
1312+
field.type.baseName.startsWith('Map')))) {
1313+
_writeDeepEquals(generatorOptions, indent);
1314+
}
12391315
}
12401316

12411317
static void _writeMethodDeclaration(

0 commit comments

Comments
 (0)