Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
4 changes: 4 additions & 0 deletions packages/pigeon/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 25.2.0

* [kotlin] Adds equality methods to generated data classes.

## 25.1.0

* [dart] Adds equality methods to generated data classes.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ data class IntEvent(val data: Long) : PlatformEvent() {
data,
)
}

override fun equals(other: Any?): Boolean {
if (other !is IntEvent) {
return false
}
if (this === other) {
return true
}
return data == other.data
}

override fun hashCode(): Int = toList().hashCode()
}

/** Generated class from Pigeon that represents data sent in messages. */
Expand All @@ -47,6 +59,18 @@ data class StringEvent(val data: String) : PlatformEvent() {
data,
)
}

override fun equals(other: Any?): Boolean {
if (other !is StringEvent) {
return false
}
if (this === other) {
return true
}
return data == other.data
}

override fun hashCode(): Int = toList().hashCode()
}

private open class EventChannelMessagesPigeonCodec : StandardMessageCodec() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,29 @@ class FlutterError(
val details: Any? = null
) : Throwable()

private fun deepEqualsMessages(a: Any?, b: Any?): Boolean {
if (a is ByteArray && b is ByteArray) {
return a.contentEquals(b)
}
if (a is IntArray && b is IntArray) {
return a.contentEquals(b)
}
if (a is LongArray && b is LongArray) {
return a.contentEquals(b)
}
if (a is DoubleArray && b is DoubleArray) {
return a.contentEquals(b)
}
if (a is Array<*> && b is Array<*>) {
return a.size == b.size && a.indices.all { deepEqualsMessages(a[it], b[it]) }
}
if (a is Map<*, *> && b is Map<*, *>) {
return a.size == b.size &&
a.keys.all { (b as Map<Any?, Any?>).containsKey(it) && deepEqualsMessages(a[it], b[it]) }
}
return a == b
}

enum class Code(val raw: Int) {
ONE(0),
TWO(1);
Expand Down Expand Up @@ -82,6 +105,21 @@ data class MessageData(
data,
)
}

override fun equals(other: Any?): Boolean {
if (other !is MessageData) {
return false
}
if (this === other) {
return true
}
return name == other.name &&
description == other.description &&
code == other.code &&
deepEqualsMessages(data, other.data)
}

override fun hashCode(): Int = toList().hashCode()
}

private open class MessagesPigeonCodec : StandardMessageCodec() {
Expand Down
6 changes: 4 additions & 2 deletions packages/pigeon/lib/src/dart/dart_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1091,8 +1091,10 @@ final BinaryMessenger? ${varNamePrefix}binaryMessenger;
if (root.classes.isNotEmpty &&
root.classes.any((Class dataClass) => dataClass.fields.any(
(NamedType field) =>
field.type.baseName.startsWith('List') ||
field.type.baseName.startsWith('Map')))) {
!field.type.isClass &&
!field.type.isEnum &&
(field.type.baseName.contains('List') ||
field.type.baseName.startsWith('Map'))))) {
_writeDeepEquals(indent);
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/pigeon/lib/src/generator_tools.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import 'ast.dart';
/// The current version of pigeon.
///
/// This must match the version in pubspec.yaml.
const String pigeonVersion = '25.1.0';
const String pigeonVersion = '25.2.0';

/// Read all the content from [stdin] to a String.
String readStdin() {
Expand Down
79 changes: 78 additions & 1 deletion packages/pigeon/lib/src/kotlin/kotlin_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -291,9 +291,48 @@ class KotlinGenerator extends StructuredGenerator<InternalKotlinOptions> {
classDefinition,
dartPackageName: dartPackageName,
);
writeClassEquality(
generatorOptions,
root,
indent,
classDefinition,
dartPackageName: dartPackageName,
);
});
}

@override
void writeClassEquality(
InternalKotlinOptions generatorOptions,
Root root,
Indent indent,
Class classDefinition, {
required String dartPackageName,
}) {
indent.writeScoped('override fun equals(other: Any?): Boolean {', '}', () {
indent.writeScoped('if (other !is ${classDefinition.name}) {', '}', () {
indent.writeln('return false');
});
indent.writeScoped('if (this === other) {', '}', () {
indent.writeln('return true');
});
indent.write('return ');
indent.format(classDefinition.fields
.map((NamedType field) => field.type.baseName == 'List' ||
field.type.baseName == 'Float64List' ||
field.type.baseName == 'Int32List' ||
field.type.baseName == 'Int64List' ||
field.type.baseName == 'Uint8List' ||
field.type.baseName == 'Map'
? 'deepEquals${generatorOptions.fileSpecificClassNameComponent}(${field.name}, other.${field.name})'
: '${field.name} == other.${field.name}')
.join('\n&& '));
});

indent.newln();
indent.writeln('override fun hashCode(): Int = toList().hashCode()');
}

void _writeDataClassSignature(
Indent indent,
Class classDefinition, {
Expand Down Expand Up @@ -507,7 +546,7 @@ class KotlinGenerator extends StructuredGenerator<InternalKotlinOptions> {
indent.newln();
if (root.containsEventChannel) {
indent.writeln(
'val ${generatorOptions.fileSpecificClassNameComponent}$_pigeonMethodChannelCodec = StandardMethodCodec(${generatorOptions.fileSpecificClassNameComponent}$_codecName());');
'val ${generatorOptions.fileSpecificClassNameComponent}$_pigeonMethodChannelCodec = StandardMethodCodec(${generatorOptions.fileSpecificClassNameComponent}$_codecName())');
indent.newln();
}
}
Expand Down Expand Up @@ -1219,6 +1258,36 @@ if (wrapped == null) {
});
}

void _writeDeepEquals(InternalKotlinOptions generatorOptions, Indent indent) {
indent.format('''
private fun deepEquals${generatorOptions.fileSpecificClassNameComponent}(a: Any?, b: Any?): Boolean {
if (a is ByteArray && b is ByteArray) {
return a.contentEquals(b)
}
if (a is IntArray && b is IntArray) {
return a.contentEquals(b)
}
if (a is LongArray && b is LongArray) {
return a.contentEquals(b)
}
if (a is DoubleArray && b is DoubleArray) {
return a.contentEquals(b)
}
if (a is Array<*> && b is Array<*>) {
return a.size == b.size &&
a.indices.all{ deepEquals${generatorOptions.fileSpecificClassNameComponent}(a[it], b[it]) }
}
if (a is Map<*, *> && b is Map<*, *>) {
return a.size == b.size && a.keys.all {
(b as Map<Any?, Any?>).containsKey(it) &&
deepEquals${generatorOptions.fileSpecificClassNameComponent}(a[it], b[it])
}
}
return a == b;
}
''');
}

@override
void writeGeneralUtilities(
InternalKotlinOptions generatorOptions,
Expand All @@ -1236,6 +1305,14 @@ if (wrapped == null) {
if (generatorOptions.includeErrorClass) {
_writeErrorClass(generatorOptions, indent);
}
if (root.classes.isNotEmpty &&
root.classes.any((Class dataClass) => dataClass.fields.any(
(NamedType field) =>
_kotlinTypeForBuiltinDartType(field.type) != null &&
(field.type.baseName.contains('List') ||
field.type.baseName.startsWith('Map'))))) {
_writeDeepEquals(generatorOptions, indent);
}
}

static void _writeMethodDeclaration(
Expand Down
Loading