diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md index 27ebd2090661..1765e1aa63a5 100644 --- a/packages/pigeon/CHANGELOG.md +++ b/packages/pigeon/CHANGELOG.md @@ -1,3 +1,9 @@ +## 26.2.0 + +* Optimizes and improves data class equality and hashing. +* Changes hashing and equality methods to behave consistently across platforms. +* Adds equality methods to previously unsupported languages. + ## 26.1.10 * Dramatically reduces the number of File write operations sent to the operating diff --git a/packages/pigeon/example/app/android/app/src/main/java/io/flutter/plugins/Messages.java b/packages/pigeon/example/app/android/app/src/main/java/io/flutter/plugins/Messages.java index 799d468cfb1e..ebae5599bffd 100644 --- a/packages/pigeon/example/app/android/app/src/main/java/io/flutter/plugins/Messages.java +++ b/packages/pigeon/example/app/android/app/src/main/java/io/flutter/plugins/Messages.java @@ -19,14 +19,164 @@ import java.lang.annotation.Target; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; /** Generated class from Pigeon. */ @SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression", "serial"}) public class Messages { + static boolean pigeonDoubleEquals(double a, double b) { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (a == 0.0 ? 0.0 : a) == (b == 0.0 ? 0.0 : b) || (Double.isNaN(a) && Double.isNaN(b)); + } + + static boolean pigeonFloatEquals(float a, float b) { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (a == 0.0f ? 0.0f : a) == (b == 0.0f ? 0.0f : b) || (Float.isNaN(a) && Float.isNaN(b)); + } + + static int pigeonDoubleHashCode(double d) { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + if (d == 0.0) d = 0.0; + long bits = Double.doubleToLongBits(d); + return (int) (bits ^ (bits >>> 32)); + } + + static int pigeonFloatHashCode(float f) { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + if (f == 0.0f) f = 0.0f; + return Float.floatToIntBits(f); + } + + static boolean pigeonDeepEquals(Object a, Object b) { + if (a == b) { + return true; + } + if (a == null || b == null) { + return false; + } + if (a instanceof byte[] && b instanceof byte[]) { + return Arrays.equals((byte[]) a, (byte[]) b); + } + if (a instanceof int[] && b instanceof int[]) { + return Arrays.equals((int[]) a, (int[]) b); + } + if (a instanceof long[] && b instanceof long[]) { + return Arrays.equals((long[]) a, (long[]) b); + } + if (a instanceof double[] && b instanceof double[]) { + double[] da = (double[]) a; + double[] db = (double[]) b; + if (da.length != db.length) return false; + for (int i = 0; i < da.length; i++) { + if (!pigeonDoubleEquals(da[i], db[i])) { + return false; + } + } + return true; + } + if (a instanceof List && b instanceof List) { + List listA = (List) a; + List listB = (List) b; + if (listA.size() != listB.size()) { + return false; + } + for (int i = 0; i < listA.size(); i++) { + if (!pigeonDeepEquals(listA.get(i), listB.get(i))) { + return false; + } + } + return true; + } + if (a instanceof Map && b instanceof Map) { + Map mapA = (Map) a; + Map mapB = (Map) b; + if (mapA.size() != mapB.size()) { + return false; + } + for (Map.Entry entryA : mapA.entrySet()) { + Object keyA = entryA.getKey(); + Object valueA = entryA.getValue(); + boolean found = false; + for (Map.Entry entryB : mapB.entrySet()) { + Object keyB = entryB.getKey(); + if (pigeonDeepEquals(keyA, keyB)) { + Object valueB = entryB.getValue(); + if (pigeonDeepEquals(valueA, valueB)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; + } + if (a instanceof Double && b instanceof Double) { + return pigeonDoubleEquals((double) a, (double) b); + } + if (a instanceof Float && b instanceof Float) { + return pigeonFloatEquals((float) a, (float) b); + } + return a.equals(b); + } + + static int pigeonDeepHashCode(Object value) { + if (value == null) { + return 0; + } + if (value instanceof byte[]) { + return Arrays.hashCode((byte[]) value); + } + if (value instanceof int[]) { + return Arrays.hashCode((int[]) value); + } + if (value instanceof long[]) { + return Arrays.hashCode((long[]) value); + } + if (value instanceof double[]) { + double[] da = (double[]) value; + int result = 1; + for (double d : da) { + result = 31 * result + pigeonDoubleHashCode(d); + } + return result; + } + if (value instanceof List) { + int result = 1; + for (Object item : (List) value) { + result = 31 * result + pigeonDeepHashCode(item); + } + return result; + } + if (value instanceof Map) { + int result = 0; + for (Map.Entry entry : ((Map) value).entrySet()) { + result += (pigeonDeepHashCode(entry.getKey()) ^ pigeonDeepHashCode(entry.getValue())); + } + return result; + } + if (value instanceof Object[]) { + int result = 1; + for (Object item : (Object[]) value) { + result = 31 * result + pigeonDeepHashCode(item); + } + return result; + } + if (value instanceof Double) { + return pigeonDoubleHashCode((double) value); + } + if (value instanceof Float) { + return pigeonFloatHashCode((float) value); + } + return value.hashCode(); + } /** Error class for passing custom error details to Flutter via a thrown PlatformException. */ public static class FlutterError extends RuntimeException { @@ -142,15 +292,16 @@ public boolean equals(Object o) { return false; } MessageData that = (MessageData) o; - return Objects.equals(name, that.name) - && Objects.equals(description, that.description) - && code.equals(that.code) - && data.equals(that.data); + return pigeonDeepEquals(name, that.name) + && pigeonDeepEquals(description, that.description) + && pigeonDeepEquals(code, that.code) + && pigeonDeepEquals(data, that.data); } @Override public int hashCode() { - return Objects.hash(name, description, code, data); + Object[] fields = new Object[] {getClass(), name, description, code, data}; + return pigeonDeepHashCode(fields); } public static final class Builder { diff --git a/packages/pigeon/example/app/android/app/src/main/kotlin/dev/flutter/pigeon_example_app/EventChannelMessages.g.kt b/packages/pigeon/example/app/android/app/src/main/kotlin/dev/flutter/pigeon_example_app/EventChannelMessages.g.kt index e524f5d5b0cf..b1e223ea0ece 100644 --- a/packages/pigeon/example/app/android/app/src/main/kotlin/dev/flutter/pigeon_example_app/EventChannelMessages.g.kt +++ b/packages/pigeon/example/app/android/app/src/main/kotlin/dev/flutter/pigeon_example_app/EventChannelMessages.g.kt @@ -13,7 +13,33 @@ import java.io.ByteArrayOutputStream import java.nio.ByteBuffer private object EventChannelMessagesPigeonUtils { + fun doubleEquals(a: Double, b: Double): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0) 0.0 else a) == (if (b == 0.0) 0.0 else b) || (a.isNaN() && b.isNaN()) + } + + fun floatEquals(a: Float, b: Float): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0f) 0.0f else a) == (if (b == 0.0f) 0.0f else b) || (a.isNaN() && b.isNaN()) + } + + fun doubleHash(d: Double): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (d == 0.0) 0.0 else d + val bits = java.lang.Double.doubleToLongBits(normalized) + return (bits xor (bits ushr 32)).toInt() + } + + fun floatHash(f: Float): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (f == 0.0f) 0.0f else f + return java.lang.Float.floatToIntBits(normalized) + } + fun deepEquals(a: Any?, b: Any?): Boolean { + if (a === b) { + return true + } if (a is ByteArray && b is ByteArray) { return a.contentEquals(b) } @@ -24,20 +50,93 @@ private object EventChannelMessagesPigeonUtils { return a.contentEquals(b) } if (a is DoubleArray && b is DoubleArray) { - return a.contentEquals(b) + if (a.size != b.size) return false + for (i in a.indices) { + if (!doubleEquals(a[i], b[i])) return false + } + return true + } + if (a is FloatArray && b is FloatArray) { + if (a.size != b.size) return false + for (i in a.indices) { + if (!floatEquals(a[i], b[i])) return false + } + return true } if (a is Array<*> && b is Array<*>) { - return a.size == b.size && a.indices.all { deepEquals(a[it], b[it]) } + return a.contentDeepEquals(b) } if (a is List<*> && b is List<*>) { return a.size == b.size && a.indices.all { deepEquals(a[it], b[it]) } } if (a is Map<*, *> && b is Map<*, *>) { - return a.size == b.size && - a.all { (b as Map).contains(it.key) && deepEquals(it.value, b[it.key]) } + if (a.size != b.size) return false + for (entry in a) { + val key = entry.key + var found = false + for (bEntry in b) { + if (deepEquals(key, bEntry.key)) { + if (deepEquals(entry.value, bEntry.value)) { + found = true + break + } else { + return false + } + } + } + if (!found) return false + } + return true + } + if (a is Double && b is Double) { + return doubleEquals(a, b) + } + if (a is Float && b is Float) { + return floatEquals(a, b) } return a == b } + + fun deepHash(value: Any?): Int { + return when (value) { + null -> 0 + is ByteArray -> value.contentHashCode() + is IntArray -> value.contentHashCode() + is LongArray -> value.contentHashCode() + is DoubleArray -> { + var result = 1 + for (item in value) { + result = 31 * result + doubleHash(item) + } + result + } + is FloatArray -> { + var result = 1 + for (item in value) { + result = 31 * result + floatHash(item) + } + result + } + is Array<*> -> value.contentDeepHashCode() + is List<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is Map<*, *> -> { + var result = 0 + for (entry in value) { + result += (deepHash(entry.key) xor deepHash(entry.value)) + } + result + } + is Double -> doubleHash(value) + is Float -> floatHash(value) + else -> value.hashCode() + } + } } /** @@ -61,16 +160,21 @@ data class IntEvent(val data: Long) : PlatformEvent() { } override fun equals(other: Any?): Boolean { - if (other !is IntEvent) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return EventChannelMessagesPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as IntEvent + return EventChannelMessagesPigeonUtils.deepEquals(this.data, other.data) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + EventChannelMessagesPigeonUtils.deepHash(this.data) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -89,16 +193,21 @@ data class StringEvent(val data: String) : PlatformEvent() { } override fun equals(other: Any?): Boolean { - if (other !is StringEvent) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return EventChannelMessagesPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as StringEvent + return EventChannelMessagesPigeonUtils.deepEquals(this.data, other.data) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + EventChannelMessagesPigeonUtils.deepHash(this.data) + return result + } } private open class EventChannelMessagesPigeonCodec : StandardMessageCodec() { diff --git a/packages/pigeon/example/app/android/app/src/main/kotlin/dev/flutter/pigeon_example_app/Messages.g.kt b/packages/pigeon/example/app/android/app/src/main/kotlin/dev/flutter/pigeon_example_app/Messages.g.kt index 87f4ef1acf12..237faf549401 100644 --- a/packages/pigeon/example/app/android/app/src/main/kotlin/dev/flutter/pigeon_example_app/Messages.g.kt +++ b/packages/pigeon/example/app/android/app/src/main/kotlin/dev/flutter/pigeon_example_app/Messages.g.kt @@ -35,7 +35,33 @@ private object MessagesPigeonUtils { } } + fun doubleEquals(a: Double, b: Double): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0) 0.0 else a) == (if (b == 0.0) 0.0 else b) || (a.isNaN() && b.isNaN()) + } + + fun floatEquals(a: Float, b: Float): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0f) 0.0f else a) == (if (b == 0.0f) 0.0f else b) || (a.isNaN() && b.isNaN()) + } + + fun doubleHash(d: Double): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (d == 0.0) 0.0 else d + val bits = java.lang.Double.doubleToLongBits(normalized) + return (bits xor (bits ushr 32)).toInt() + } + + fun floatHash(f: Float): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (f == 0.0f) 0.0f else f + return java.lang.Float.floatToIntBits(normalized) + } + fun deepEquals(a: Any?, b: Any?): Boolean { + if (a === b) { + return true + } if (a is ByteArray && b is ByteArray) { return a.contentEquals(b) } @@ -46,20 +72,93 @@ private object MessagesPigeonUtils { return a.contentEquals(b) } if (a is DoubleArray && b is DoubleArray) { - return a.contentEquals(b) + if (a.size != b.size) return false + for (i in a.indices) { + if (!doubleEquals(a[i], b[i])) return false + } + return true + } + if (a is FloatArray && b is FloatArray) { + if (a.size != b.size) return false + for (i in a.indices) { + if (!floatEquals(a[i], b[i])) return false + } + return true } if (a is Array<*> && b is Array<*>) { - return a.size == b.size && a.indices.all { deepEquals(a[it], b[it]) } + return a.contentDeepEquals(b) } if (a is List<*> && b is List<*>) { return a.size == b.size && a.indices.all { deepEquals(a[it], b[it]) } } if (a is Map<*, *> && b is Map<*, *>) { - return a.size == b.size && - a.all { (b as Map).contains(it.key) && deepEquals(it.value, b[it.key]) } + if (a.size != b.size) return false + for (entry in a) { + val key = entry.key + var found = false + for (bEntry in b) { + if (deepEquals(key, bEntry.key)) { + if (deepEquals(entry.value, bEntry.value)) { + found = true + break + } else { + return false + } + } + } + if (!found) return false + } + return true + } + if (a is Double && b is Double) { + return doubleEquals(a, b) + } + if (a is Float && b is Float) { + return floatEquals(a, b) } return a == b } + + fun deepHash(value: Any?): Int { + return when (value) { + null -> 0 + is ByteArray -> value.contentHashCode() + is IntArray -> value.contentHashCode() + is LongArray -> value.contentHashCode() + is DoubleArray -> { + var result = 1 + for (item in value) { + result = 31 * result + doubleHash(item) + } + result + } + is FloatArray -> { + var result = 1 + for (item in value) { + result = 31 * result + floatHash(item) + } + result + } + is Array<*> -> value.contentDeepHashCode() + is List<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is Map<*, *> -> { + var result = 0 + for (entry in value) { + result += (deepHash(entry.key) xor deepHash(entry.value)) + } + result + } + is Double -> doubleHash(value) + is Float -> floatHash(value) + else -> value.hashCode() + } + } } /** @@ -113,16 +212,27 @@ data class MessageData( } override fun equals(other: Any?): Boolean { - if (other !is MessageData) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return MessagesPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as MessageData + return MessagesPigeonUtils.deepEquals(this.name, other.name) && + MessagesPigeonUtils.deepEquals(this.description, other.description) && + MessagesPigeonUtils.deepEquals(this.code, other.code) && + MessagesPigeonUtils.deepEquals(this.data, other.data) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + MessagesPigeonUtils.deepHash(this.name) + result = 31 * result + MessagesPigeonUtils.deepHash(this.description) + result = 31 * result + MessagesPigeonUtils.deepHash(this.code) + result = 31 * result + MessagesPigeonUtils.deepHash(this.data) + return result + } } private open class MessagesPigeonCodec : StandardMessageCodec() { diff --git a/packages/pigeon/example/app/ios/Runner/EventChannelMessages.g.swift b/packages/pigeon/example/app/ios/Runner/EventChannelMessages.g.swift index 027453c3951e..d60e3fd1663a 100644 --- a/packages/pigeon/example/app/ios/Runner/EventChannelMessages.g.swift +++ b/packages/pigeon/example/app/ios/Runner/EventChannelMessages.g.swift @@ -23,6 +23,19 @@ private func nilOrValue(_ value: Any?) -> T? { return value as! T? } +private func doubleEqualsEventChannelMessages(_ lhs: Double, _ rhs: Double) -> Bool { + return (lhs.isNaN && rhs.isNaN) || lhs == rhs +} + +private func doubleHashEventChannelMessages(_ value: Double, _ hasher: inout Hasher) { + if value.isNaN { + hasher.combine(0x7FF8_0000_0000_0000) + } else { + // Normalize -0.0 to 0.0 + hasher.combine(value == 0 ? 0 : value) + } +} + func deepEqualsEventChannelMessages(_ lhs: Any?, _ rhs: Any?) -> Bool { let cleanLhs = nilOrValue(lhs) as Any? let cleanRhs = nilOrValue(rhs) as Any? @@ -33,56 +46,90 @@ func deepEqualsEventChannelMessages(_ lhs: Any?, _ rhs: Any?) -> Bool { case (nil, _), (_, nil): return false - case is (Void, Void): + case (let lhs as AnyObject, let rhs as AnyObject) where lhs === rhs: return true - case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable): - return cleanLhsHashable == cleanRhsHashable + case is (Void, Void): + return true - case let (cleanLhsArray, cleanRhsArray) as ([Any?], [Any?]): - guard cleanLhsArray.count == cleanRhsArray.count else { return false } - for (index, element) in cleanLhsArray.enumerated() { - if !deepEqualsEventChannelMessages(element, cleanRhsArray[index]) { + case (let lhsArray, let rhsArray) as ([Any?], [Any?]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !deepEqualsEventChannelMessages(element, rhsArray[index]) { return false } } return true - case let (cleanLhsDictionary, cleanRhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): - guard cleanLhsDictionary.count == cleanRhsDictionary.count else { return false } - for (key, cleanLhsValue) in cleanLhsDictionary { - guard cleanRhsDictionary.index(forKey: key) != nil else { return false } - if !deepEqualsEventChannelMessages(cleanLhsValue, cleanRhsDictionary[key]!) { + case (let lhsArray, let rhsArray) as ([Double], [Double]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !doubleEqualsEventChannelMessages(element, rhsArray[index]) { return false } } return true + case (let lhsDictionary, let rhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): + guard lhsDictionary.count == rhsDictionary.count else { return false } + for (lhsKey, lhsValue) in lhsDictionary { + var found = false + for (rhsKey, rhsValue) in rhsDictionary { + if deepEqualsEventChannelMessages(lhsKey, rhsKey) { + if deepEqualsEventChannelMessages(lhsValue, rhsValue) { + found = true + break + } else { + return false + } + } + } + if !found { return false } + } + return true + + case (let lhs as Double, let rhs as Double): + return doubleEqualsEventChannelMessages(lhs, rhs) + + case (let lhsHashable, let rhsHashable) as (AnyHashable, AnyHashable): + return lhsHashable == rhsHashable + default: - // Any other type shouldn't be able to be used with pigeon. File an issue if you find this to be untrue. return false } } func deepHashEventChannelMessages(value: Any?, hasher: inout Hasher) { - if let valueList = value as? [AnyHashable] { - for item in valueList { deepHashEventChannelMessages(value: item, hasher: &hasher) } - return - } - - if let valueDict = value as? [AnyHashable: AnyHashable] { - for key in valueDict.keys { - hasher.combine(key) - deepHashEventChannelMessages(value: valueDict[key]!, hasher: &hasher) + let cleanValue = nilOrValue(value) as Any? + if let cleanValue = cleanValue { + if let doubleValue = cleanValue as? Double { + doubleHashEventChannelMessages(doubleValue, &hasher) + } else if let valueList = cleanValue as? [Any?] { + for item in valueList { + deepHashEventChannelMessages(value: item, hasher: &hasher) + } + } else if let valueList = cleanValue as? [Double] { + for item in valueList { + doubleHashEventChannelMessages(item, &hasher) + } + } else if let valueDict = cleanValue as? [AnyHashable: Any?] { + var result = 0 + for (key, value) in valueDict { + var entryKeyHasher = Hasher() + deepHashEventChannelMessages(value: key, hasher: &entryKeyHasher) + var entryValueHasher = Hasher() + deepHashEventChannelMessages(value: value, hasher: &entryValueHasher) + result = result &+ (entryKeyHasher.finalize() ^ entryValueHasher.finalize()) + } + hasher.combine(result) + } else if let hashableValue = cleanValue as? AnyHashable { + hasher.combine(hashableValue) + } else { + hasher.combine(String(describing: cleanValue)) } - return + } else { + hasher.combine(0) } - - if let hashableValue = value as? AnyHashable { - hasher.combine(hashableValue.hashValue) - } - - return hasher.combine(String(describing: value)) } /// Generated class from Pigeon that represents data sent in messages. @@ -109,10 +156,15 @@ struct IntEvent: PlatformEvent { ] } static func == (lhs: IntEvent, rhs: IntEvent) -> Bool { - return deepEqualsEventChannelMessages(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsEventChannelMessages(lhs.data, rhs.data) } + func hash(into hasher: inout Hasher) { - deepHashEventChannelMessages(value: toList(), hasher: &hasher) + hasher.combine("IntEvent") + deepHashEventChannelMessages(value: data, hasher: &hasher) } } @@ -134,10 +186,15 @@ struct StringEvent: PlatformEvent { ] } static func == (lhs: StringEvent, rhs: StringEvent) -> Bool { - return deepEqualsEventChannelMessages(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsEventChannelMessages(lhs.data, rhs.data) } + func hash(into hasher: inout Hasher) { - deepHashEventChannelMessages(value: toList(), hasher: &hasher) + hasher.combine("StringEvent") + deepHashEventChannelMessages(value: data, hasher: &hasher) } } diff --git a/packages/pigeon/example/app/ios/Runner/Messages.g.swift b/packages/pigeon/example/app/ios/Runner/Messages.g.swift index 46c3e23598ef..40e179792c84 100644 --- a/packages/pigeon/example/app/ios/Runner/Messages.g.swift +++ b/packages/pigeon/example/app/ios/Runner/Messages.g.swift @@ -53,7 +53,7 @@ private func wrapError(_ error: Any) -> [Any?] { } return [ "\(error)", - "\(type(of: error))", + "\(Swift.type(of: error))", "Stacktrace: \(Thread.callStackSymbols)", ] } @@ -73,6 +73,19 @@ private func nilOrValue(_ value: Any?) -> T? { return value as! T? } +private func doubleEqualsMessages(_ lhs: Double, _ rhs: Double) -> Bool { + return (lhs.isNaN && rhs.isNaN) || lhs == rhs +} + +private func doubleHashMessages(_ value: Double, _ hasher: inout Hasher) { + if value.isNaN { + hasher.combine(0x7FF8_0000_0000_0000) + } else { + // Normalize -0.0 to 0.0 + hasher.combine(value == 0 ? 0 : value) + } +} + func deepEqualsMessages(_ lhs: Any?, _ rhs: Any?) -> Bool { let cleanLhs = nilOrValue(lhs) as Any? let cleanRhs = nilOrValue(rhs) as Any? @@ -83,56 +96,90 @@ func deepEqualsMessages(_ lhs: Any?, _ rhs: Any?) -> Bool { case (nil, _), (_, nil): return false - case is (Void, Void): + case (let lhs as AnyObject, let rhs as AnyObject) where lhs === rhs: return true - case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable): - return cleanLhsHashable == cleanRhsHashable + case is (Void, Void): + return true - case let (cleanLhsArray, cleanRhsArray) as ([Any?], [Any?]): - guard cleanLhsArray.count == cleanRhsArray.count else { return false } - for (index, element) in cleanLhsArray.enumerated() { - if !deepEqualsMessages(element, cleanRhsArray[index]) { + case (let lhsArray, let rhsArray) as ([Any?], [Any?]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !deepEqualsMessages(element, rhsArray[index]) { return false } } return true - case let (cleanLhsDictionary, cleanRhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): - guard cleanLhsDictionary.count == cleanRhsDictionary.count else { return false } - for (key, cleanLhsValue) in cleanLhsDictionary { - guard cleanRhsDictionary.index(forKey: key) != nil else { return false } - if !deepEqualsMessages(cleanLhsValue, cleanRhsDictionary[key]!) { + case (let lhsArray, let rhsArray) as ([Double], [Double]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !doubleEqualsMessages(element, rhsArray[index]) { return false } } return true + case (let lhsDictionary, let rhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): + guard lhsDictionary.count == rhsDictionary.count else { return false } + for (lhsKey, lhsValue) in lhsDictionary { + var found = false + for (rhsKey, rhsValue) in rhsDictionary { + if deepEqualsMessages(lhsKey, rhsKey) { + if deepEqualsMessages(lhsValue, rhsValue) { + found = true + break + } else { + return false + } + } + } + if !found { return false } + } + return true + + case (let lhs as Double, let rhs as Double): + return doubleEqualsMessages(lhs, rhs) + + case (let lhsHashable, let rhsHashable) as (AnyHashable, AnyHashable): + return lhsHashable == rhsHashable + default: - // Any other type shouldn't be able to be used with pigeon. File an issue if you find this to be untrue. return false } } func deepHashMessages(value: Any?, hasher: inout Hasher) { - if let valueList = value as? [AnyHashable] { - for item in valueList { deepHashMessages(value: item, hasher: &hasher) } - return - } - - if let valueDict = value as? [AnyHashable: AnyHashable] { - for key in valueDict.keys { - hasher.combine(key) - deepHashMessages(value: valueDict[key]!, hasher: &hasher) + let cleanValue = nilOrValue(value) as Any? + if let cleanValue = cleanValue { + if let doubleValue = cleanValue as? Double { + doubleHashMessages(doubleValue, &hasher) + } else if let valueList = cleanValue as? [Any?] { + for item in valueList { + deepHashMessages(value: item, hasher: &hasher) + } + } else if let valueList = cleanValue as? [Double] { + for item in valueList { + doubleHashMessages(item, &hasher) + } + } else if let valueDict = cleanValue as? [AnyHashable: Any?] { + var result = 0 + for (key, value) in valueDict { + var entryKeyHasher = Hasher() + deepHashMessages(value: key, hasher: &entryKeyHasher) + var entryValueHasher = Hasher() + deepHashMessages(value: value, hasher: &entryValueHasher) + result = result &+ (entryKeyHasher.finalize() ^ entryValueHasher.finalize()) + } + hasher.combine(result) + } else if let hashableValue = cleanValue as? AnyHashable { + hasher.combine(hashableValue) + } else { + hasher.combine(String(describing: cleanValue)) } - return - } - - if let hashableValue = value as? AnyHashable { - hasher.combine(hashableValue.hashValue) + } else { + hasher.combine(0) } - - return hasher.combine(String(describing: value)) } enum Code: Int { @@ -170,10 +217,20 @@ struct MessageData: Hashable { ] } static func == (lhs: MessageData, rhs: MessageData) -> Bool { - return deepEqualsMessages(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsMessages(lhs.name, rhs.name) + && deepEqualsMessages(lhs.description, rhs.description) + && deepEqualsMessages(lhs.code, rhs.code) && deepEqualsMessages(lhs.data, rhs.data) } + func hash(into hasher: inout Hasher) { - deepHashMessages(value: toList(), hasher: &hasher) + hasher.combine("MessageData") + deepHashMessages(value: name, hasher: &hasher) + deepHashMessages(value: description, hasher: &hasher) + deepHashMessages(value: code, hasher: &hasher) + deepHashMessages(value: data, hasher: &hasher) } } diff --git a/packages/pigeon/example/app/lib/src/event_channel_messages.g.dart b/packages/pigeon/example/app/lib/src/event_channel_messages.g.dart index 5c7f5c6b31b5..4590b74a0708 100644 --- a/packages/pigeon/example/app/lib/src/event_channel_messages.g.dart +++ b/packages/pigeon/example/app/lib/src/event_channel_messages.g.dart @@ -12,6 +12,14 @@ import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; import 'package:flutter/services.dart'; bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -19,16 +27,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += _deepHash(entry.key) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + sealed class PlatformEvent {} class IntEvent extends PlatformEvent { @@ -58,12 +102,12 @@ class IntEvent extends PlatformEvent { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(data, other.data); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class StringEvent extends PlatformEvent { @@ -93,12 +137,12 @@ class StringEvent extends PlatformEvent { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(data, other.data); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { diff --git a/packages/pigeon/example/app/lib/src/messages.g.dart b/packages/pigeon/example/app/lib/src/messages.g.dart index d62d999988a9..c0c3c861444c 100644 --- a/packages/pigeon/example/app/lib/src/messages.g.dart +++ b/packages/pigeon/example/app/lib/src/messages.g.dart @@ -51,6 +51,14 @@ List wrapResponse({ } bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -58,16 +66,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += _deepHash(entry.key) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + enum Code { one, two } class MessageData { @@ -113,12 +157,15 @@ class MessageData { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(name, other.name) && + _deepEquals(description, other.description) && + _deepEquals(code, other.code) && + _deepEquals(data, other.data); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { diff --git a/packages/pigeon/example/app/linux/messages.g.cc b/packages/pigeon/example/app/linux/messages.g.cc index 5dc179e4203a..de1ad17b9da2 100644 --- a/packages/pigeon/example/app/linux/messages.g.cc +++ b/packages/pigeon/example/app/linux/messages.g.cc @@ -6,6 +6,186 @@ #include "messages.g.h" +#include + +#include +static guint G_GNUC_UNUSED flpigeon_hash_double(double v) { + if (std::isnan(v)) return (guint)0x7FF80000; + if (v == 0.0) v = 0.0; + union { + double d; + uint64_t u; + } u; + u.d = v; + return (guint)(u.u ^ (u.u >> 32)); +} +static gboolean G_GNUC_UNUSED flpigeon_equals_double(double a, double b) { + return (a == b) || (std::isnan(a) && std::isnan(b)); +} +static gboolean G_GNUC_UNUSED flpigeon_deep_equals(FlValue* a, FlValue* b) { + if (a == b) { + return TRUE; + } + if (a == nullptr || b == nullptr) { + return FALSE; + } + if (fl_value_get_type(a) != fl_value_get_type(b)) { + return FALSE; + } + switch (fl_value_get_type(a)) { + case FL_VALUE_TYPE_NULL: + return TRUE; + case FL_VALUE_TYPE_BOOL: + return fl_value_get_bool(a) == fl_value_get_bool(b); + case FL_VALUE_TYPE_INT: + return fl_value_get_int(a) == fl_value_get_int(b); + case FL_VALUE_TYPE_FLOAT: { + return flpigeon_equals_double(fl_value_get_float(a), + fl_value_get_float(b)); + } + case FL_VALUE_TYPE_STRING: + return g_strcmp0(fl_value_get_string(a), fl_value_get_string(b)) == 0; + case FL_VALUE_TYPE_UINT8_LIST: + return fl_value_get_length(a) == fl_value_get_length(b) && + memcmp(fl_value_get_uint8_list(a), fl_value_get_uint8_list(b), + fl_value_get_length(a)) == 0; + case FL_VALUE_TYPE_INT32_LIST: + return fl_value_get_length(a) == fl_value_get_length(b) && + memcmp(fl_value_get_int32_list(a), fl_value_get_int32_list(b), + fl_value_get_length(a) * sizeof(int32_t)) == 0; + case FL_VALUE_TYPE_INT64_LIST: + return fl_value_get_length(a) == fl_value_get_length(b) && + memcmp(fl_value_get_int64_list(a), fl_value_get_int64_list(b), + fl_value_get_length(a) * sizeof(int64_t)) == 0; + case FL_VALUE_TYPE_FLOAT_LIST: { + size_t len = fl_value_get_length(a); + if (len != fl_value_get_length(b)) { + return FALSE; + } + const double* a_data = fl_value_get_float_list(a); + const double* b_data = fl_value_get_float_list(b); + for (size_t i = 0; i < len; i++) { + if (!flpigeon_equals_double(a_data[i], b_data[i])) { + return FALSE; + } + } + return TRUE; + } + case FL_VALUE_TYPE_LIST: { + size_t len = fl_value_get_length(a); + if (len != fl_value_get_length(b)) { + return FALSE; + } + for (size_t i = 0; i < len; i++) { + if (!flpigeon_deep_equals(fl_value_get_list_value(a, i), + fl_value_get_list_value(b, i))) { + return FALSE; + } + } + return TRUE; + } + case FL_VALUE_TYPE_MAP: { + size_t len = fl_value_get_length(a); + if (len != fl_value_get_length(b)) { + return FALSE; + } + for (size_t i = 0; i < len; i++) { + FlValue* key = fl_value_get_map_key(a, i); + FlValue* val = fl_value_get_map_value(a, i); + gboolean found = FALSE; + for (size_t j = 0; j < len; j++) { + FlValue* b_key = fl_value_get_map_key(b, j); + if (flpigeon_deep_equals(key, b_key)) { + FlValue* b_val = fl_value_get_map_value(b, j); + if (flpigeon_deep_equals(val, b_val)) { + found = TRUE; + break; + } else { + return FALSE; + } + } + } + if (!found) { + return FALSE; + } + } + return TRUE; + } + default: + return FALSE; + } + return FALSE; +} +static guint G_GNUC_UNUSED flpigeon_deep_hash(FlValue* value) { + if (value == nullptr) return 0; + switch (fl_value_get_type(value)) { + case FL_VALUE_TYPE_NULL: + return 0; + case FL_VALUE_TYPE_BOOL: + return fl_value_get_bool(value) ? 1231 : 1237; + case FL_VALUE_TYPE_INT: { + int64_t v = fl_value_get_int(value); + return (guint)(v ^ (v >> 32)); + } + case FL_VALUE_TYPE_FLOAT: + return flpigeon_hash_double(fl_value_get_float(value)); + case FL_VALUE_TYPE_STRING: + return g_str_hash(fl_value_get_string(value)); + case FL_VALUE_TYPE_UINT8_LIST: { + guint result = 1; + size_t len = fl_value_get_length(value); + const uint8_t* data = fl_value_get_uint8_list(value); + for (size_t i = 0; i < len; i++) result = result * 31 + data[i]; + return result; + } + case FL_VALUE_TYPE_INT32_LIST: { + guint result = 1; + size_t len = fl_value_get_length(value); + const int32_t* data = fl_value_get_int32_list(value); + for (size_t i = 0; i < len; i++) result = result * 31 + (guint)data[i]; + return result; + } + case FL_VALUE_TYPE_INT64_LIST: { + guint result = 1; + size_t len = fl_value_get_length(value); + const int64_t* data = fl_value_get_int64_list(value); + for (size_t i = 0; i < len; i++) + result = result * 31 + (guint)(data[i] ^ (data[i] >> 32)); + return result; + } + case FL_VALUE_TYPE_FLOAT_LIST: { + guint result = 1; + size_t len = fl_value_get_length(value); + const double* data = fl_value_get_float_list(value); + for (size_t i = 0; i < len; i++) { + result = result * 31 + flpigeon_hash_double(data[i]); + } + return result; + } + case FL_VALUE_TYPE_LIST: { + guint result = 1; + size_t len = fl_value_get_length(value); + for (size_t i = 0; i < len; i++) { + result = + result * 31 + flpigeon_deep_hash(fl_value_get_list_value(value, i)); + } + return result; + } + case FL_VALUE_TYPE_MAP: { + guint result = 0; + size_t len = fl_value_get_length(value); + for (size_t i = 0; i < len; i++) { + result += (flpigeon_deep_hash(fl_value_get_map_key(value, i)) ^ + flpigeon_deep_hash(fl_value_get_map_value(value, i))); + } + return result; + } + default: + return (guint)fl_value_get_type(value); + } + return 0; +} + struct _PigeonExamplePackageMessageData { GObject parent_instance; @@ -119,6 +299,41 @@ pigeon_example_package_message_data_new_from_list(FlValue* values) { return pigeon_example_package_message_data_new(name, description, code, data); } +gboolean pigeon_example_package_message_data_equals( + PigeonExamplePackageMessageData* a, PigeonExamplePackageMessageData* b) { + if (a == b) { + return TRUE; + } + if (a == nullptr || b == nullptr) { + return FALSE; + } + if (g_strcmp0(a->name, b->name) != 0) { + return FALSE; + } + if (g_strcmp0(a->description, b->description) != 0) { + return FALSE; + } + if (a->code != b->code) { + return FALSE; + } + if (!flpigeon_deep_equals(a->data, b->data)) { + return FALSE; + } + return TRUE; +} + +guint pigeon_example_package_message_data_hash( + PigeonExamplePackageMessageData* self) { + g_return_val_if_fail(PIGEON_EXAMPLE_PACKAGE_IS_MESSAGE_DATA(self), 0); + guint result = 0; + result = result * 31 + (self->name != nullptr ? g_str_hash(self->name) : 0); + result = result * 31 + + (self->description != nullptr ? g_str_hash(self->description) : 0); + result = result * 31 + (guint)self->code; + result = result * 31 + flpigeon_deep_hash(self->data); + return result; +} + struct _PigeonExamplePackageMessageCodec { FlStandardMessageCodec parent_instance; }; diff --git a/packages/pigeon/example/app/linux/messages.g.h b/packages/pigeon/example/app/linux/messages.g.h index 6fb44cc93516..c03ecb20a01d 100644 --- a/packages/pigeon/example/app/linux/messages.g.h +++ b/packages/pigeon/example/app/linux/messages.g.h @@ -90,6 +90,29 @@ PigeonExamplePackageCode pigeon_example_package_message_data_get_code( FlValue* pigeon_example_package_message_data_get_data( PigeonExamplePackageMessageData* object); +/** + * pigeon_example_package_message_data_equals: + * @a: a #PigeonExamplePackageMessageData. + * @b: another #PigeonExamplePackageMessageData. + * + * Checks if two #PigeonExamplePackageMessageData objects are equal. + * + * Returns: TRUE if @a and @b are equal. + */ +gboolean pigeon_example_package_message_data_equals( + PigeonExamplePackageMessageData* a, PigeonExamplePackageMessageData* b); + +/** + * pigeon_example_package_message_data_hash: + * @object: a #PigeonExamplePackageMessageData. + * + * Calculates a hash code for a #PigeonExamplePackageMessageData object. + * + * Returns: the hash code. + */ +guint pigeon_example_package_message_data_hash( + PigeonExamplePackageMessageData* object); + G_DECLARE_FINAL_TYPE(PigeonExamplePackageMessageCodec, pigeon_example_package_message_codec, PIGEON_EXAMPLE_PACKAGE, MESSAGE_CODEC, diff --git a/packages/pigeon/example/app/macos/Runner/messages.g.m b/packages/pigeon/example/app/macos/Runner/messages.g.m index 3e3bc65265ae..9de9e2129230 100644 --- a/packages/pigeon/example/app/macos/Runner/messages.g.m +++ b/packages/pigeon/example/app/macos/Runner/messages.g.m @@ -12,6 +12,96 @@ @import Flutter; #endif +static BOOL __attribute__((unused)) FLTPigeonDeepEquals(id _Nullable a, id _Nullable b) { + if (a == b) { + return YES; + } + if (a == nil || b == nil) { + return NO; + } + if ([a isKindOfClass:[NSNumber class]] && [b isKindOfClass:[NSNumber class]]) { + NSNumber *na = (NSNumber *)a; + NSNumber *nb = (NSNumber *)b; + // Normalize -0.0 to 0.0 and handle NaN equality. + return na.doubleValue == nb.doubleValue || (isnan(na.doubleValue) && isnan(nb.doubleValue)); + } + if ([a isKindOfClass:[NSArray class]] && [b isKindOfClass:[NSArray class]]) { + NSArray *arrayA = (NSArray *)a; + NSArray *arrayB = (NSArray *)b; + if (arrayA.count != arrayB.count) { + return NO; + } + for (NSUInteger i = 0; i < arrayA.count; i++) { + if (!FLTPigeonDeepEquals(arrayA[i], arrayB[i])) { + return NO; + } + } + return YES; + } + if ([a isKindOfClass:[NSDictionary class]] && [b isKindOfClass:[NSDictionary class]]) { + NSDictionary *dictA = (NSDictionary *)a; + NSDictionary *dictB = (NSDictionary *)b; + if (dictA.count != dictB.count) { + return NO; + } + for (id keyA in dictA) { + id valueA = dictA[keyA]; + BOOL found = NO; + for (id keyB in dictB) { + if (FLTPigeonDeepEquals(keyA, keyB)) { + id valueB = dictB[keyB]; + if (FLTPigeonDeepEquals(valueA, valueB)) { + found = YES; + break; + } else { + return NO; + } + } + } + if (!found) { + return NO; + } + } + return YES; + } + return [a isEqual:b]; +} + +static NSUInteger __attribute__((unused)) FLTPigeonDeepHash(id _Nullable value) { + if (value == nil) { + return 0; + } + if ([value isKindOfClass:[NSNumber class]]) { + NSNumber *n = (NSNumber *)value; + double d = n.doubleValue; + if (isnan(d)) { + // Normalize NaN to a consistent hash. + return (NSUInteger)0x7FF8000000000000; + } + if (d == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + d = 0.0; + } + return @(d).hash; + } + if ([value isKindOfClass:[NSArray class]]) { + NSUInteger result = 1; + for (id item in (NSArray *)value) { + result = result * 31 + FLTPigeonDeepHash(item); + } + return result; + } + if ([value isKindOfClass:[NSDictionary class]]) { + NSUInteger result = 0; + NSDictionary *dict = (NSDictionary *)value; + for (id key in dict) { + result += (FLTPigeonDeepHash(key) ^ FLTPigeonDeepHash(dict[key])); + } + return result; + } + return [value hash]; +} + static NSArray *wrapResult(id result, FlutterError *error) { if (error) { return @[ @@ -83,6 +173,27 @@ + (nullable PGNMessageData *)nullableFromList:(NSArray *)list { self.data ?: [NSNull null], ]; } +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[self class]]) { + return NO; + } + PGNMessageData *other = (PGNMessageData *)object; + return FLTPigeonDeepEquals(self.name, other.name) && + FLTPigeonDeepEquals(self.description, other.description) && self.code == other.code && + FLTPigeonDeepEquals(self.data, other.data); +} + +- (NSUInteger)hash { + NSUInteger result = [self class].hash; + result = result * 31 + FLTPigeonDeepHash(self.name); + result = result * 31 + FLTPigeonDeepHash(self.description); + result = result * 31 + @(self.code).hash; + result = result * 31 + FLTPigeonDeepHash(self.data); + return result; +} @end @interface PGNMessagesPigeonCodecReader : FlutterStandardReader diff --git a/packages/pigeon/example/app/windows/runner/messages.g.cpp b/packages/pigeon/example/app/windows/runner/messages.g.cpp index 755efbc8570b..9846d3d0ffd5 100644 --- a/packages/pigeon/example/app/windows/runner/messages.g.cpp +++ b/packages/pigeon/example/app/windows/runner/messages.g.cpp @@ -13,16 +13,18 @@ #include #include +#include +#include #include #include #include namespace pigeon_example { -using flutter::BasicMessageChannel; -using flutter::CustomEncodableValue; -using flutter::EncodableList; -using flutter::EncodableMap; -using flutter::EncodableValue; +using ::flutter::BasicMessageChannel; +using ::flutter::CustomEncodableValue; +using ::flutter::EncodableList; +using ::flutter::EncodableMap; +using ::flutter::EncodableValue; FlutterError CreateConnectionError(const std::string channel_name) { return FlutterError( @@ -31,6 +33,210 @@ FlutterError CreateConnectionError(const std::string channel_name) { EncodableValue("")); } +template +bool PigeonInternalDeepEquals(const T& a, const T& b); + +inline bool PigeonInternalDeepEquals(const double& a, const double& b); + +template +bool PigeonInternalDeepEquals(const std::vector& a, const std::vector& b); + +template +bool PigeonInternalDeepEquals(const std::map& a, const std::map& b); + +template +bool PigeonInternalDeepEquals(const std::optional& a, + const std::optional& b); + +template +bool PigeonInternalDeepEquals(const std::unique_ptr& a, + const std::unique_ptr& b); + +inline bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, + const ::flutter::EncodableValue& b); + +template +bool PigeonInternalDeepEquals(const T& a, const T& b) { + return a == b; +} + +template +bool PigeonInternalDeepEquals(const std::vector& a, + const std::vector& b) { + if (a.size() != b.size()) { + return false; + } + for (size_t i = 0; i < a.size(); ++i) { + if (!PigeonInternalDeepEquals(a[i], b[i])) { + return false; + } + } + return true; +} + +template +bool PigeonInternalDeepEquals(const std::map& a, + const std::map& b) { + if (a.size() != b.size()) { + return false; + } + for (const auto& kv : a) { + bool found = false; + for (const auto& b_kv : b) { + if (PigeonInternalDeepEquals(kv.first, b_kv.first)) { + if (PigeonInternalDeepEquals(kv.second, b_kv.second)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; +} + +inline bool PigeonInternalDeepEquals(const double& a, const double& b) { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (a == b) || (std::isnan(a) && std::isnan(b)); +} + +template +bool PigeonInternalDeepEquals(const std::optional& a, + const std::optional& b) { + if (!a && !b) { + return true; + } + if (!a || !b) { + return false; + } + return PigeonInternalDeepEquals(*a, *b); +} + +template +bool PigeonInternalDeepEquals(const std::unique_ptr& a, + const std::unique_ptr& b) { + if (!a && !b) { + return true; + } + if (!a || !b) { + return false; + } + return PigeonInternalDeepEquals(*a, *b); +} + +inline bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, + const ::flutter::EncodableValue& b) { + if (a.index() != b.index()) { + return false; + } + if (const double* da = std::get_if(&a)) { + return PigeonInternalDeepEquals(*da, std::get(b)); + } else if (const ::flutter::EncodableList* la = + std::get_if<::flutter::EncodableList>(&a)) { + return PigeonInternalDeepEquals(*la, std::get<::flutter::EncodableList>(b)); + } else if (const ::flutter::EncodableMap* ma = + std::get_if<::flutter::EncodableMap>(&a)) { + return PigeonInternalDeepEquals(*ma, std::get<::flutter::EncodableMap>(b)); + } + return a == b; +} + +template +size_t PigeonInternalDeepHash(const T& v); + +inline size_t PigeonInternalDeepHash(const double& v); + +template +size_t PigeonInternalDeepHash(const std::vector& v); + +template +size_t PigeonInternalDeepHash(const std::map& v); + +template +size_t PigeonInternalDeepHash(const std::optional& v); + +template +size_t PigeonInternalDeepHash(const std::unique_ptr& v); + +inline size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v); + +template +size_t PigeonInternalDeepHash(const T& v) { + return std::hash()(v); +} + +template +size_t PigeonInternalDeepHash(const std::vector& v) { + size_t result = 0; + for (const auto& item : v) { + result = result * 31 + PigeonInternalDeepHash(item); + } + return result; +} + +template +size_t PigeonInternalDeepHash(const std::map& v) { + size_t result = 0; + for (const auto& kv : v) { + result = result * 31 + PigeonInternalDeepHash(kv.first); + result = result * 31 + PigeonInternalDeepHash(kv.second); + } + return result; +} + +inline size_t PigeonInternalDeepHash(const double& v) { + if (std::isnan(v)) { + // Normalize NaN to a consistent hash. + return std::hash()(std::numeric_limits::quiet_NaN()); + } + if (v == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return std::hash()(0.0); + } + return std::hash()(v); +} + +template +size_t PigeonInternalDeepHash(const std::optional& v) { + return v ? PigeonInternalDeepHash(*v) : 0; +} + +template +size_t PigeonInternalDeepHash(const std::unique_ptr& v) { + return v ? PigeonInternalDeepHash(*v) : 0; +} + +inline size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v) { + size_t result = v.index(); + if (const double* dv = std::get_if(&v)) { + result = result * 31 + PigeonInternalDeepHash(*dv); + } else if (const ::flutter::EncodableList* lv = + std::get_if<::flutter::EncodableList>(&v)) { + result = result * 31 + PigeonInternalDeepHash(*lv); + } else if (const ::flutter::EncodableMap* mv = + std::get_if<::flutter::EncodableMap>(&v)) { + result = result * 31 + PigeonInternalDeepHash(*mv); + } else { + std::visit( + [&result](const auto& val) { + using T = std::decay_t; + if constexpr (!std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v) { + result = result * 31 + PigeonInternalDeepHash(val); + } + }, + v); + } + return result; +} + // MessageData MessageData::MessageData(const Code& code, const EncodableMap& data) @@ -102,10 +308,32 @@ MessageData MessageData::FromEncodableList(const EncodableList& list) { return decoded; } +bool MessageData::operator==(const MessageData& other) const { + return PigeonInternalDeepEquals(name_, other.name_) && + PigeonInternalDeepEquals(description_, other.description_) && + PigeonInternalDeepEquals(code_, other.code_) && + PigeonInternalDeepEquals(data_, other.data_); +} + +bool MessageData::operator!=(const MessageData& other) const { + return !(*this == other); +} + +size_t MessageData::Hash() const { + size_t result = 0; + result = result * 31 + PigeonInternalDeepHash(name_); + result = result * 31 + PigeonInternalDeepHash(description_); + result = result * 31 + PigeonInternalDeepHash(code_); + result = result * 31 + PigeonInternalDeepHash(data_); + return result; +} + +size_t PigeonInternalDeepHash(const MessageData& v) { return v.Hash(); } + PigeonInternalCodecSerializer::PigeonInternalCodecSerializer() {} EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( - uint8_t type, flutter::ByteStreamReader* stream) const { + uint8_t type, ::flutter::ByteStreamReader* stream) const { switch (type) { case 129: { const auto& encodable_enum_arg = ReadValue(stream); @@ -120,12 +348,12 @@ EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( std::get(ReadValue(stream)))); } default: - return flutter::StandardCodecSerializer::ReadValueOfType(type, stream); + return ::flutter::StandardCodecSerializer::ReadValueOfType(type, stream); } } void PigeonInternalCodecSerializer::WriteValue( - const EncodableValue& value, flutter::ByteStreamWriter* stream) const { + const EncodableValue& value, ::flutter::ByteStreamWriter* stream) const { if (const CustomEncodableValue* custom_value = std::get_if(&value)) { if (custom_value->type() == typeid(Code)) { @@ -144,23 +372,23 @@ void PigeonInternalCodecSerializer::WriteValue( return; } } - flutter::StandardCodecSerializer::WriteValue(value, stream); + ::flutter::StandardCodecSerializer::WriteValue(value, stream); } /// The codec used by ExampleHostApi. -const flutter::StandardMessageCodec& ExampleHostApi::GetCodec() { - return flutter::StandardMessageCodec::GetInstance( +const ::flutter::StandardMessageCodec& ExampleHostApi::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance( &PigeonInternalCodecSerializer::GetInstance()); } // Sets up an instance of `ExampleHostApi` to handle messages through the // `binary_messenger`. -void ExampleHostApi::SetUp(flutter::BinaryMessenger* binary_messenger, +void ExampleHostApi::SetUp(::flutter::BinaryMessenger* binary_messenger, ExampleHostApi* api) { ExampleHostApi::SetUp(binary_messenger, api, ""); } -void ExampleHostApi::SetUp(flutter::BinaryMessenger* binary_messenger, +void ExampleHostApi::SetUp(::flutter::BinaryMessenger* binary_messenger, ExampleHostApi* api, const std::string& message_channel_suffix) { const std::string prepended_suffix = @@ -176,7 +404,7 @@ void ExampleHostApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { ErrorOr output = api->GetHostLanguage(); if (output.has_error()) { @@ -203,7 +431,7 @@ void ExampleHostApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_arg = args.at(0); @@ -243,7 +471,7 @@ void ExampleHostApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_message_arg = args.at(0); @@ -287,18 +515,20 @@ EncodableValue ExampleHostApi::WrapError(const FlutterError& error) { // Generated class from Pigeon that represents Flutter messages that can be // called from C++. -MessageFlutterApi::MessageFlutterApi(flutter::BinaryMessenger* binary_messenger) +MessageFlutterApi::MessageFlutterApi( + ::flutter::BinaryMessenger* binary_messenger) : binary_messenger_(binary_messenger), message_channel_suffix_("") {} -MessageFlutterApi::MessageFlutterApi(flutter::BinaryMessenger* binary_messenger, - const std::string& message_channel_suffix) +MessageFlutterApi::MessageFlutterApi( + ::flutter::BinaryMessenger* binary_messenger, + const std::string& message_channel_suffix) : binary_messenger_(binary_messenger), message_channel_suffix_(message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : "") {} -const flutter::StandardMessageCodec& MessageFlutterApi::GetCodec() { - return flutter::StandardMessageCodec::GetInstance( +const ::flutter::StandardMessageCodec& MessageFlutterApi::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance( &PigeonInternalCodecSerializer::GetInstance()); } diff --git a/packages/pigeon/example/app/windows/runner/messages.g.h b/packages/pigeon/example/app/windows/runner/messages.g.h index c56c0d1cf171..b23312baccff 100644 --- a/packages/pigeon/example/app/windows/runner/messages.g.h +++ b/packages/pigeon/example/app/windows/runner/messages.g.h @@ -25,17 +25,17 @@ class FlutterError { explicit FlutterError(const std::string& code, const std::string& message) : code_(code), message_(message) {} explicit FlutterError(const std::string& code, const std::string& message, - const flutter::EncodableValue& details) + const ::flutter::EncodableValue& details) : code_(code), message_(message), details_(details) {} const std::string& code() const { return code_; } const std::string& message() const { return message_; } - const flutter::EncodableValue& details() const { return details_; } + const ::flutter::EncodableValue& details() const { return details_; } private: std::string code_; std::string message_; - flutter::EncodableValue details_; + ::flutter::EncodableValue details_; }; template @@ -65,11 +65,11 @@ enum class Code { kOne = 0, kTwo = 1 }; class MessageData { public: // Constructs an object setting all non-nullable fields. - explicit MessageData(const Code& code, const flutter::EncodableMap& data); + explicit MessageData(const Code& code, const ::flutter::EncodableMap& data); // Constructs an object setting all fields. explicit MessageData(const std::string* name, const std::string* description, - const Code& code, const flutter::EncodableMap& data); + const Code& code, const ::flutter::EncodableMap& data); const std::string* name() const; void set_name(const std::string_view* value_arg); @@ -82,22 +82,29 @@ class MessageData { const Code& code() const; void set_code(const Code& value_arg); - const flutter::EncodableMap& data() const; - void set_data(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap& data() const; + void set_data(const ::flutter::EncodableMap& value_arg); + + bool operator==(const MessageData& other) const; + bool operator!=(const MessageData& other) const; + /// Returns a hash code value for the object. This method is supported for the + /// benefit of hash tables. + size_t Hash() const; private: - static MessageData FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static MessageData FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class ExampleHostApi; friend class MessageFlutterApi; friend class PigeonInternalCodecSerializer; std::optional name_; std::optional description_; Code code_; - flutter::EncodableMap data_; + ::flutter::EncodableMap data_; }; -class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer { +class PigeonInternalCodecSerializer + : public ::flutter::StandardCodecSerializer { public: PigeonInternalCodecSerializer(); inline static PigeonInternalCodecSerializer& GetInstance() { @@ -105,12 +112,12 @@ class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer { return sInstance; } - void WriteValue(const flutter::EncodableValue& value, - flutter::ByteStreamWriter* stream) const override; + void WriteValue(const ::flutter::EncodableValue& value, + ::flutter::ByteStreamWriter* stream) const override; protected: - flutter::EncodableValue ReadValueOfType( - uint8_t type, flutter::ByteStreamReader* stream) const override; + ::flutter::EncodableValue ReadValueOfType( + uint8_t type, ::flutter::ByteStreamReader* stream) const override; }; // Generated interface from Pigeon that represents a handler of messages from @@ -126,16 +133,16 @@ class ExampleHostApi { std::function reply)> result) = 0; // The codec used by ExampleHostApi. - static const flutter::StandardMessageCodec& GetCodec(); + static const ::flutter::StandardMessageCodec& GetCodec(); // Sets up an instance of `ExampleHostApi` to handle messages through the // `binary_messenger`. - static void SetUp(flutter::BinaryMessenger* binary_messenger, + static void SetUp(::flutter::BinaryMessenger* binary_messenger, ExampleHostApi* api); - static void SetUp(flutter::BinaryMessenger* binary_messenger, + static void SetUp(::flutter::BinaryMessenger* binary_messenger, ExampleHostApi* api, const std::string& message_channel_suffix); - static flutter::EncodableValue WrapError(std::string_view error_message); - static flutter::EncodableValue WrapError(const FlutterError& error); + static ::flutter::EncodableValue WrapError(std::string_view error_message); + static ::flutter::EncodableValue WrapError(const FlutterError& error); protected: ExampleHostApi() = default; @@ -144,16 +151,16 @@ class ExampleHostApi { // called from C++. class MessageFlutterApi { public: - MessageFlutterApi(flutter::BinaryMessenger* binary_messenger); - MessageFlutterApi(flutter::BinaryMessenger* binary_messenger, + MessageFlutterApi(::flutter::BinaryMessenger* binary_messenger); + MessageFlutterApi(::flutter::BinaryMessenger* binary_messenger, const std::string& message_channel_suffix); - static const flutter::StandardMessageCodec& GetCodec(); + static const ::flutter::StandardMessageCodec& GetCodec(); void FlutterMethod(const std::string* a_string, std::function&& on_success, std::function&& on_error); private: - flutter::BinaryMessenger* binary_messenger_; + ::flutter::BinaryMessenger* binary_messenger_; std::string message_channel_suffix_; }; diff --git a/packages/pigeon/lib/src/cpp/cpp_generator.dart b/packages/pigeon/lib/src/cpp/cpp_generator.dart index 9708198f6cd8..7b045958ff50 100644 --- a/packages/pigeon/lib/src/cpp/cpp_generator.dart +++ b/packages/pigeon/lib/src/cpp/cpp_generator.dart @@ -20,7 +20,7 @@ const DocumentCommentSpecification _docCommentSpec = DocumentCommentSpecification(_commentPrefix); /// The default serializer for Flutter. -const String _standardCodecSerializer = 'flutter::StandardCodecSerializer'; +const String _standardCodecSerializer = '::flutter::StandardCodecSerializer'; /// The name of the codec serializer. const String _codecSerializerName = '${classNamePrefix}CodecSerializer'; @@ -459,6 +459,30 @@ class CppHeaderGenerator extends StructuredGenerator { } indent.newln(); } + + _writeFunctionDeclaration( + indent, + 'operator==', + returnType: 'bool', + parameters: ['const ${classDefinition.name}& other'], + isConst: true, + ); + _writeFunctionDeclaration( + indent, + 'operator!=', + returnType: 'bool', + parameters: ['const ${classDefinition.name}& other'], + isConst: true, + ); + indent.writeln( + '/// Returns a hash code value for the object. This method is supported for the benefit of hash tables.', + ); + _writeFunctionDeclaration( + indent, + 'Hash', + returnType: 'size_t', + isConst: true, + ); }); _writeAccessBlock(indent, _ClassAccess.private, () { @@ -466,22 +490,22 @@ class CppHeaderGenerator extends StructuredGenerator { indent, 'FromEncodableList', returnType: isOverflowClass - ? 'flutter::EncodableValue' + ? '::flutter::EncodableValue' : classDefinition.name, - parameters: ['const flutter::EncodableList& list'], + parameters: ['const ::flutter::EncodableList& list'], isStatic: true, ); _writeFunctionDeclaration( indent, 'ToEncodableList', - returnType: 'flutter::EncodableList', + returnType: '::flutter::EncodableList', isConst: true, ); if (isOverflowClass) { _writeFunctionDeclaration( indent, 'Unwrap', - returnType: 'flutter::EncodableValue', + returnType: '::flutter::EncodableValue', ); } if (!isOverflowClass && root.requiresOverflowClass) { @@ -556,8 +580,8 @@ class CppHeaderGenerator extends StructuredGenerator { 'WriteValue', returnType: _voidType, parameters: [ - 'const flutter::EncodableValue& value', - 'flutter::ByteStreamWriter* stream', + 'const ::flutter::EncodableValue& value', + '::flutter::ByteStreamWriter* stream', ], isConst: true, isOverride: true, @@ -567,10 +591,10 @@ class CppHeaderGenerator extends StructuredGenerator { _writeFunctionDeclaration( indent, 'ReadValueOfType', - returnType: 'flutter::EncodableValue', + returnType: '::flutter::EncodableValue', parameters: [ 'uint8_t type', - 'flutter::ByteStreamReader* stream', + '::flutter::ByteStreamReader* stream', ], isConst: true, isOverride: true, @@ -603,20 +627,20 @@ class CppHeaderGenerator extends StructuredGenerator { _writeFunctionDeclaration( indent, api.name, - parameters: ['flutter::BinaryMessenger* binary_messenger'], + parameters: ['::flutter::BinaryMessenger* binary_messenger'], ); _writeFunctionDeclaration( indent, api.name, parameters: [ - 'flutter::BinaryMessenger* binary_messenger', + '::flutter::BinaryMessenger* binary_messenger', 'const std::string& message_channel_suffix', ], ); _writeFunctionDeclaration( indent, 'GetCodec', - returnType: 'const flutter::StandardMessageCodec&', + returnType: 'const ::flutter::StandardMessageCodec&', isStatic: true, ); for (final Method func in api.methods) { @@ -656,7 +680,7 @@ class CppHeaderGenerator extends StructuredGenerator { } }); indent.addScoped(' private:', null, () { - indent.writeln('flutter::BinaryMessenger* binary_messenger_;'); + indent.writeln('::flutter::BinaryMessenger* binary_messenger_;'); indent.writeln('std::string message_channel_suffix_;'); }); }, nestCount: 0); @@ -758,7 +782,7 @@ class CppHeaderGenerator extends StructuredGenerator { _writeFunctionDeclaration( indent, 'GetCodec', - returnType: 'const flutter::StandardMessageCodec&', + returnType: 'const ::flutter::StandardMessageCodec&', isStatic: true, ); indent.writeln( @@ -770,7 +794,7 @@ class CppHeaderGenerator extends StructuredGenerator { returnType: _voidType, isStatic: true, parameters: [ - 'flutter::BinaryMessenger* binary_messenger', + '::flutter::BinaryMessenger* binary_messenger', '${api.name}* api', ], ); @@ -780,7 +804,7 @@ class CppHeaderGenerator extends StructuredGenerator { returnType: _voidType, isStatic: true, parameters: [ - 'flutter::BinaryMessenger* binary_messenger', + '::flutter::BinaryMessenger* binary_messenger', '${api.name}* api', 'const std::string& message_channel_suffix', ], @@ -788,14 +812,14 @@ class CppHeaderGenerator extends StructuredGenerator { _writeFunctionDeclaration( indent, 'WrapError', - returnType: 'flutter::EncodableValue', + returnType: '::flutter::EncodableValue', isStatic: true, parameters: ['std::string_view error_message'], ); _writeFunctionDeclaration( indent, 'WrapError', - returnType: 'flutter::EncodableValue', + returnType: '::flutter::EncodableValue', isStatic: true, parameters: ['const FlutterError& error'], ); @@ -839,17 +863,17 @@ class FlutterError { \t\t: code_(code) {} \texplicit FlutterError(const std::string& code, const std::string& message) \t\t: code_(code), message_(message) {} -\texplicit FlutterError(const std::string& code, const std::string& message, const flutter::EncodableValue& details) +\texplicit FlutterError(const std::string& code, const std::string& message, const ::flutter::EncodableValue& details) \t\t: code_(code), message_(message), details_(details) {} \tconst std::string& code() const { return code_; } \tconst std::string& message() const { return message_; } -\tconst flutter::EncodableValue& details() const { return details_; } +\tconst ::flutter::EncodableValue& details() const { return details_; } private: \tstd::string code_; \tstd::string message_; -\tflutter::EncodableValue details_; +\t::flutter::EncodableValue details_; };'''); } @@ -937,6 +961,8 @@ class CppSourceGenerator extends StructuredGenerator { ]); indent.newln(); _writeSystemHeaderIncludeBlock(indent, [ + 'cmath', + 'limits', 'map', 'string', 'optional', @@ -964,11 +990,11 @@ class CppSourceGenerator extends StructuredGenerator { required String dartPackageName, }) { final usingDirectives = [ - 'flutter::BasicMessageChannel', - 'flutter::CustomEncodableValue', - 'flutter::EncodableList', - 'flutter::EncodableMap', - 'flutter::EncodableValue', + '::flutter::BasicMessageChannel', + '::flutter::CustomEncodableValue', + '::flutter::EncodableList', + '::flutter::EncodableMap', + '::flutter::EncodableValue', ]; usingDirectives.sort(); for (final using in usingDirectives) { @@ -988,6 +1014,8 @@ class CppSourceGenerator extends StructuredGenerator { EncodableValue(""));'''); }, ); + _writeDeepEquals(indent); + _writeDeepHash(indent); } @override @@ -1052,6 +1080,268 @@ class CppSourceGenerator extends StructuredGenerator { classDefinition, dartPackageName: dartPackageName, ); + + _writeFunctionDefinition( + indent, + 'operator==', + scope: classDefinition.name, + returnType: 'bool', + parameters: ['const ${classDefinition.name}& other'], + isConst: true, + body: () { + final Iterable checks = orderedFields.map((NamedType field) { + final String name = _makeInstanceVariableName(field); + return 'PigeonInternalDeepEquals($name, other.$name)'; + }); + if (checks.isEmpty) { + indent.writeln('return true;'); + } else { + indent.writeln('return ${checks.join(' && ')};'); + } + }, + ); + + _writeFunctionDefinition( + indent, + 'operator!=', + scope: classDefinition.name, + returnType: 'bool', + parameters: ['const ${classDefinition.name}& other'], + isConst: true, + body: () { + indent.writeln('return !(*this == other);'); + }, + ); + + _writeFunctionDefinition( + indent, + 'Hash', + scope: classDefinition.name, + returnType: 'size_t', + isConst: true, + body: () { + indent.writeln('size_t result = 0;'); + for (final field in orderedFields) { + final String name = _makeInstanceVariableName(field); + indent.writeln( + 'result = result * 31 + PigeonInternalDeepHash($name);', + ); + } + indent.writeln('return result;'); + }, + ); + + _writeFunctionDefinition( + indent, + 'PigeonInternalDeepHash', + returnType: 'size_t', + parameters: ['const ${classDefinition.name}& v'], + body: () { + indent.writeln('return v.Hash();'); + }, + ); + } + + void _writeDeepEquals(Indent indent) { + indent.format(''' +template +bool PigeonInternalDeepEquals(const T& a, const T& b); + +inline bool PigeonInternalDeepEquals(const double& a, const double& b); + +template +bool PigeonInternalDeepEquals(const std::vector& a, const std::vector& b); + +template +bool PigeonInternalDeepEquals(const std::map& a, const std::map& b); + +template +bool PigeonInternalDeepEquals(const std::optional& a, const std::optional& b); + +template +bool PigeonInternalDeepEquals(const std::unique_ptr& a, const std::unique_ptr& b); + +inline bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, const ::flutter::EncodableValue& b); + +template +bool PigeonInternalDeepEquals(const T& a, const T& b) { + return a == b; +} + +template +bool PigeonInternalDeepEquals(const std::vector& a, const std::vector& b) { + if (a.size() != b.size()) { + return false; + } + for (size_t i = 0; i < a.size(); ++i) { + if (!PigeonInternalDeepEquals(a[i], b[i])) { + return false; + } + } + return true; +} + +template +bool PigeonInternalDeepEquals(const std::map& a, const std::map& b) { + if (a.size() != b.size()) { + return false; + } + for (const auto& kv : a) { + bool found = false; + for (const auto& b_kv : b) { + if (PigeonInternalDeepEquals(kv.first, b_kv.first)) { + if (PigeonInternalDeepEquals(kv.second, b_kv.second)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; +} + +inline bool PigeonInternalDeepEquals(const double& a, const double& b) { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (a == b) || (std::isnan(a) && std::isnan(b)); +} + +template +bool PigeonInternalDeepEquals(const std::optional& a, const std::optional& b) { + if (!a && !b) { + return true; + } + if (!a || !b) { + return false; + } + return PigeonInternalDeepEquals(*a, *b); +} + +template +bool PigeonInternalDeepEquals(const std::unique_ptr& a, const std::unique_ptr& b) { + if (!a && !b) { + return true; + } + if (!a || !b) { + return false; + } + return PigeonInternalDeepEquals(*a, *b); +} + +inline bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, const ::flutter::EncodableValue& b) { + if (a.index() != b.index()) { + return false; + } + if (const double* da = std::get_if(&a)) { + return PigeonInternalDeepEquals(*da, std::get(b)); + } else if (const ::flutter::EncodableList* la = std::get_if<::flutter::EncodableList>(&a)) { + return PigeonInternalDeepEquals(*la, std::get<::flutter::EncodableList>(b)); + } else if (const ::flutter::EncodableMap* ma = std::get_if<::flutter::EncodableMap>(&a)) { + return PigeonInternalDeepEquals(*ma, std::get<::flutter::EncodableMap>(b)); + } + return a == b; +} +'''); + } + + void _writeDeepHash(Indent indent) { + indent.format(''' +template +size_t PigeonInternalDeepHash(const T& v); + +inline size_t PigeonInternalDeepHash(const double& v); + +template +size_t PigeonInternalDeepHash(const std::vector& v); + +template +size_t PigeonInternalDeepHash(const std::map& v); + +template +size_t PigeonInternalDeepHash(const std::optional& v); + +template +size_t PigeonInternalDeepHash(const std::unique_ptr& v); + +inline size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v); + +template +size_t PigeonInternalDeepHash(const T& v) { + return std::hash()(v); +} + +template +size_t PigeonInternalDeepHash(const std::vector& v) { + size_t result = 0; + for (const auto& item : v) { + result = result * 31 + PigeonInternalDeepHash(item); + } + return result; +} + +template +size_t PigeonInternalDeepHash(const std::map& v) { + size_t result = 0; + for (const auto& kv : v) { + result = result * 31 + PigeonInternalDeepHash(kv.first); + result = result * 31 + PigeonInternalDeepHash(kv.second); + } + return result; +} + +inline size_t PigeonInternalDeepHash(const double& v) { + if (std::isnan(v)) { + // Normalize NaN to a consistent hash. + return std::hash()(std::numeric_limits::quiet_NaN()); + } + if (v == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return std::hash()(0.0); + } + return std::hash()(v); +} + +template +size_t PigeonInternalDeepHash(const std::optional& v) { + return v ? PigeonInternalDeepHash(*v) : 0; +} + +template +size_t PigeonInternalDeepHash(const std::unique_ptr& v) { + return v ? PigeonInternalDeepHash(*v) : 0; +} + +inline size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v) { + size_t result = v.index(); + if (const double* dv = std::get_if(&v)) { + result = result * 31 + PigeonInternalDeepHash(*dv); + } else if (const ::flutter::EncodableList* lv = + std::get_if<::flutter::EncodableList>(&v)) { + result = result * 31 + PigeonInternalDeepHash(*lv); + } else if (const ::flutter::EncodableMap* mv = + std::get_if<::flutter::EncodableMap>(&v)) { + result = result * 31 + PigeonInternalDeepHash(*mv); + } else { + std::visit( + [&result](const auto& val) { + using T = std::decay_t; + if constexpr (!std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v) { + result = result * 31 + PigeonInternalDeepHash(val); + } + }, + v); + } + return result; +} +'''); } @override @@ -1292,7 +1582,10 @@ EncodableValue $_overflowClassName::FromEncodableList( 'ReadValueOfType', scope: _codecSerializerName, returnType: 'EncodableValue', - parameters: ['uint8_t type', 'flutter::ByteStreamReader* stream'], + parameters: [ + 'uint8_t type', + '::flutter::ByteStreamReader* stream', + ], isConst: true, body: () { if (enumeratedTypes.isNotEmpty) { @@ -1330,7 +1623,7 @@ EncodableValue $_overflowClassName::FromEncodableList( returnType: _voidType, parameters: [ 'const EncodableValue& value', - 'flutter::ByteStreamWriter* stream', + '::flutter::ByteStreamWriter* stream', ], isConst: true, body: () { @@ -1388,7 +1681,7 @@ EncodableValue $_overflowClassName::FromEncodableList( indent, api.name, scope: api.name, - parameters: ['flutter::BinaryMessenger* binary_messenger'], + parameters: ['::flutter::BinaryMessenger* binary_messenger'], initializers: [ 'binary_messenger_(binary_messenger)', 'message_channel_suffix_("")', @@ -1399,7 +1692,7 @@ EncodableValue $_overflowClassName::FromEncodableList( api.name, scope: api.name, parameters: [ - 'flutter::BinaryMessenger* binary_messenger', + '::flutter::BinaryMessenger* binary_messenger', 'const std::string& message_channel_suffix', ], initializers: [ @@ -1411,10 +1704,10 @@ EncodableValue $_overflowClassName::FromEncodableList( indent, 'GetCodec', scope: api.name, - returnType: 'const flutter::StandardMessageCodec&', + returnType: 'const ::flutter::StandardMessageCodec&', body: () { indent.writeln( - 'return flutter::StandardMessageCodec::GetInstance(&$_codecSerializerName::GetInstance());', + 'return ::flutter::StandardMessageCodec::GetInstance(&$_codecSerializerName::GetInstance());', ); }, ); @@ -1545,10 +1838,10 @@ EncodableValue $_overflowClassName::FromEncodableList( indent, 'GetCodec', scope: api.name, - returnType: 'const flutter::StandardMessageCodec&', + returnType: 'const ::flutter::StandardMessageCodec&', body: () { indent.writeln( - 'return flutter::StandardMessageCodec::GetInstance(&$_codecSerializerName::GetInstance());', + 'return ::flutter::StandardMessageCodec::GetInstance(&$_codecSerializerName::GetInstance());', ); }, ); @@ -1561,7 +1854,7 @@ EncodableValue $_overflowClassName::FromEncodableList( scope: api.name, returnType: _voidType, parameters: [ - 'flutter::BinaryMessenger* binary_messenger', + '::flutter::BinaryMessenger* binary_messenger', '${api.name}* api', ], body: () { @@ -1574,7 +1867,7 @@ EncodableValue $_overflowClassName::FromEncodableList( scope: api.name, returnType: _voidType, parameters: [ - 'flutter::BinaryMessenger* binary_messenger', + '::flutter::BinaryMessenger* binary_messenger', '${api.name}* api', 'const std::string& message_channel_suffix', ], @@ -1595,7 +1888,7 @@ EncodableValue $_overflowClassName::FromEncodableList( ); indent.writeScoped('if (api != nullptr) {', '} else {', () { indent.write( - 'channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) ', + 'channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) ', ); indent.addScoped('{', '});', () { indent.writeScoped('try {', '}', () { @@ -2187,7 +2480,7 @@ String? _baseCppTypeForBuiltinDartType( TypeDeclaration type, { bool includeFlutterNamespace = true, }) { - final flutterNamespace = includeFlutterNamespace ? 'flutter::' : ''; + final flutterNamespace = includeFlutterNamespace ? '::flutter::' : ''; final cppTypeForDartTypeMap = { 'void': 'void', 'bool': 'bool', diff --git a/packages/pigeon/lib/src/dart/dart_generator.dart b/packages/pigeon/lib/src/dart/dart_generator.dart index a979f6386222..37675158e01e 100644 --- a/packages/pigeon/lib/src/dart/dart_generator.dart +++ b/packages/pigeon/lib/src/dart/dart_generator.dart @@ -357,6 +357,9 @@ class DartGenerator extends StructuredGenerator { Class classDefinition, { required String dartPackageName, }) { + final Iterable fields = getFieldsInSerializationOrder( + classDefinition, + ); indent.writeln('@override'); indent.writeln('// ignore: avoid_equals_and_hash_code_on_mutable_classes'); indent.writeScoped('bool operator ==(Object other) {', '}', () { @@ -367,16 +370,28 @@ class DartGenerator extends StructuredGenerator { indent.writeln('return false;'); }, ); - indent.writeScoped('if (identical(this, other)) {', '}', () { + if (fields.isEmpty) { indent.writeln('return true;'); - }); - indent.writeln('return _deepEquals(encode(), other.encode());'); + } else { + indent.writeScoped('if (identical(this, other)) {', '}', () { + indent.writeln('return true;'); + }); + final String comparisons = fields + .map( + (NamedType field) => + '_deepEquals(${field.name}, other.${field.name})', + ) + .join(' && '); + indent.writeln('return $comparisons;'); + } }); + indent.newln(); indent.writeln('@override'); indent.writeln('// ignore: avoid_equals_and_hash_code_on_mutable_classes'); - indent.writeln('int get hashCode => Object.hashAll(_toList())'); - indent.addln(';'); + indent.writeln( + 'int get hashCode => _deepHash([runtimeType, ..._toList()]);', + ); } @override @@ -1126,6 +1141,7 @@ final BinaryMessenger? ${varNamePrefix}binaryMessenger; } if (root.classes.isNotEmpty) { _writeDeepEquals(indent); + _writeDeepHash(indent); } if (root.containsProxyApi) { proxy_api_helper.writeProxyApiPigeonOverrides( @@ -1159,21 +1175,72 @@ final BinaryMessenger? ${varNamePrefix}binaryMessenger; void _writeDeepEquals(Indent indent) { indent.format(r''' bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + } if (a is List && b is List) { return a.length == b.length && a.indexed - .every(((int, dynamic) item) => _deepEquals(item.$2, b[item.$1])); + .every(((int, dynamic) item) => _deepEquals(item.$2, b[item.$1])); } if (a is Map && b is Map) { - return a.length == b.length && a.entries.every((MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key])); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } '''); } + void _writeDeepHash(Indent indent) { + indent.format(r''' +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += _deepHash(entry.key) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} +'''); + } + static void _writeExtractReplyValueOrThrow(Indent indent) { indent.newln(); indent.format(''' diff --git a/packages/pigeon/lib/src/generator_tools.dart b/packages/pigeon/lib/src/generator_tools.dart index 406cf94f1556..f37a6878845b 100644 --- a/packages/pigeon/lib/src/generator_tools.dart +++ b/packages/pigeon/lib/src/generator_tools.dart @@ -15,7 +15,7 @@ import 'generator.dart'; /// The current version of pigeon. /// /// This must match the version in pubspec.yaml. -const String pigeonVersion = '26.1.10'; +const String pigeonVersion = '26.2.0'; /// Read all the content from [stdin] to a String. String readStdin() { diff --git a/packages/pigeon/lib/src/gobject/gobject_generator.dart b/packages/pigeon/lib/src/gobject/gobject_generator.dart index 0daa9debd069..505080f3fa14 100644 --- a/packages/pigeon/lib/src/gobject/gobject_generator.dart +++ b/packages/pigeon/lib/src/gobject/gobject_generator.dart @@ -327,6 +327,31 @@ class GObjectHeaderGenerator '$returnType ${methodPrefix}_get_$fieldName(${getterArgs.join(', ')});', ); } + + indent.newln(); + addDocumentationComments(indent, [ + '${methodPrefix}_equals:', + '@a: a #$className.', + '@b: another #$className.', + '', + 'Checks if two #$className objects are equal.', + '', + 'Returns: TRUE if @a and @b are equal.', + ], _docCommentSpec); + indent.writeln( + 'gboolean ${methodPrefix}_equals($className* a, $className* b);', + ); + + indent.newln(); + addDocumentationComments(indent, [ + '${methodPrefix}_hash:', + '@object: a #$className.', + '', + 'Calculates a hash code for a #$className object.', + '', + 'Returns: the hash code.', + ], _docCommentSpec); + indent.writeln('guint ${methodPrefix}_hash($className* object);'); } @override @@ -818,7 +843,13 @@ class GObjectSourceGenerator required String dartPackageName, }) { indent.newln(); + indent.writeln('#include '); + indent.writeln('#include '); indent.writeln('#include "${generatorOptions.headerIncludePath}"'); + + _writeHashHelpers(indent); + _writeDeepEquals(indent); + _writeDeepHash(indent); } @override @@ -1039,6 +1070,275 @@ class GObjectSourceGenerator indent.writeln('return ${methodPrefix}_new(${args.join(', ')});'); }, ); + + _writeClassEquality( + generatorOptions, + root, + indent, + classDefinition, + dartPackageName: dartPackageName, + ); + } + + void _writeClassEquality( + InternalGObjectOptions generatorOptions, + Root root, + Indent indent, + Class classDefinition, { + required String dartPackageName, + }) { + final String module = _getModule(generatorOptions, dartPackageName); + final String snakeModule = _snakeCaseFromCamelCase(module); + final String className = _getClassName(module, classDefinition.name); + final String snakeClassName = _snakeCaseFromCamelCase(classDefinition.name); + + final String methodPrefix = _getMethodPrefix(module, classDefinition.name); + final String testMacro = '${snakeModule}_IS_$snakeClassName'.toUpperCase(); + + indent.newln(); + indent.writeScoped('gboolean ${methodPrefix}_equals($className* a, $className* b) {', '}', () { + indent.writeScoped('if (a == b) {', '}', () { + indent.writeln('return TRUE;'); + }); + indent.writeScoped('if (a == nullptr || b == nullptr) {', '}', () { + indent.writeln('return FALSE;'); + }); + for (final NamedType field in classDefinition.fields) { + final String fieldName = _getFieldName(field.name); + if (field.type.isClass) { + final String fieldMethodPrefix = _getMethodPrefix( + module, + field.type.baseName, + ); + indent.writeScoped( + 'if (!${fieldMethodPrefix}_equals(a->$fieldName, b->$fieldName)) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + } else if (field.type.isEnum) { + if (field.type.isNullable) { + indent.writeScoped( + 'if ((a->$fieldName == nullptr) != (b->$fieldName == nullptr)) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + indent.writeScoped( + 'if (a->$fieldName != nullptr && *a->$fieldName != *b->$fieldName) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + } else { + indent.writeScoped( + 'if (a->$fieldName != b->$fieldName) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + } + } else if (_isNumericListType(field.type)) { + indent.writeScoped('if (a->$fieldName != b->$fieldName) {', '}', () { + indent.writeScoped( + 'if (a->$fieldName == nullptr || b->$fieldName == nullptr) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + indent.writeScoped( + 'if (a->${fieldName}_length != b->${fieldName}_length) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + if (field.type.baseName == 'Float32List' || + field.type.baseName == 'Float64List') { + indent.writeScoped( + 'for (size_t i = 0; i < a->${fieldName}_length; i++) {', + '}', + () { + indent.writeScoped( + 'if (!flpigeon_equals_double(a->$fieldName[i], b->$fieldName[i])) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + }, + ); + } else { + final elementSize = field.type.baseName == 'Uint8List' + ? 'sizeof(uint8_t)' + : field.type.baseName == 'Int32List' + ? 'sizeof(int32_t)' + : 'sizeof(int64_t)'; + indent.writeScoped( + 'if (memcmp(a->$fieldName, b->$fieldName, a->${fieldName}_length * $elementSize) != 0) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + } + }); + } else if (field.type.baseName == 'bool' || + field.type.baseName == 'int') { + if (field.type.isNullable) { + indent.writeScoped( + 'if ((a->$fieldName == nullptr) != (b->$fieldName == nullptr)) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + indent.writeScoped( + 'if (a->$fieldName != nullptr && *a->$fieldName != *b->$fieldName) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + } else { + indent.writeScoped( + 'if (a->$fieldName != b->$fieldName) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + } + } else if (field.type.baseName == 'double') { + if (field.type.isNullable) { + indent.writeScoped( + 'if ((a->$fieldName == nullptr) != (b->$fieldName == nullptr)) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + indent.writeScoped( + 'if (a->$fieldName != nullptr && !flpigeon_equals_double(*a->$fieldName, *b->$fieldName)) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + } else { + indent.writeScoped( + 'if (!flpigeon_equals_double(a->$fieldName, b->$fieldName)) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + } + } else if (field.type.baseName == 'String') { + indent.writeScoped( + 'if (g_strcmp0(a->$fieldName, b->$fieldName) != 0) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + } else { + indent.writeScoped( + 'if (!flpigeon_deep_equals(a->$fieldName, b->$fieldName)) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + } + } + indent.writeln('return TRUE;'); + }); + + indent.newln(); + indent.writeScoped('guint ${methodPrefix}_hash($className* self) {', '}', () { + indent.writeln('g_return_val_if_fail($testMacro(self), 0);'); + indent.writeln('guint result = 0;'); + for (final NamedType field in classDefinition.fields) { + final String fieldName = _getFieldName(field.name); + if (field.type.isClass) { + final String fieldMethodPrefix = _getMethodPrefix( + module, + field.type.baseName, + ); + indent.writeln( + 'result = result * 31 + ${fieldMethodPrefix}_hash(self->$fieldName);', + ); + } else if (field.type.isEnum) { + if (field.type.isNullable) { + indent.writeln( + 'result = result * 31 + (self->$fieldName != nullptr ? (guint)*self->$fieldName : 0);', + ); + } else { + indent.writeln('result = result * 31 + (guint)self->$fieldName;'); + } + } else if (_isNumericListType(field.type)) { + indent.writeScoped('{', '}', () { + indent.writeln('size_t len = self->${fieldName}_length;'); + final String elementTypeName = _getType( + module, + field.type, + isElementType: true, + ); + indent.writeln('const $elementTypeName* data = self->$fieldName;'); + indent.writeScoped('if (data != nullptr) {', '}', () { + indent.writeScoped('for (size_t i = 0; i < len; i++) {', '}', () { + if (field.type.baseName == 'Int64List') { + indent.writeln( + 'result = result * 31 + (guint)(data[i] ^ (data[i] >> 32));', + ); + } else if (field.type.baseName == 'Float32List' || + field.type.baseName == 'Float64List') { + indent.writeln( + 'result = result * 31 + flpigeon_hash_double(data[i]);', + ); + } else { + indent.writeln('result = result * 31 + (guint)data[i];'); + } + }); + }); + }); + } else if (field.type.baseName == 'bool' || + field.type.baseName == 'int') { + if (field.type.isNullable) { + indent.writeln( + 'result = result * 31 + (self->$fieldName != nullptr ? (guint)*self->$fieldName : 0);', + ); + } else { + indent.writeln('result = result * 31 + (guint)self->$fieldName;'); + } + } else if (field.type.baseName == 'double') { + if (field.type.isNullable) { + indent.writeln( + 'result = result * 31 + (self->$fieldName != nullptr ? flpigeon_hash_double(*self->$fieldName) : 0);', + ); + } else { + indent.writeln( + 'result = result * 31 + flpigeon_hash_double(self->$fieldName);', + ); + } + } else if (field.type.baseName == 'String') { + indent.writeln( + 'result = result * 31 + (self->$fieldName != nullptr ? g_str_hash(self->$fieldName) : 0);', + ); + } else { + indent.writeln( + 'result = result * 31 + flpigeon_deep_hash(self->$fieldName);', + ); + } + } + indent.writeln('return result;'); + }); } @override @@ -2254,6 +2554,7 @@ String _getType( TypeDeclaration type, { bool isOutput = false, bool primitive = false, + bool isElementType = false, }) { if (type.isClass) { return '${_getClassName(module, type.baseName)}*'; @@ -2273,14 +2574,29 @@ String _getType( } else if (type.baseName == 'String') { return isOutput ? 'gchar*' : 'const gchar*'; } else if (type.baseName == 'Uint8List') { + if (isElementType) { + return 'uint8_t'; + } return isOutput ? 'uint8_t*' : 'const uint8_t*'; } else if (type.baseName == 'Int32List') { + if (isElementType) { + return 'int32_t'; + } return isOutput ? 'int32_t*' : 'const int32_t*'; } else if (type.baseName == 'Int64List') { + if (isElementType) { + return 'int64_t'; + } return isOutput ? 'int64_t*' : 'const int64_t*'; } else if (type.baseName == 'Float32List') { + if (isElementType) { + return 'float'; + } return isOutput ? 'float*' : 'const float*'; } else if (type.baseName == 'Float64List') { + if (isElementType) { + return 'double'; + } return isOutput ? 'double*' : 'const double*'; } else { throw Exception('Unknown type ${type.baseName}'); @@ -2498,7 +2814,8 @@ String _fromFlValue(String module, TypeDeclaration type, String variableName) { } else if (type.baseName == 'Int64List') { return 'fl_value_get_int64_list($variableName)'; } else if (type.baseName == 'Float32List') { - return 'fl_value_get_float32_list($variableName)'; + // TODO(stuartmorgan): Support Float32List. + return 'nullptr'; } else if (type.baseName == 'Float64List') { return 'fl_value_get_float_list($variableName)'; } else { @@ -2512,3 +2829,251 @@ String _getResponseName(String name, String methodName) { methodName[0].toUpperCase() + methodName.substring(1); return '$name${upperMethodName}Response'; } + +void _writeHashHelpers(Indent indent) { + indent.writeScoped( + 'static guint G_GNUC_UNUSED flpigeon_hash_double(double v) {', + '}', + () { + indent.writeln('if (std::isnan(v)) return (guint)0x7FF80000;'); + indent.writeln('if (v == 0.0) v = 0.0;'); + indent.writeln('union { double d; uint64_t u; } u;'); + indent.writeln('u.d = v;'); + indent.writeln('return (guint)(u.u ^ (u.u >> 32));'); + }, + ); + indent.writeScoped( + 'static gboolean G_GNUC_UNUSED flpigeon_equals_double(double a, double b) {', + '}', + () { + indent.writeln('return (a == b) || (std::isnan(a) && std::isnan(b));'); + }, + ); +} + +void _writeDeepEquals(Indent indent) { + indent.writeScoped( + 'static gboolean G_GNUC_UNUSED flpigeon_deep_equals(FlValue* a, FlValue* b) {', + '}', + () { + indent.writeScoped('if (a == b) {', '}', () { + indent.writeln('return TRUE;'); + }); + indent.writeScoped('if (a == nullptr || b == nullptr) {', '}', () { + indent.writeln('return FALSE;'); + }); + indent.writeScoped( + 'if (fl_value_get_type(a) != fl_value_get_type(b)) {', + '}', + () { + indent.writeln('return FALSE;'); + }, + ); + indent.writeScoped('switch (fl_value_get_type(a)) {', '}', () { + indent.writeln('case FL_VALUE_TYPE_NULL:'); + indent.writeln(' return TRUE;'); + indent.writeln('case FL_VALUE_TYPE_BOOL:'); + indent.writeln( + ' return fl_value_get_bool(a) == fl_value_get_bool(b);', + ); + indent.writeln('case FL_VALUE_TYPE_INT:'); + indent.writeln(' return fl_value_get_int(a) == fl_value_get_int(b);'); + indent.writeln('case FL_VALUE_TYPE_FLOAT: {'); + indent.writeln( + ' return flpigeon_equals_double(fl_value_get_float(a), fl_value_get_float(b));', + ); + indent.writeln('}'); + indent.writeln('case FL_VALUE_TYPE_STRING:'); + indent.writeln( + ' return g_strcmp0(fl_value_get_string(a), fl_value_get_string(b)) == 0;', + ); + indent.writeln('case FL_VALUE_TYPE_UINT8_LIST:'); + indent.writeln( + ' return fl_value_get_length(a) == fl_value_get_length(b) &&', + ); + indent.writeln( + ' memcmp(fl_value_get_uint8_list(a), fl_value_get_uint8_list(b), fl_value_get_length(a)) == 0;', + ); + indent.writeln('case FL_VALUE_TYPE_INT32_LIST:'); + indent.writeln( + ' return fl_value_get_length(a) == fl_value_get_length(b) &&', + ); + indent.writeln( + ' memcmp(fl_value_get_int32_list(a), fl_value_get_int32_list(b), fl_value_get_length(a) * sizeof(int32_t)) == 0;', + ); + indent.writeln('case FL_VALUE_TYPE_INT64_LIST:'); + indent.writeln( + ' return fl_value_get_length(a) == fl_value_get_length(b) &&', + ); + indent.writeln( + ' memcmp(fl_value_get_int64_list(a), fl_value_get_int64_list(b), fl_value_get_length(a) * sizeof(int64_t)) == 0;', + ); + indent.writeln('case FL_VALUE_TYPE_FLOAT_LIST: {'); + indent.writeln(' size_t len = fl_value_get_length(a);'); + indent.writeln(' if (len != fl_value_get_length(b)) {'); + indent.writeln(' return FALSE;'); + indent.writeln(' }'); + indent.writeln(' const double* a_data = fl_value_get_float_list(a);'); + indent.writeln(' const double* b_data = fl_value_get_float_list(b);'); + indent.writeScoped(' for (size_t i = 0; i < len; i++) {', '}', () { + indent.writeln( + 'if (!flpigeon_equals_double(a_data[i], b_data[i])) {', + ); + indent.writeln(' return FALSE;'); + indent.writeln('}'); + }); + indent.writeln(' return TRUE;'); + indent.writeln('}'); + indent.writeln('case FL_VALUE_TYPE_LIST: {'); + indent.writeln(' size_t len = fl_value_get_length(a);'); + indent.writeln(' if (len != fl_value_get_length(b)) {'); + indent.writeln(' return FALSE;'); + indent.writeln(' }'); + indent.writeScoped(' for (size_t i = 0; i < len; i++) {', '}', () { + indent.writeln( + 'if (!flpigeon_deep_equals(fl_value_get_list_value(a, i), fl_value_get_list_value(b, i))) {', + ); + indent.writeln(' return FALSE;'); + indent.writeln('}'); + }); + indent.writeln(' return TRUE;'); + indent.writeln('}'); + indent.writeln('case FL_VALUE_TYPE_MAP: {'); + indent.writeln(' size_t len = fl_value_get_length(a);'); + indent.writeln(' if (len != fl_value_get_length(b)) {'); + indent.writeln(' return FALSE;'); + indent.writeln(' }'); + indent.writeScoped(' for (size_t i = 0; i < len; i++) {', '}', () { + indent.writeln('FlValue* key = fl_value_get_map_key(a, i);'); + indent.writeln('FlValue* val = fl_value_get_map_value(a, i);'); + indent.writeln('gboolean found = FALSE;'); + indent.writeScoped('for (size_t j = 0; j < len; j++) {', '}', () { + indent.writeln('FlValue* b_key = fl_value_get_map_key(b, j);'); + indent.writeScoped( + 'if (flpigeon_deep_equals(key, b_key)) {', + '}', + () { + indent.writeln( + 'FlValue* b_val = fl_value_get_map_value(b, j);', + ); + indent.writeln('if (flpigeon_deep_equals(val, b_val)) {'); + indent.nest(1, () { + indent.writeln('found = TRUE;'); + indent.writeln('break;'); + }); + indent.writeln('} else {'); + indent.nest(1, () { + indent.writeln('return FALSE;'); + }); + indent.writeln('}'); + }, + ); + }); + indent.writeln('if (!found) {'); + indent.writeln(' return FALSE;'); + indent.writeln('}'); + }); + indent.writeln(' return TRUE;'); + indent.writeln('}'); + indent.writeln('default:'); + indent.writeln(' return FALSE;'); + }); + indent.writeln('return FALSE;'); + }, + ); +} + +void _writeDeepHash(Indent indent) { + indent.writeScoped( + 'static guint G_GNUC_UNUSED flpigeon_deep_hash(FlValue* value) {', + '}', + () { + indent.writeln('if (value == nullptr) return 0;'); + indent.writeScoped('switch (fl_value_get_type(value)) {', '}', () { + indent.writeln('case FL_VALUE_TYPE_NULL:'); + indent.writeln(' return 0;'); + indent.writeln('case FL_VALUE_TYPE_BOOL:'); + indent.writeln(' return fl_value_get_bool(value) ? 1231 : 1237;'); + indent.writeln('case FL_VALUE_TYPE_INT: {'); + indent.writeln(' int64_t v = fl_value_get_int(value);'); + indent.writeln(' return (guint)(v ^ (v >> 32));'); + indent.writeln('}'); + indent.writeln('case FL_VALUE_TYPE_FLOAT:'); + indent.writeln( + ' return flpigeon_hash_double(fl_value_get_float(value));', + ); + indent.writeln('case FL_VALUE_TYPE_STRING:'); + indent.writeln(' return g_str_hash(fl_value_get_string(value));'); + indent.writeln('case FL_VALUE_TYPE_UINT8_LIST: {'); + indent.writeln(' guint result = 1;'); + indent.writeln(' size_t len = fl_value_get_length(value);'); + indent.writeln( + ' const uint8_t* data = fl_value_get_uint8_list(value);', + ); + indent.writeln( + ' for (size_t i = 0; i < len; i++) result = result * 31 + data[i];', + ); + indent.writeln(' return result;'); + indent.writeln('}'); + indent.writeln('case FL_VALUE_TYPE_INT32_LIST: {'); + indent.writeln(' guint result = 1;'); + indent.writeln(' size_t len = fl_value_get_length(value);'); + indent.writeln( + ' const int32_t* data = fl_value_get_int32_list(value);', + ); + indent.writeln( + ' for (size_t i = 0; i < len; i++) result = result * 31 + (guint)data[i];', + ); + indent.writeln(' return result;'); + indent.writeln('}'); + indent.writeln('case FL_VALUE_TYPE_INT64_LIST: {'); + indent.writeln(' guint result = 1;'); + indent.writeln(' size_t len = fl_value_get_length(value);'); + indent.writeln( + ' const int64_t* data = fl_value_get_int64_list(value);', + ); + indent.writeln( + ' for (size_t i = 0; i < len; i++) result = result * 31 + (guint)(data[i] ^ (data[i] >> 32));', + ); + indent.writeln(' return result;'); + indent.writeln('}'); + indent.writeln('case FL_VALUE_TYPE_FLOAT_LIST: {'); + indent.writeln(' guint result = 1;'); + indent.writeln(' size_t len = fl_value_get_length(value);'); + indent.writeln( + ' const double* data = fl_value_get_float_list(value);', + ); + indent.writeScoped(' for (size_t i = 0; i < len; i++) {', '}', () { + indent.writeln( + 'result = result * 31 + flpigeon_hash_double(data[i]);', + ); + }); + indent.writeln(' return result;'); + indent.writeln('}'); + indent.writeln('case FL_VALUE_TYPE_LIST: {'); + indent.writeln(' guint result = 1;'); + indent.writeln(' size_t len = fl_value_get_length(value);'); + indent.writeScoped(' for (size_t i = 0; i < len; i++) {', '}', () { + indent.writeln( + 'result = result * 31 + flpigeon_deep_hash(fl_value_get_list_value(value, i));', + ); + }); + indent.writeln(' return result;'); + indent.writeln('}'); + indent.writeln('case FL_VALUE_TYPE_MAP: {'); + indent.writeln(' guint result = 0;'); + indent.writeln(' size_t len = fl_value_get_length(value);'); + indent.writeScoped(' for (size_t i = 0; i < len; i++) {', '}', () { + indent.writeln( + 'result += (flpigeon_deep_hash(fl_value_get_map_key(value, i)) ^ flpigeon_deep_hash(fl_value_get_map_value(value, i)));', + ); + }); + indent.writeln(' return result;'); + indent.writeln('}'); + indent.writeln('default:'); + indent.writeln(' return (guint)fl_value_get_type(value);'); + }); + indent.writeln('return 0;'); + }, + ); +} diff --git a/packages/pigeon/lib/src/java/java_generator.dart b/packages/pigeon/lib/src/java/java_generator.dart index 2f08bc3a0c61..38a35dff1b91 100644 --- a/packages/pigeon/lib/src/java/java_generator.dart +++ b/packages/pigeon/lib/src/java/java_generator.dart @@ -206,6 +206,9 @@ class JavaGenerator extends StructuredGenerator { } indent.writeln('public class ${generatorOptions.className!} {'); indent.inc(); + _writeNumberHelpers(indent); + _writeDeepEquals(indent); + _writeDeepHashCode(indent); } @override @@ -381,13 +384,7 @@ class JavaGenerator extends StructuredGenerator { final Iterable checks = classDefinition.fields.map(( NamedType field, ) { - // Objects.equals only does pointer equality for array types. - if (_javaTypeIsArray(field.type)) { - return 'Arrays.equals(${field.name}, that.${field.name})'; - } - return field.type.isNullable - ? 'Objects.equals(${field.name}, that.${field.name})' - : '${field.name}.equals(that.${field.name})'; + return 'pigeonDeepEquals(${field.name}, that.${field.name})'; }); indent.writeln('return ${checks.join(' && ')};'); }); @@ -396,36 +393,267 @@ class JavaGenerator extends StructuredGenerator { // Implement hashCode(). indent.writeln('@Override'); indent.writeScoped('public int hashCode() {', '}', () { - // As with equalty checks, arrays need special handling. - final Iterable arrayFieldNames = classDefinition.fields - .where((NamedType field) => _javaTypeIsArray(field.type)) - .map((NamedType field) => field.name); - final Iterable nonArrayFieldNames = classDefinition.fields - .where((NamedType field) => !_javaTypeIsArray(field.type)) - .map((NamedType field) => field.name); - final nonArrayHashValue = nonArrayFieldNames.isNotEmpty - ? 'Objects.hash(${nonArrayFieldNames.join(', ')})' - : '0'; - - if (arrayFieldNames.isEmpty) { - // Return directly if there are no array variables, to avoid redundant - // variable lint warnings. - indent.writeln('return $nonArrayHashValue;'); + final Iterable fieldNames = classDefinition.fields.map( + (NamedType field) => field.name, + ); + if (fieldNames.isEmpty) { + indent.writeln('return Objects.hash(getClass());'); } else { - const resultVar = '${varNamePrefix}result'; - indent.writeln('int $resultVar = $nonArrayHashValue;'); - // Manually mix in the Arrays.hashCode values. - for (final name in arrayFieldNames) { - indent.writeln( - '$resultVar = 31 * $resultVar + Arrays.hashCode($name);', - ); - } - indent.writeln('return $resultVar;'); + indent.writeln( + 'Object[] fields = new Object[] {getClass(), ${fieldNames.join(', ')}};', + ); + indent.writeln('return pigeonDeepHashCode(fields);'); } }); indent.newln(); } + void _writeDeepEquals(Indent indent) { + indent.writeScoped( + 'static boolean pigeonDeepEquals(Object a, Object b) {', + '}', + () { + indent.writeln('if (a == b) { return true; }'); + indent.writeln('if (a == null || b == null) { return false; }'); + indent.writeScoped( + 'if (a instanceof byte[] && b instanceof byte[]) {', + '}', + () { + indent.writeln('return Arrays.equals((byte[]) a, (byte[]) b);'); + }, + ); + indent.writeScoped( + 'if (a instanceof int[] && b instanceof int[]) {', + '}', + () { + indent.writeln('return Arrays.equals((int[]) a, (int[]) b);'); + }, + ); + indent.writeScoped( + 'if (a instanceof long[] && b instanceof long[]) {', + '}', + () { + indent.writeln('return Arrays.equals((long[]) a, (long[]) b);'); + }, + ); + indent.writeScoped( + 'if (a instanceof double[] && b instanceof double[]) {', + '}', + () { + indent.writeln('double[] da = (double[]) a;'); + indent.writeln('double[] db = (double[]) b;'); + indent.writeln('if (da.length != db.length) return false;'); + indent.writeScoped( + 'for (int i = 0; i < da.length; i++) {', + '}', + () { + indent.writeScoped( + 'if (!pigeonDoubleEquals(da[i], db[i])) {', + '}', + () { + indent.writeln('return false;'); + }, + ); + }, + ); + indent.writeln('return true;'); + }, + ); + indent.writeScoped( + 'if (a instanceof List && b instanceof List) {', + '}', + () { + indent.writeln('List listA = (List) a;'); + indent.writeln('List listB = (List) b;'); + indent.writeln( + 'if (listA.size() != listB.size()) { return false; }', + ); + indent.writeScoped( + 'for (int i = 0; i < listA.size(); i++) {', + '}', + () { + indent.writeScoped( + 'if (!pigeonDeepEquals(listA.get(i), listB.get(i))) {', + '}', + () { + indent.writeln('return false;'); + }, + ); + }, + ); + indent.writeln('return true;'); + }, + ); + indent.writeScoped( + 'if (a instanceof Map && b instanceof Map) {', + '}', + () { + indent.writeln('Map mapA = (Map) a;'); + indent.writeln('Map mapB = (Map) b;'); + indent.writeln('if (mapA.size() != mapB.size()) { return false; }'); + indent.writeScoped( + 'for (Map.Entry entryA : mapA.entrySet()) {', + '}', + () { + indent.writeln('Object keyA = entryA.getKey();'); + indent.writeln('Object valueA = entryA.getValue();'); + indent.writeln('boolean found = false;'); + indent.writeScoped( + 'for (Map.Entry entryB : mapB.entrySet()) {', + '}', + () { + indent.writeln('Object keyB = entryB.getKey();'); + indent.writeScoped( + 'if (pigeonDeepEquals(keyA, keyB)) {', + '}', + () { + indent.writeln('Object valueB = entryB.getValue();'); + indent.writeln( + 'if (pigeonDeepEquals(valueA, valueB)) {', + ); + indent.nest(1, () { + indent.writeln('found = true;'); + indent.writeln('break;'); + }); + indent.writeln('} else {'); + indent.nest(1, () { + indent.writeln('return false;'); + }); + indent.writeln('}'); + }, + ); + }, + ); + indent.writeScoped('if (!found) {', '}', () { + indent.writeln('return false;'); + }); + }, + ); + indent.writeln('return true;'); + }, + ); + indent.writeScoped( + 'if (a instanceof Double && b instanceof Double) {', + '}', + () { + indent.writeln( + 'return pigeonDoubleEquals((double) a, (double) b);', + ); + }, + ); + indent.writeScoped( + 'if (a instanceof Float && b instanceof Float) {', + '}', + () { + indent.writeln('return pigeonFloatEquals((float) a, (float) b);'); + }, + ); + indent.writeln('return a.equals(b);'); + }, + ); + indent.newln(); + } + + void _writeDeepHashCode(Indent indent) { + indent.writeScoped('static int pigeonDeepHashCode(Object value) {', '}', () { + indent.writeln('if (value == null) { return 0; }'); + indent.writeScoped('if (value instanceof byte[]) {', '}', () { + indent.writeln('return Arrays.hashCode((byte[]) value);'); + }); + indent.writeScoped('if (value instanceof int[]) {', '}', () { + indent.writeln('return Arrays.hashCode((int[]) value);'); + }); + indent.writeScoped('if (value instanceof long[]) {', '}', () { + indent.writeln('return Arrays.hashCode((long[]) value);'); + }); + indent.writeScoped('if (value instanceof double[]) {', '}', () { + indent.writeln('double[] da = (double[]) value;'); + indent.writeln('int result = 1;'); + indent.writeScoped('for (double d : da) {', '}', () { + indent.writeln('result = 31 * result + pigeonDoubleHashCode(d);'); + }); + indent.writeln('return result;'); + }); + indent.writeScoped('if (value instanceof List) {', '}', () { + indent.writeln('int result = 1;'); + indent.writeScoped('for (Object item : (List) value) {', '}', () { + indent.writeln('result = 31 * result + pigeonDeepHashCode(item);'); + }); + indent.writeln('return result;'); + }); + indent.writeScoped('if (value instanceof Map) {', '}', () { + indent.writeln('int result = 0;'); + indent.writeScoped( + 'for (Map.Entry entry : ((Map) value).entrySet()) {', + '}', + () { + indent.writeln( + 'result += (pigeonDeepHashCode(entry.getKey()) ^ pigeonDeepHashCode(entry.getValue()));', + ); + }, + ); + indent.writeln('return result;'); + }); + indent.writeScoped('if (value instanceof Object[]) {', '}', () { + indent.writeln('int result = 1;'); + indent.writeScoped('for (Object item : (Object[]) value) {', '}', () { + indent.writeln('result = 31 * result + pigeonDeepHashCode(item);'); + }); + indent.writeln('return result;'); + }); + indent.writeScoped('if (value instanceof Double) {', '}', () { + indent.writeln('return pigeonDoubleHashCode((double) value);'); + }); + indent.writeScoped('if (value instanceof Float) {', '}', () { + indent.writeln('return pigeonFloatHashCode((float) value);'); + }); + indent.writeln('return value.hashCode();'); + }); + indent.newln(); + } + + void _writeNumberHelpers(Indent indent) { + indent.writeScoped( + 'static boolean pigeonDoubleEquals(double a, double b) {', + '}', + () { + indent.writeln('// Normalize -0.0 to 0.0 and handle NaN equality.'); + indent.writeln( + 'return (a == 0.0 ? 0.0 : a) == (b == 0.0 ? 0.0 : b) || (Double.isNaN(a) && Double.isNaN(b));', + ); + }, + ); + indent.newln(); + indent.writeScoped( + 'static boolean pigeonFloatEquals(float a, float b) {', + '}', + () { + indent.writeln('// Normalize -0.0 to 0.0 and handle NaN equality.'); + indent.writeln( + 'return (a == 0.0f ? 0.0f : a) == (b == 0.0f ? 0.0f : b) || (Float.isNaN(a) && Float.isNaN(b));', + ); + }, + ); + indent.newln(); + indent.writeScoped('static int pigeonDoubleHashCode(double d) {', '}', () { + indent.writeln( + '// Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes.', + ); + indent.writeln('if (d == 0.0) d = 0.0;'); + indent.writeln('long bits = Double.doubleToLongBits(d);'); + indent.writeln('return (int) (bits ^ (bits >>> 32));'); + }); + indent.newln(); + indent.writeScoped('static int pigeonFloatHashCode(float f) {', '}', () { + indent.writeln( + '// Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes.', + ); + indent.writeln('if (f == 0.0f) f = 0.0f;'); + indent.writeln('return Float.floatToIntBits(f);'); + }); + indent.newln(); + } + void _writeClassBuilder( InternalJavaOptions generatorOptions, Root root, @@ -1370,10 +1598,6 @@ String _javaTypeForBuiltinGenericDartType( } } -bool _javaTypeIsArray(TypeDeclaration type) { - return _javaTypeForBuiltinDartType(type)?.endsWith('[]') ?? false; -} - String? _javaTypeForBuiltinDartType(TypeDeclaration type) { const javaTypeForDartTypeMap = { 'bool': 'Boolean', diff --git a/packages/pigeon/lib/src/kotlin/kotlin_generator.dart b/packages/pigeon/lib/src/kotlin/kotlin_generator.dart index 7df50a975990..c6afb4147cdc 100644 --- a/packages/pigeon/lib/src/kotlin/kotlin_generator.dart +++ b/packages/pigeon/lib/src/kotlin/kotlin_generator.dart @@ -320,19 +320,49 @@ class KotlinGenerator extends StructuredGenerator { 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 (other == null || other.javaClass != javaClass) {', + '}', + () { + indent.writeln('return false'); + }, + ); indent.writeScoped('if (this === other) {', '}', () { indent.writeln('return true'); }); - indent.write( - 'return ${_getUtilsClassName(generatorOptions)}.deepEquals(toList(), other.toList())', + + indent.writeln('val other = other as ${classDefinition.name}'); + final Iterable fields = getFieldsInSerializationOrder( + classDefinition, ); + if (fields.isEmpty) { + indent.writeln('return true'); + } else { + final String utils = _getUtilsClassName(generatorOptions); + final String comparisons = fields + .map( + (NamedType field) => + '$utils.deepEquals(this.${field.name}, other.${field.name})', + ) + .join(' && '); + indent.writeln('return $comparisons'); + } }); indent.newln(); - indent.writeln('override fun hashCode(): Int = toList().hashCode()'); + indent.writeScoped('override fun hashCode(): Int {', '}', () { + final Iterable fields = getFieldsInSerializationOrder( + classDefinition, + ); + final String utils = _getUtilsClassName(generatorOptions); + indent.writeln('var result = javaClass.hashCode()'); + for (final field in fields) { + indent.writeln( + 'result = 31 * result + $utils.deepHash(this.${field.name})', + ); + } + indent.writeln('return result'); + }); } void _writeDataClassSignature( @@ -1317,35 +1347,139 @@ if (wrapped == null) { void _writeDeepEquals(InternalKotlinOptions generatorOptions, Indent indent) { indent.format(''' fun deepEquals(a: Any?, b: Any?): Boolean { + if (a === b) { + return true + } if (a is ByteArray && b is ByteArray) { - return a.contentEquals(b) + return a.contentEquals(b) } if (a is IntArray && b is IntArray) { - return a.contentEquals(b) + return a.contentEquals(b) } if (a is LongArray && b is LongArray) { - return a.contentEquals(b) + return a.contentEquals(b) } if (a is DoubleArray && b is DoubleArray) { - return a.contentEquals(b) + if (a.size != b.size) return false + for (i in a.indices) { + if (!doubleEquals(a[i], b[i])) return false + } + return true + } + if (a is FloatArray && b is FloatArray) { + if (a.size != b.size) return false + for (i in a.indices) { + if (!floatEquals(a[i], b[i])) return false + } + return true } if (a is Array<*> && b is Array<*>) { - return a.size == b.size && - a.indices.all{ deepEquals(a[it], b[it]) } + return a.contentDeepEquals(b) } if (a is List<*> && b is List<*>) { return a.size == b.size && - a.indices.all{ deepEquals(a[it], b[it]) } + a.indices.all { deepEquals(a[it], b[it]) } } if (a is Map<*, *> && b is Map<*, *>) { - return a.size == b.size && a.all { - (b as Map).contains(it.key) && - deepEquals(it.value, b[it.key]) + if (a.size != b.size) return false + for (entry in a) { + val key = entry.key + var found = false + for (bEntry in b) { + if (deepEquals(key, bEntry.key)) { + if (deepEquals(entry.value, bEntry.value)) { + found = true + break + } else { + return false + } + } + } + if (!found) return false } + return true + } + if (a is Double && b is Double) { + return doubleEquals(a, b) + } + if (a is Float && b is Float) { + return floatEquals(a, b) } return a == b } - '''); +'''); + } + + void _writeDeepHash(InternalKotlinOptions generatorOptions, Indent indent) { + indent.format(''' +fun deepHash(value: Any?): Int { + return when (value) { + null -> 0 + is ByteArray -> value.contentHashCode() + is IntArray -> value.contentHashCode() + is LongArray -> value.contentHashCode() + is DoubleArray -> { + var result = 1 + for (item in value) { + result = 31 * result + doubleHash(item) + } + result + } + is FloatArray -> { + var result = 1 + for (item in value) { + result = 31 * result + floatHash(item) + } + result + } + is Array<*> -> value.contentDeepHashCode() + is List<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is Map<*, *> -> { + var result = 0 + for (entry in value) { + result += (deepHash(entry.key) xor deepHash(entry.value)) + } + result + } + is Double -> doubleHash(value) + is Float -> floatHash(value) + else -> value.hashCode() + } +} +'''); + } + + void _writeNumberHelpers(Indent indent) { + indent.format(''' +fun doubleEquals(a: Double, b: Double): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0) 0.0 else a) == (if (b == 0.0) 0.0 else b) || (a.isNaN() && b.isNaN()) +} + +fun floatEquals(a: Float, b: Float): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0f) 0.0f else a) == (if (b == 0.0f) 0.0f else b) || (a.isNaN() && b.isNaN()) +} + +fun doubleHash(d: Double): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (d == 0.0) 0.0 else d + val bits = java.lang.Double.doubleToLongBits(normalized) + return (bits xor (bits ushr 32)).toInt() +} + +fun floatHash(f: Float): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (f == 0.0f) 0.0f else f + return java.lang.Float.floatToIntBits(normalized) +} +'''); } @override @@ -1367,7 +1501,9 @@ fun deepEquals(a: Any?, b: Any?): Boolean { _writeWrapError(generatorOptions, indent); } if (root.classes.isNotEmpty) { + _writeNumberHelpers(indent); _writeDeepEquals(generatorOptions, indent); + _writeDeepHash(generatorOptions, indent); } }, ); diff --git a/packages/pigeon/lib/src/objc/objc_generator.dart b/packages/pigeon/lib/src/objc/objc_generator.dart index e76459a19dc9..a19c7c668b50 100644 --- a/packages/pigeon/lib/src/objc/objc_generator.dart +++ b/packages/pigeon/lib/src/objc/objc_generator.dart @@ -518,6 +518,8 @@ class ObjcSourceGenerator extends StructuredGenerator { indent.writeln('@import Flutter;'); indent.writeln('#endif'); indent.newln(); + _writeDeepEquals(indent); + _writeDeepHash(indent); } @override @@ -614,10 +616,76 @@ class ObjcSourceGenerator extends StructuredGenerator { classDefinition, dartPackageName: dartPackageName, ); + _writeObjcEquality(generatorOptions, indent, classDefinition); indent.writeln('@end'); indent.newln(); } + void _writeObjcEquality( + InternalObjcOptions generatorOptions, + Indent indent, + Class classDefinition, + ) { + final String className = _className( + generatorOptions.prefix, + classDefinition.name, + ); + indent.write('- (BOOL)isEqual:(id)object '); + indent.addScoped('{', '}', () { + indent.writeScoped('if (self == object) {', '}', () { + indent.writeln('return YES;'); + }); + indent.writeScoped( + 'if (![object isKindOfClass:[self class]]) {', + '}', + () { + indent.writeln('return NO;'); + }, + ); + indent.writeln('$className *other = ($className *)object;'); + final Iterable checks = classDefinition.fields.map(( + NamedType field, + ) { + final String name = field.name; + if (_usesPrimitive(field.type)) { + if (field.type.baseName == 'double') { + return '(self.$name == other.$name || (isnan(self.$name) && isnan(other.$name)))'; + } + return 'self.$name == other.$name'; + } else { + return 'FLTPigeonDeepEquals(self.$name, other.$name)'; + } + }); + if (checks.isEmpty) { + indent.writeln('return YES;'); + } else { + indent.writeln('return ${checks.join(' && ')};'); + } + }); + indent.newln(); + indent.write('- (NSUInteger)hash '); + indent.addScoped('{', '}', () { + indent.writeln('NSUInteger result = [self class].hash;'); + for (final NamedType field in classDefinition.fields) { + final String name = field.name; + if (_usesPrimitive(field.type)) { + if (field.type.baseName == 'double') { + indent.writeln( + 'result = result * 31 + (isnan(self.$name) ? (NSUInteger)0x7FF8000000000000 : @(self.$name).hash);', + ); + } else { + indent.writeln('result = result * 31 + @(self.$name).hash;'); + } + } else { + indent.writeln( + 'result = result * 31 + FLTPigeonDeepHash(self.$name);', + ); + } + } + indent.writeln('return result;'); + }); + } + @override void writeClassEncode( InternalObjcOptions generatorOptions, @@ -1601,6 +1669,104 @@ const Map _objcTypeForNonNullableDartTypeMap = 'Object': _ObjcType(baseName: 'id'), }; +void _writeDeepEquals(Indent indent) { + indent.format(''' +static BOOL __attribute__((unused)) FLTPigeonDeepEquals(id _Nullable a, id _Nullable b) { + if (a == b) { + return YES; + } + if (a == nil || b == nil) { + return NO; + } + if ([a isKindOfClass:[NSNumber class]] && [b isKindOfClass:[NSNumber class]]) { + NSNumber *na = (NSNumber *)a; + NSNumber *nb = (NSNumber *)b; + // Normalize -0.0 to 0.0 and handle NaN equality. + return na.doubleValue == nb.doubleValue || (isnan(na.doubleValue) && isnan(nb.doubleValue)); + } + if ([a isKindOfClass:[NSArray class]] && [b isKindOfClass:[NSArray class]]) { + NSArray *arrayA = (NSArray *)a; + NSArray *arrayB = (NSArray *)b; + if (arrayA.count != arrayB.count) { + return NO; + } + for (NSUInteger i = 0; i < arrayA.count; i++) { + if (!FLTPigeonDeepEquals(arrayA[i], arrayB[i])) { + return NO; + } + } + return YES; + } + if ([a isKindOfClass:[NSDictionary class]] && [b isKindOfClass:[NSDictionary class]]) { + NSDictionary *dictA = (NSDictionary *)a; + NSDictionary *dictB = (NSDictionary *)b; + if (dictA.count != dictB.count) { + return NO; + } + for (id keyA in dictA) { + id valueA = dictA[keyA]; + BOOL found = NO; + for (id keyB in dictB) { + if (FLTPigeonDeepEquals(keyA, keyB)) { + id valueB = dictB[keyB]; + if (FLTPigeonDeepEquals(valueA, valueB)) { + found = YES; + break; + } else { + return NO; + } + } + } + if (!found) { + return NO; + } + } + return YES; + } + return [a isEqual:b]; +} +'''); +} + +void _writeDeepHash(Indent indent) { + indent.format(''' +static NSUInteger __attribute__((unused)) FLTPigeonDeepHash(id _Nullable value) { + if (value == nil) { + return 0; + } + if ([value isKindOfClass:[NSNumber class]]) { + NSNumber *n = (NSNumber *)value; + double d = n.doubleValue; + if (isnan(d)) { + // Normalize NaN to a consistent hash. + return (NSUInteger)0x7FF8000000000000; + } + if (d == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + d = 0.0; + } + return @(d).hash; + } + if ([value isKindOfClass:[NSArray class]]) { + NSUInteger result = 1; + for (id item in (NSArray *)value) { + result = result * 31 + FLTPigeonDeepHash(item); + } + return result; + } + if ([value isKindOfClass:[NSDictionary class]]) { + NSUInteger result = 0; + NSDictionary *dict = (NSDictionary *)value; + for (id key in dict) { + result += (FLTPigeonDeepHash(key) ^ FLTPigeonDeepHash(dict[key])); + } + return result; + } + return [value hash]; +} +'''); +} + bool _usesPrimitive(TypeDeclaration type) { // Only non-nullable types are unboxed. if (!type.isNullable) { diff --git a/packages/pigeon/lib/src/swift/swift_generator.dart b/packages/pigeon/lib/src/swift/swift_generator.dart index 220f0ba8d6dd..9afa1be2a57e 100644 --- a/packages/pigeon/lib/src/swift/swift_generator.dart +++ b/packages/pigeon/lib/src/swift/swift_generator.dart @@ -661,21 +661,46 @@ if (wrapped == nil) { 'static func == (lhs: ${classDefinition.name}, rhs: ${classDefinition.name}) -> Bool {', '}', () { + indent.writeScoped( + 'if Swift.type(of: lhs) != Swift.type(of: rhs) {', + '}', + () { + indent.writeln('return false'); + }, + ); if (classDefinition.isSwiftClass) { indent.writeScoped('if (lhs === rhs) {', '}', () { indent.writeln('return true'); }); } - indent.write( - 'return deepEquals${generatorOptions.fileSpecificClassNameComponent}(lhs.toList(), rhs.toList())', + final Iterable fields = getFieldsInSerializationOrder( + classDefinition, ); + if (fields.isEmpty) { + indent.writeln('return true'); + } else { + final String comparisons = fields + .map( + (NamedType field) => + 'deepEquals${generatorOptions.fileSpecificClassNameComponent ?? ''}(lhs.${field.name}, rhs.${field.name})', + ) + .join(' && '); + indent.writeln('return $comparisons'); + } }, ); + indent.newln(); indent.writeScoped('func hash(into hasher: inout Hasher) {', '}', () { - indent.writeln( - 'deepHash${generatorOptions.fileSpecificClassNameComponent}(value: toList(), hasher: &hasher)', + indent.writeln('hasher.combine("${classDefinition.name}")'); + final Iterable fields = getFieldsInSerializationOrder( + classDefinition, ); + for (final field in fields) { + indent.writeln( + 'deepHash${generatorOptions.fileSpecificClassNameComponent ?? ''}(value: ${field.name}, hasher: &hasher)', + ); + } }); } @@ -1449,7 +1474,7 @@ if (wrapped == nil) { indent.write('return '); indent.addScoped('[', ']', () { indent.writeln(r'"\(error)",'); - indent.writeln(r'"\(type(of: error))",'); + indent.writeln(r'"\(Swift.type(of: error))",'); indent.writeln(r'"Stacktrace: \(Thread.callStackSymbols)",'); }); }); @@ -1482,8 +1507,29 @@ private func nilOrValue(_ value: Any?) -> T? { } void _writeDeepEquals(InternalSwiftOptions generatorOptions, Indent indent) { + final deepEqualsName = + 'deepEquals${generatorOptions.fileSpecificClassNameComponent ?? ''}'; + final deepHashName = + 'deepHash${generatorOptions.fileSpecificClassNameComponent ?? ''}'; + final doubleEqualsName = + 'doubleEquals${generatorOptions.fileSpecificClassNameComponent ?? ''}'; + final doubleHashName = + 'doubleHash${generatorOptions.fileSpecificClassNameComponent ?? ''}'; indent.format(''' -func deepEquals${generatorOptions.fileSpecificClassNameComponent}(_ lhs: Any?, _ rhs: Any?) -> Bool { +private func $doubleEqualsName(_ lhs: Double, _ rhs: Double) -> Bool { + return (lhs.isNaN && rhs.isNaN) || lhs == rhs +} + +private func $doubleHashName(_ value: Double, _ hasher: inout Hasher) { + if value.isNaN { + hasher.combine(0x7FF8000000000000) + } else { + // Normalize -0.0 to 0.0 + hasher.combine(value == 0 ? 0 : value) + } +} + +func $deepEqualsName(_ lhs: Any?, _ rhs: Any?) -> Bool { let cleanLhs = nilOrValue(lhs) as Any? let cleanRhs = nilOrValue(rhs) as Any? switch (cleanLhs, cleanRhs) { @@ -1493,59 +1539,92 @@ func deepEquals${generatorOptions.fileSpecificClassNameComponent}(_ lhs: Any?, _ case (nil, _), (_, nil): return false - case is (Void, Void): + case (let lhs as AnyObject, let rhs as AnyObject) where lhs === rhs: return true - case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable): - return cleanLhsHashable == cleanRhsHashable + case is (Void, Void): + return true - case let (cleanLhsArray, cleanRhsArray) as ([Any?], [Any?]): - guard cleanLhsArray.count == cleanRhsArray.count else { return false } - for (index, element) in cleanLhsArray.enumerated() { - if !deepEquals${generatorOptions.fileSpecificClassNameComponent}(element, cleanRhsArray[index]) { + case (let lhsArray, let rhsArray) as ([Any?], [Any?]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !$deepEqualsName(element, rhsArray[index]) { return false } } return true - case let (cleanLhsDictionary, cleanRhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): - guard cleanLhsDictionary.count == cleanRhsDictionary.count else { return false } - for (key, cleanLhsValue) in cleanLhsDictionary { - guard cleanRhsDictionary.index(forKey: key) != nil else { return false } - if !deepEquals${generatorOptions.fileSpecificClassNameComponent}(cleanLhsValue, cleanRhsDictionary[key]!) { + case (let lhsArray, let rhsArray) as ([Double], [Double]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !$doubleEqualsName(element, rhsArray[index]) { return false } } return true + case (let lhsDictionary, let rhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): + guard lhsDictionary.count == rhsDictionary.count else { return false } + for (lhsKey, lhsValue) in lhsDictionary { + var found = false + for (rhsKey, rhsValue) in rhsDictionary { + if $deepEqualsName(lhsKey, rhsKey) { + if $deepEqualsName(lhsValue, rhsValue) { + found = true + break + } else { + return false + } + } + } + if !found { return false } + } + return true + + case (let lhs as Double, let rhs as Double): + return $doubleEqualsName(lhs, rhs) + + case (let lhsHashable, let rhsHashable) as (AnyHashable, AnyHashable): + return lhsHashable == rhsHashable + default: - // Any other type shouldn't be able to be used with pigeon. File an issue if you find this to be untrue. return false } } -func deepHash${generatorOptions.fileSpecificClassNameComponent}(value: Any?, hasher: inout Hasher) { - if let valueList = value as? [AnyHashable] { - for item in valueList { deepHash${generatorOptions.fileSpecificClassNameComponent}(value: item, hasher: &hasher) } - return - } - - if let valueDict = value as? [AnyHashable: AnyHashable] { - for key in valueDict.keys { - hasher.combine(key) - deepHash${generatorOptions.fileSpecificClassNameComponent}(value: valueDict[key]!, hasher: &hasher) +func $deepHashName(value: Any?, hasher: inout Hasher) { + let cleanValue = nilOrValue(value) as Any? + if let cleanValue = cleanValue { + if let doubleValue = cleanValue as? Double { + $doubleHashName(doubleValue, &hasher) + } else if let valueList = cleanValue as? [Any?] { + for item in valueList { + $deepHashName(value: item, hasher: &hasher) + } + } else if let valueList = cleanValue as? [Double] { + for item in valueList { + $doubleHashName(item, &hasher) + } + } else if let valueDict = cleanValue as? [AnyHashable: Any?] { + var result = 0 + for (key, value) in valueDict { + var entryKeyHasher = Hasher() + $deepHashName(value: key, hasher: &entryKeyHasher) + var entryValueHasher = Hasher() + $deepHashName(value: value, hasher: &entryValueHasher) + result = result &+ (entryKeyHasher.finalize() ^ entryValueHasher.finalize()) + } + hasher.combine(result) + } else if let hashableValue = cleanValue as? AnyHashable { + hasher.combine(hashableValue) + } else { + hasher.combine(String(describing: cleanValue)) } - return - } - - if let hashableValue = value as? AnyHashable { - hasher.combine(hashableValue.hashValue) + } else { + hasher.combine(0) } - - return hasher.combine(String(describing: value)) } - - '''); +'''); } @override diff --git a/packages/pigeon/pigeons/core_tests.dart b/packages/pigeon/pigeons/core_tests.dart index 8795c8de900a..f55c0bbfd519 100644 --- a/packages/pigeon/pigeons/core_tests.dart +++ b/packages/pigeon/pigeons/core_tests.dart @@ -435,6 +435,17 @@ abstract class HostIntegrationCoreApi { // ========== Synchronous nullable method tests ========== + /// Returns the result of platform-side equality check. + bool areAllNullableTypesEqual(AllNullableTypes a, AllNullableTypes b); + + /// Returns the platform-side hash code for the given object. + int getAllNullableTypesHash(AllNullableTypes value); + + /// Returns the platform-side hash code for the given object. + int getAllNullableTypesWithoutRecursionHash( + AllNullableTypesWithoutRecursion value, + ); + /// Returns the passed object, to test serialization and deserialization. @ObjCSelector('echoAllNullableTypes:') @SwiftFunction('echo(_:)') diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/AlternateLanguageTestPlugin.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/AlternateLanguageTestPlugin.java index 4ece8628d399..5c46688a6d95 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/AlternateLanguageTestPlugin.java +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/AlternateLanguageTestPlugin.java @@ -61,6 +61,23 @@ public void noop() {} return everything; } + @Override + public @NonNull Boolean areAllNullableTypesEqual( + @NonNull AllNullableTypes a, @NonNull AllNullableTypes b) { + return a.equals(b); + } + + @Override + public @NonNull Long getAllNullableTypesHash(@NonNull AllNullableTypes value) { + return (long) value.hashCode(); + } + + @Override + public @NonNull Long getAllNullableTypesWithoutRecursionHash( + @NonNull AllNullableTypesWithoutRecursion value) { + return (long) value.hashCode(); + } + @Override public @Nullable AllNullableTypesWithoutRecursion echoAllNullableTypesWithoutRecursion( @Nullable AllNullableTypesWithoutRecursion everything) { diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java index 66e0f3516fa4..1bf19274b4f8 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java @@ -26,11 +26,160 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; /** Generated class from Pigeon. */ @SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression", "serial"}) public class CoreTests { + static boolean pigeonDoubleEquals(double a, double b) { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (a == 0.0 ? 0.0 : a) == (b == 0.0 ? 0.0 : b) || (Double.isNaN(a) && Double.isNaN(b)); + } + + static boolean pigeonFloatEquals(float a, float b) { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (a == 0.0f ? 0.0f : a) == (b == 0.0f ? 0.0f : b) || (Float.isNaN(a) && Float.isNaN(b)); + } + + static int pigeonDoubleHashCode(double d) { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + if (d == 0.0) d = 0.0; + long bits = Double.doubleToLongBits(d); + return (int) (bits ^ (bits >>> 32)); + } + + static int pigeonFloatHashCode(float f) { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + if (f == 0.0f) f = 0.0f; + return Float.floatToIntBits(f); + } + + static boolean pigeonDeepEquals(Object a, Object b) { + if (a == b) { + return true; + } + if (a == null || b == null) { + return false; + } + if (a instanceof byte[] && b instanceof byte[]) { + return Arrays.equals((byte[]) a, (byte[]) b); + } + if (a instanceof int[] && b instanceof int[]) { + return Arrays.equals((int[]) a, (int[]) b); + } + if (a instanceof long[] && b instanceof long[]) { + return Arrays.equals((long[]) a, (long[]) b); + } + if (a instanceof double[] && b instanceof double[]) { + double[] da = (double[]) a; + double[] db = (double[]) b; + if (da.length != db.length) return false; + for (int i = 0; i < da.length; i++) { + if (!pigeonDoubleEquals(da[i], db[i])) { + return false; + } + } + return true; + } + if (a instanceof List && b instanceof List) { + List listA = (List) a; + List listB = (List) b; + if (listA.size() != listB.size()) { + return false; + } + for (int i = 0; i < listA.size(); i++) { + if (!pigeonDeepEquals(listA.get(i), listB.get(i))) { + return false; + } + } + return true; + } + if (a instanceof Map && b instanceof Map) { + Map mapA = (Map) a; + Map mapB = (Map) b; + if (mapA.size() != mapB.size()) { + return false; + } + for (Map.Entry entryA : mapA.entrySet()) { + Object keyA = entryA.getKey(); + Object valueA = entryA.getValue(); + boolean found = false; + for (Map.Entry entryB : mapB.entrySet()) { + Object keyB = entryB.getKey(); + if (pigeonDeepEquals(keyA, keyB)) { + Object valueB = entryB.getValue(); + if (pigeonDeepEquals(valueA, valueB)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; + } + if (a instanceof Double && b instanceof Double) { + return pigeonDoubleEquals((double) a, (double) b); + } + if (a instanceof Float && b instanceof Float) { + return pigeonFloatEquals((float) a, (float) b); + } + return a.equals(b); + } + + static int pigeonDeepHashCode(Object value) { + if (value == null) { + return 0; + } + if (value instanceof byte[]) { + return Arrays.hashCode((byte[]) value); + } + if (value instanceof int[]) { + return Arrays.hashCode((int[]) value); + } + if (value instanceof long[]) { + return Arrays.hashCode((long[]) value); + } + if (value instanceof double[]) { + double[] da = (double[]) value; + int result = 1; + for (double d : da) { + result = 31 * result + pigeonDoubleHashCode(d); + } + return result; + } + if (value instanceof List) { + int result = 1; + for (Object item : (List) value) { + result = 31 * result + pigeonDeepHashCode(item); + } + return result; + } + if (value instanceof Map) { + int result = 0; + for (Map.Entry entry : ((Map) value).entrySet()) { + result += (pigeonDeepHashCode(entry.getKey()) ^ pigeonDeepHashCode(entry.getValue())); + } + return result; + } + if (value instanceof Object[]) { + int result = 1; + for (Object item : (Object[]) value) { + result = 31 * result + pigeonDeepHashCode(item); + } + return result; + } + if (value instanceof Double) { + return pigeonDoubleHashCode((double) value); + } + if (value instanceof Float) { + return pigeonFloatHashCode((float) value); + } + return value.hashCode(); + } /** Error class for passing custom error details to Flutter via a thrown PlatformException. */ public static class FlutterError extends RuntimeException { @@ -120,12 +269,13 @@ public boolean equals(Object o) { return false; } UnusedClass that = (UnusedClass) o; - return Objects.equals(aField, that.aField); + return pigeonDeepEquals(aField, that.aField); } @Override public int hashCode() { - return Objects.hash(aField); + Object[] fields = new Object[] {getClass(), aField}; + return pigeonDeepHashCode(fields); } public static final class Builder { @@ -542,69 +692,71 @@ public boolean equals(Object o) { return false; } AllTypes that = (AllTypes) o; - return aBool.equals(that.aBool) - && anInt.equals(that.anInt) - && anInt64.equals(that.anInt64) - && aDouble.equals(that.aDouble) - && Arrays.equals(aByteArray, that.aByteArray) - && Arrays.equals(a4ByteArray, that.a4ByteArray) - && Arrays.equals(a8ByteArray, that.a8ByteArray) - && Arrays.equals(aFloatArray, that.aFloatArray) - && anEnum.equals(that.anEnum) - && anotherEnum.equals(that.anotherEnum) - && aString.equals(that.aString) - && anObject.equals(that.anObject) - && list.equals(that.list) - && stringList.equals(that.stringList) - && intList.equals(that.intList) - && doubleList.equals(that.doubleList) - && boolList.equals(that.boolList) - && enumList.equals(that.enumList) - && objectList.equals(that.objectList) - && listList.equals(that.listList) - && mapList.equals(that.mapList) - && map.equals(that.map) - && stringMap.equals(that.stringMap) - && intMap.equals(that.intMap) - && enumMap.equals(that.enumMap) - && objectMap.equals(that.objectMap) - && listMap.equals(that.listMap) - && mapMap.equals(that.mapMap); + return pigeonDeepEquals(aBool, that.aBool) + && pigeonDeepEquals(anInt, that.anInt) + && pigeonDeepEquals(anInt64, that.anInt64) + && pigeonDeepEquals(aDouble, that.aDouble) + && pigeonDeepEquals(aByteArray, that.aByteArray) + && pigeonDeepEquals(a4ByteArray, that.a4ByteArray) + && pigeonDeepEquals(a8ByteArray, that.a8ByteArray) + && pigeonDeepEquals(aFloatArray, that.aFloatArray) + && pigeonDeepEquals(anEnum, that.anEnum) + && pigeonDeepEquals(anotherEnum, that.anotherEnum) + && pigeonDeepEquals(aString, that.aString) + && pigeonDeepEquals(anObject, that.anObject) + && pigeonDeepEquals(list, that.list) + && pigeonDeepEquals(stringList, that.stringList) + && pigeonDeepEquals(intList, that.intList) + && pigeonDeepEquals(doubleList, that.doubleList) + && pigeonDeepEquals(boolList, that.boolList) + && pigeonDeepEquals(enumList, that.enumList) + && pigeonDeepEquals(objectList, that.objectList) + && pigeonDeepEquals(listList, that.listList) + && pigeonDeepEquals(mapList, that.mapList) + && pigeonDeepEquals(map, that.map) + && pigeonDeepEquals(stringMap, that.stringMap) + && pigeonDeepEquals(intMap, that.intMap) + && pigeonDeepEquals(enumMap, that.enumMap) + && pigeonDeepEquals(objectMap, that.objectMap) + && pigeonDeepEquals(listMap, that.listMap) + && pigeonDeepEquals(mapMap, that.mapMap); } @Override public int hashCode() { - int pigeonVar_result = - Objects.hash( - aBool, - anInt, - anInt64, - aDouble, - anEnum, - anotherEnum, - aString, - anObject, - list, - stringList, - intList, - doubleList, - boolList, - enumList, - objectList, - listList, - mapList, - map, - stringMap, - intMap, - enumMap, - objectMap, - listMap, - mapMap); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(aByteArray); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(a4ByteArray); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(a8ByteArray); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(aFloatArray); - return pigeonVar_result; + Object[] fields = + new Object[] { + getClass(), + aBool, + anInt, + anInt64, + aDouble, + aByteArray, + a4ByteArray, + a8ByteArray, + aFloatArray, + anEnum, + anotherEnum, + aString, + anObject, + list, + stringList, + intList, + doubleList, + boolList, + enumList, + objectList, + listList, + mapList, + map, + stringMap, + intMap, + enumMap, + objectMap, + listMap, + mapMap + }; + return pigeonDeepHashCode(fields); } public static final class Builder { @@ -1288,75 +1440,77 @@ public boolean equals(Object o) { return false; } AllNullableTypes that = (AllNullableTypes) o; - return Objects.equals(aNullableBool, that.aNullableBool) - && Objects.equals(aNullableInt, that.aNullableInt) - && Objects.equals(aNullableInt64, that.aNullableInt64) - && Objects.equals(aNullableDouble, that.aNullableDouble) - && Arrays.equals(aNullableByteArray, that.aNullableByteArray) - && Arrays.equals(aNullable4ByteArray, that.aNullable4ByteArray) - && Arrays.equals(aNullable8ByteArray, that.aNullable8ByteArray) - && Arrays.equals(aNullableFloatArray, that.aNullableFloatArray) - && Objects.equals(aNullableEnum, that.aNullableEnum) - && Objects.equals(anotherNullableEnum, that.anotherNullableEnum) - && Objects.equals(aNullableString, that.aNullableString) - && Objects.equals(aNullableObject, that.aNullableObject) - && Objects.equals(allNullableTypes, that.allNullableTypes) - && Objects.equals(list, that.list) - && Objects.equals(stringList, that.stringList) - && Objects.equals(intList, that.intList) - && Objects.equals(doubleList, that.doubleList) - && Objects.equals(boolList, that.boolList) - && Objects.equals(enumList, that.enumList) - && Objects.equals(objectList, that.objectList) - && Objects.equals(listList, that.listList) - && Objects.equals(mapList, that.mapList) - && Objects.equals(recursiveClassList, that.recursiveClassList) - && Objects.equals(map, that.map) - && Objects.equals(stringMap, that.stringMap) - && Objects.equals(intMap, that.intMap) - && Objects.equals(enumMap, that.enumMap) - && Objects.equals(objectMap, that.objectMap) - && Objects.equals(listMap, that.listMap) - && Objects.equals(mapMap, that.mapMap) - && Objects.equals(recursiveClassMap, that.recursiveClassMap); + return pigeonDeepEquals(aNullableBool, that.aNullableBool) + && pigeonDeepEquals(aNullableInt, that.aNullableInt) + && pigeonDeepEquals(aNullableInt64, that.aNullableInt64) + && pigeonDeepEquals(aNullableDouble, that.aNullableDouble) + && pigeonDeepEquals(aNullableByteArray, that.aNullableByteArray) + && pigeonDeepEquals(aNullable4ByteArray, that.aNullable4ByteArray) + && pigeonDeepEquals(aNullable8ByteArray, that.aNullable8ByteArray) + && pigeonDeepEquals(aNullableFloatArray, that.aNullableFloatArray) + && pigeonDeepEquals(aNullableEnum, that.aNullableEnum) + && pigeonDeepEquals(anotherNullableEnum, that.anotherNullableEnum) + && pigeonDeepEquals(aNullableString, that.aNullableString) + && pigeonDeepEquals(aNullableObject, that.aNullableObject) + && pigeonDeepEquals(allNullableTypes, that.allNullableTypes) + && pigeonDeepEquals(list, that.list) + && pigeonDeepEquals(stringList, that.stringList) + && pigeonDeepEquals(intList, that.intList) + && pigeonDeepEquals(doubleList, that.doubleList) + && pigeonDeepEquals(boolList, that.boolList) + && pigeonDeepEquals(enumList, that.enumList) + && pigeonDeepEquals(objectList, that.objectList) + && pigeonDeepEquals(listList, that.listList) + && pigeonDeepEquals(mapList, that.mapList) + && pigeonDeepEquals(recursiveClassList, that.recursiveClassList) + && pigeonDeepEquals(map, that.map) + && pigeonDeepEquals(stringMap, that.stringMap) + && pigeonDeepEquals(intMap, that.intMap) + && pigeonDeepEquals(enumMap, that.enumMap) + && pigeonDeepEquals(objectMap, that.objectMap) + && pigeonDeepEquals(listMap, that.listMap) + && pigeonDeepEquals(mapMap, that.mapMap) + && pigeonDeepEquals(recursiveClassMap, that.recursiveClassMap); } @Override public int hashCode() { - int pigeonVar_result = - Objects.hash( - aNullableBool, - aNullableInt, - aNullableInt64, - aNullableDouble, - aNullableEnum, - anotherNullableEnum, - aNullableString, - aNullableObject, - allNullableTypes, - list, - stringList, - intList, - doubleList, - boolList, - enumList, - objectList, - listList, - mapList, - recursiveClassList, - map, - stringMap, - intMap, - enumMap, - objectMap, - listMap, - mapMap, - recursiveClassMap); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(aNullableByteArray); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(aNullable4ByteArray); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(aNullable8ByteArray); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(aNullableFloatArray); - return pigeonVar_result; + Object[] fields = + new Object[] { + getClass(), + aNullableBool, + aNullableInt, + aNullableInt64, + aNullableDouble, + aNullableByteArray, + aNullable4ByteArray, + aNullable8ByteArray, + aNullableFloatArray, + aNullableEnum, + anotherNullableEnum, + aNullableString, + aNullableObject, + allNullableTypes, + list, + stringList, + intList, + doubleList, + boolList, + enumList, + objectList, + listList, + mapList, + recursiveClassList, + map, + stringMap, + intMap, + enumMap, + objectMap, + listMap, + mapMap, + recursiveClassMap + }; + return pigeonDeepHashCode(fields); } public static final class Builder { @@ -2048,69 +2202,71 @@ public boolean equals(Object o) { return false; } AllNullableTypesWithoutRecursion that = (AllNullableTypesWithoutRecursion) o; - return Objects.equals(aNullableBool, that.aNullableBool) - && Objects.equals(aNullableInt, that.aNullableInt) - && Objects.equals(aNullableInt64, that.aNullableInt64) - && Objects.equals(aNullableDouble, that.aNullableDouble) - && Arrays.equals(aNullableByteArray, that.aNullableByteArray) - && Arrays.equals(aNullable4ByteArray, that.aNullable4ByteArray) - && Arrays.equals(aNullable8ByteArray, that.aNullable8ByteArray) - && Arrays.equals(aNullableFloatArray, that.aNullableFloatArray) - && Objects.equals(aNullableEnum, that.aNullableEnum) - && Objects.equals(anotherNullableEnum, that.anotherNullableEnum) - && Objects.equals(aNullableString, that.aNullableString) - && Objects.equals(aNullableObject, that.aNullableObject) - && Objects.equals(list, that.list) - && Objects.equals(stringList, that.stringList) - && Objects.equals(intList, that.intList) - && Objects.equals(doubleList, that.doubleList) - && Objects.equals(boolList, that.boolList) - && Objects.equals(enumList, that.enumList) - && Objects.equals(objectList, that.objectList) - && Objects.equals(listList, that.listList) - && Objects.equals(mapList, that.mapList) - && Objects.equals(map, that.map) - && Objects.equals(stringMap, that.stringMap) - && Objects.equals(intMap, that.intMap) - && Objects.equals(enumMap, that.enumMap) - && Objects.equals(objectMap, that.objectMap) - && Objects.equals(listMap, that.listMap) - && Objects.equals(mapMap, that.mapMap); + return pigeonDeepEquals(aNullableBool, that.aNullableBool) + && pigeonDeepEquals(aNullableInt, that.aNullableInt) + && pigeonDeepEquals(aNullableInt64, that.aNullableInt64) + && pigeonDeepEquals(aNullableDouble, that.aNullableDouble) + && pigeonDeepEquals(aNullableByteArray, that.aNullableByteArray) + && pigeonDeepEquals(aNullable4ByteArray, that.aNullable4ByteArray) + && pigeonDeepEquals(aNullable8ByteArray, that.aNullable8ByteArray) + && pigeonDeepEquals(aNullableFloatArray, that.aNullableFloatArray) + && pigeonDeepEquals(aNullableEnum, that.aNullableEnum) + && pigeonDeepEquals(anotherNullableEnum, that.anotherNullableEnum) + && pigeonDeepEquals(aNullableString, that.aNullableString) + && pigeonDeepEquals(aNullableObject, that.aNullableObject) + && pigeonDeepEquals(list, that.list) + && pigeonDeepEquals(stringList, that.stringList) + && pigeonDeepEquals(intList, that.intList) + && pigeonDeepEquals(doubleList, that.doubleList) + && pigeonDeepEquals(boolList, that.boolList) + && pigeonDeepEquals(enumList, that.enumList) + && pigeonDeepEquals(objectList, that.objectList) + && pigeonDeepEquals(listList, that.listList) + && pigeonDeepEquals(mapList, that.mapList) + && pigeonDeepEquals(map, that.map) + && pigeonDeepEquals(stringMap, that.stringMap) + && pigeonDeepEquals(intMap, that.intMap) + && pigeonDeepEquals(enumMap, that.enumMap) + && pigeonDeepEquals(objectMap, that.objectMap) + && pigeonDeepEquals(listMap, that.listMap) + && pigeonDeepEquals(mapMap, that.mapMap); } @Override public int hashCode() { - int pigeonVar_result = - Objects.hash( - aNullableBool, - aNullableInt, - aNullableInt64, - aNullableDouble, - aNullableEnum, - anotherNullableEnum, - aNullableString, - aNullableObject, - list, - stringList, - intList, - doubleList, - boolList, - enumList, - objectList, - listList, - mapList, - map, - stringMap, - intMap, - enumMap, - objectMap, - listMap, - mapMap); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(aNullableByteArray); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(aNullable4ByteArray); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(aNullable8ByteArray); - pigeonVar_result = 31 * pigeonVar_result + Arrays.hashCode(aNullableFloatArray); - return pigeonVar_result; + Object[] fields = + new Object[] { + getClass(), + aNullableBool, + aNullableInt, + aNullableInt64, + aNullableDouble, + aNullableByteArray, + aNullable4ByteArray, + aNullable8ByteArray, + aNullableFloatArray, + aNullableEnum, + anotherNullableEnum, + aNullableString, + aNullableObject, + list, + stringList, + intList, + doubleList, + boolList, + enumList, + objectList, + listList, + mapList, + map, + stringMap, + intMap, + enumMap, + objectMap, + listMap, + mapMap + }; + return pigeonDeepHashCode(fields); } public static final class Builder { @@ -2573,25 +2729,30 @@ public boolean equals(Object o) { return false; } AllClassesWrapper that = (AllClassesWrapper) o; - return allNullableTypes.equals(that.allNullableTypes) - && Objects.equals(allNullableTypesWithoutRecursion, that.allNullableTypesWithoutRecursion) - && Objects.equals(allTypes, that.allTypes) - && classList.equals(that.classList) - && Objects.equals(nullableClassList, that.nullableClassList) - && classMap.equals(that.classMap) - && Objects.equals(nullableClassMap, that.nullableClassMap); + return pigeonDeepEquals(allNullableTypes, that.allNullableTypes) + && pigeonDeepEquals( + allNullableTypesWithoutRecursion, that.allNullableTypesWithoutRecursion) + && pigeonDeepEquals(allTypes, that.allTypes) + && pigeonDeepEquals(classList, that.classList) + && pigeonDeepEquals(nullableClassList, that.nullableClassList) + && pigeonDeepEquals(classMap, that.classMap) + && pigeonDeepEquals(nullableClassMap, that.nullableClassMap); } @Override public int hashCode() { - return Objects.hash( - allNullableTypes, - allNullableTypesWithoutRecursion, - allTypes, - classList, - nullableClassList, - classMap, - nullableClassMap); + Object[] fields = + new Object[] { + getClass(), + allNullableTypes, + allNullableTypesWithoutRecursion, + allTypes, + classList, + nullableClassList, + classMap, + nullableClassMap + }; + return pigeonDeepHashCode(fields); } public static final class Builder { @@ -2728,12 +2889,13 @@ public boolean equals(Object o) { return false; } TestMessage that = (TestMessage) o; - return Objects.equals(testList, that.testList); + return pigeonDeepEquals(testList, that.testList); } @Override public int hashCode() { - return Objects.hash(testList); + Object[] fields = new Object[] {getClass(), testList}; + return pigeonDeepHashCode(fields); } public static final class Builder { @@ -2959,6 +3121,15 @@ public interface HostIntegrationCoreApi { /** Returns passed in int. */ @NonNull Long echoRequiredInt(@NonNull Long anInt); + /** Returns the result of platform-side equality check. */ + @NonNull + Boolean areAllNullableTypesEqual(@NonNull AllNullableTypes a, @NonNull AllNullableTypes b); + /** Returns the platform-side hash code for the given object. */ + @NonNull + Long getAllNullableTypesHash(@NonNull AllNullableTypes value); + /** Returns the platform-side hash code for the given object. */ + @NonNull + Long getAllNullableTypesWithoutRecursionHash(@NonNull AllNullableTypesWithoutRecursion value); /** Returns the passed object, to test serialization and deserialization. */ @Nullable AllNullableTypes echoAllNullableTypes(@Nullable AllNullableTypes everything); @@ -4120,6 +4291,83 @@ static void setUp( channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.areAllNullableTypesEqual" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList<>(); + ArrayList args = (ArrayList) message; + AllNullableTypes aArg = (AllNullableTypes) args.get(0); + AllNullableTypes bArg = (AllNullableTypes) args.get(1); + try { + Boolean output = api.areAllNullableTypesEqual(aArg, bArg); + wrapped.add(0, output); + } catch (Throwable exception) { + wrapped = wrapError(exception); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.getAllNullableTypesHash" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList<>(); + ArrayList args = (ArrayList) message; + AllNullableTypes valueArg = (AllNullableTypes) args.get(0); + try { + Long output = api.getAllNullableTypesHash(valueArg); + wrapped.add(0, output); + } catch (Throwable exception) { + wrapped = wrapError(exception); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.getAllNullableTypesWithoutRecursionHash" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList<>(); + ArrayList args = (ArrayList) message; + AllNullableTypesWithoutRecursion valueArg = + (AllNullableTypesWithoutRecursion) args.get(0); + try { + Long output = api.getAllNullableTypesWithoutRecursionHash(valueArg); + wrapped.add(0, output); + } catch (Throwable exception) { + wrapped = wrapError(exception); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } { BasicMessageChannel channel = new BasicMessageChannel<>( diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/AllDatatypesTest.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/AllDatatypesTest.java index 1fb1e451dbbb..10531b7a2b03 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/AllDatatypesTest.java +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/AllDatatypesTest.java @@ -266,4 +266,47 @@ public void error(Throwable error) { }); assertTrue(didCall[0]); } + + @Test + public void equalityWithNaN() { + AllNullableTypes withNaN = + new AllNullableTypes.Builder().setANullableDouble(Double.NaN).build(); + AllNullableTypes withAnotherNaN = + new AllNullableTypes.Builder().setANullableDouble(Double.NaN).build(); + assertEquals(withNaN, withAnotherNaN); + assertEquals(withNaN.hashCode(), withAnotherNaN.hashCode()); + } + + @Test + public void crossTypeEquality() { + AllNullableTypes a = new AllNullableTypes.Builder().setANullableInt(1L).build(); + CoreTests.AllNullableTypesWithoutRecursion b = + new CoreTests.AllNullableTypesWithoutRecursion.Builder().setANullableInt(1L).build(); + assertNotEquals(a, b); + assertNotEquals(b, a); + } + + @Test + public void zeroEquality() { + AllNullableTypes a = new AllNullableTypes.Builder().setANullableDouble(0.0).build(); + AllNullableTypes b = new AllNullableTypes.Builder().setANullableDouble(-0.0).build(); + + assertEquals(a, b); + assertEquals(a.hashCode(), b.hashCode()); + } + + @Test + public void nestedByteArrayEquality() { + byte[] data = new byte[] {1, 2, 3}; + List list1 = new ArrayList<>(); + list1.add(data); + AllNullableTypes a = new AllNullableTypes.Builder().setList(list1).build(); + + List list2 = new ArrayList<>(); + list2.add(new byte[] {1, 2, 3}); + AllNullableTypes b = new AllNullableTypes.Builder().setList(list2).build(); + + assertEquals(a, b); + assertEquals(a.hashCode(), b.hashCode()); + } } diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/AlternateLanguageTestPlugin.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/AlternateLanguageTestPlugin.m index 1d494ba618ed..fdd0a0563ae5 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/AlternateLanguageTestPlugin.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/AlternateLanguageTestPlugin.m @@ -201,6 +201,23 @@ - (nullable NSNumber *)echoRequiredInt:(NSInteger)anInt return @(anInt); } +- (nullable NSNumber *)areAllNullableTypesEqualA:(FLTAllNullableTypes *)a + b:(FLTAllNullableTypes *)b + error:(FlutterError *_Nullable *_Nonnull)error { + return @([a isEqual:b]); +} + +- (nullable NSNumber *)getAllNullableTypesHashValue:(FLTAllNullableTypes *)value + error:(FlutterError *_Nullable *_Nonnull)error { + return @([value hash]); +} + +- (nullable NSNumber *) + getAllNullableTypesWithoutRecursionHashValue:(FLTAllNullableTypesWithoutRecursion *)value + error:(FlutterError *_Nullable *_Nonnull)error { + return @([value hash]); +} + - (nullable NSString *)extractNestedNullableStringFrom:(FLTAllClassesWrapper *)wrapper error:(FlutterError *_Nullable *_Nonnull)error { return wrapper.allNullableTypes.aNullableString; diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/CoreTests.gen.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/CoreTests.gen.m index 38bd8f4a417f..e9f7e0ef2c52 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/CoreTests.gen.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/CoreTests.gen.m @@ -13,6 +13,96 @@ @import Flutter; #endif +static BOOL __attribute__((unused)) FLTPigeonDeepEquals(id _Nullable a, id _Nullable b) { + if (a == b) { + return YES; + } + if (a == nil || b == nil) { + return NO; + } + if ([a isKindOfClass:[NSNumber class]] && [b isKindOfClass:[NSNumber class]]) { + NSNumber *na = (NSNumber *)a; + NSNumber *nb = (NSNumber *)b; + // Normalize -0.0 to 0.0 and handle NaN equality. + return na.doubleValue == nb.doubleValue || (isnan(na.doubleValue) && isnan(nb.doubleValue)); + } + if ([a isKindOfClass:[NSArray class]] && [b isKindOfClass:[NSArray class]]) { + NSArray *arrayA = (NSArray *)a; + NSArray *arrayB = (NSArray *)b; + if (arrayA.count != arrayB.count) { + return NO; + } + for (NSUInteger i = 0; i < arrayA.count; i++) { + if (!FLTPigeonDeepEquals(arrayA[i], arrayB[i])) { + return NO; + } + } + return YES; + } + if ([a isKindOfClass:[NSDictionary class]] && [b isKindOfClass:[NSDictionary class]]) { + NSDictionary *dictA = (NSDictionary *)a; + NSDictionary *dictB = (NSDictionary *)b; + if (dictA.count != dictB.count) { + return NO; + } + for (id keyA in dictA) { + id valueA = dictA[keyA]; + BOOL found = NO; + for (id keyB in dictB) { + if (FLTPigeonDeepEquals(keyA, keyB)) { + id valueB = dictB[keyB]; + if (FLTPigeonDeepEquals(valueA, valueB)) { + found = YES; + break; + } else { + return NO; + } + } + } + if (!found) { + return NO; + } + } + return YES; + } + return [a isEqual:b]; +} + +static NSUInteger __attribute__((unused)) FLTPigeonDeepHash(id _Nullable value) { + if (value == nil) { + return 0; + } + if ([value isKindOfClass:[NSNumber class]]) { + NSNumber *n = (NSNumber *)value; + double d = n.doubleValue; + if (isnan(d)) { + // Normalize NaN to a consistent hash. + return (NSUInteger)0x7FF8000000000000; + } + if (d == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + d = 0.0; + } + return @(d).hash; + } + if ([value isKindOfClass:[NSArray class]]) { + NSUInteger result = 1; + for (id item in (NSArray *)value) { + result = result * 31 + FLTPigeonDeepHash(item); + } + return result; + } + if ([value isKindOfClass:[NSDictionary class]]) { + NSUInteger result = 0; + NSDictionary *dict = (NSDictionary *)value; + for (id key in dict) { + result += (FLTPigeonDeepHash(key) ^ FLTPigeonDeepHash(dict[key])); + } + return result; + } + return [value hash]; +} + static NSArray *wrapResult(id result, FlutterError *error) { if (error) { return @[ @@ -111,6 +201,22 @@ + (nullable FLTUnusedClass *)nullableFromList:(NSArray *)list { self.aField ?: [NSNull null], ]; } +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[self class]]) { + return NO; + } + FLTUnusedClass *other = (FLTUnusedClass *)object; + return FLTPigeonDeepEquals(self.aField, other.aField); +} + +- (NSUInteger)hash { + NSUInteger result = [self class].hash; + result = result * 31 + FLTPigeonDeepHash(self.aField); + return result; +} @end @implementation FLTAllTypes @@ -242,6 +348,74 @@ + (nullable FLTAllTypes *)nullableFromList:(NSArray *)list { self.mapMap ?: [NSNull null], ]; } +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[self class]]) { + return NO; + } + FLTAllTypes *other = (FLTAllTypes *)object; + return self.aBool == other.aBool && self.anInt == other.anInt && self.anInt64 == other.anInt64 && + (self.aDouble == other.aDouble || (isnan(self.aDouble) && isnan(other.aDouble))) && + FLTPigeonDeepEquals(self.aByteArray, other.aByteArray) && + FLTPigeonDeepEquals(self.a4ByteArray, other.a4ByteArray) && + FLTPigeonDeepEquals(self.a8ByteArray, other.a8ByteArray) && + FLTPigeonDeepEquals(self.aFloatArray, other.aFloatArray) && self.anEnum == other.anEnum && + self.anotherEnum == other.anotherEnum && + FLTPigeonDeepEquals(self.aString, other.aString) && + FLTPigeonDeepEquals(self.anObject, other.anObject) && + FLTPigeonDeepEquals(self.list, other.list) && + FLTPigeonDeepEquals(self.stringList, other.stringList) && + FLTPigeonDeepEquals(self.intList, other.intList) && + FLTPigeonDeepEquals(self.doubleList, other.doubleList) && + FLTPigeonDeepEquals(self.boolList, other.boolList) && + FLTPigeonDeepEquals(self.enumList, other.enumList) && + FLTPigeonDeepEquals(self.objectList, other.objectList) && + FLTPigeonDeepEquals(self.listList, other.listList) && + FLTPigeonDeepEquals(self.mapList, other.mapList) && + FLTPigeonDeepEquals(self.map, other.map) && + FLTPigeonDeepEquals(self.stringMap, other.stringMap) && + FLTPigeonDeepEquals(self.intMap, other.intMap) && + FLTPigeonDeepEquals(self.enumMap, other.enumMap) && + FLTPigeonDeepEquals(self.objectMap, other.objectMap) && + FLTPigeonDeepEquals(self.listMap, other.listMap) && + FLTPigeonDeepEquals(self.mapMap, other.mapMap); +} + +- (NSUInteger)hash { + NSUInteger result = [self class].hash; + result = result * 31 + @(self.aBool).hash; + result = result * 31 + @(self.anInt).hash; + result = result * 31 + @(self.anInt64).hash; + result = + result * 31 + (isnan(self.aDouble) ? (NSUInteger)0x7FF8000000000000 : @(self.aDouble).hash); + result = result * 31 + FLTPigeonDeepHash(self.aByteArray); + result = result * 31 + FLTPigeonDeepHash(self.a4ByteArray); + result = result * 31 + FLTPigeonDeepHash(self.a8ByteArray); + result = result * 31 + FLTPigeonDeepHash(self.aFloatArray); + result = result * 31 + @(self.anEnum).hash; + result = result * 31 + @(self.anotherEnum).hash; + result = result * 31 + FLTPigeonDeepHash(self.aString); + result = result * 31 + FLTPigeonDeepHash(self.anObject); + result = result * 31 + FLTPigeonDeepHash(self.list); + result = result * 31 + FLTPigeonDeepHash(self.stringList); + result = result * 31 + FLTPigeonDeepHash(self.intList); + result = result * 31 + FLTPigeonDeepHash(self.doubleList); + result = result * 31 + FLTPigeonDeepHash(self.boolList); + result = result * 31 + FLTPigeonDeepHash(self.enumList); + result = result * 31 + FLTPigeonDeepHash(self.objectList); + result = result * 31 + FLTPigeonDeepHash(self.listList); + result = result * 31 + FLTPigeonDeepHash(self.mapList); + result = result * 31 + FLTPigeonDeepHash(self.map); + result = result * 31 + FLTPigeonDeepHash(self.stringMap); + result = result * 31 + FLTPigeonDeepHash(self.intMap); + result = result * 31 + FLTPigeonDeepHash(self.enumMap); + result = result * 31 + FLTPigeonDeepHash(self.objectMap); + result = result * 31 + FLTPigeonDeepHash(self.listMap); + result = result * 31 + FLTPigeonDeepHash(self.mapMap); + return result; +} @end @implementation FLTAllNullableTypes @@ -385,6 +559,82 @@ + (nullable FLTAllNullableTypes *)nullableFromList:(NSArray *)list { self.recursiveClassMap ?: [NSNull null], ]; } +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[self class]]) { + return NO; + } + FLTAllNullableTypes *other = (FLTAllNullableTypes *)object; + return FLTPigeonDeepEquals(self.aNullableBool, other.aNullableBool) && + FLTPigeonDeepEquals(self.aNullableInt, other.aNullableInt) && + FLTPigeonDeepEquals(self.aNullableInt64, other.aNullableInt64) && + FLTPigeonDeepEquals(self.aNullableDouble, other.aNullableDouble) && + FLTPigeonDeepEquals(self.aNullableByteArray, other.aNullableByteArray) && + FLTPigeonDeepEquals(self.aNullable4ByteArray, other.aNullable4ByteArray) && + FLTPigeonDeepEquals(self.aNullable8ByteArray, other.aNullable8ByteArray) && + FLTPigeonDeepEquals(self.aNullableFloatArray, other.aNullableFloatArray) && + FLTPigeonDeepEquals(self.aNullableEnum, other.aNullableEnum) && + FLTPigeonDeepEquals(self.anotherNullableEnum, other.anotherNullableEnum) && + FLTPigeonDeepEquals(self.aNullableString, other.aNullableString) && + FLTPigeonDeepEquals(self.aNullableObject, other.aNullableObject) && + FLTPigeonDeepEquals(self.allNullableTypes, other.allNullableTypes) && + FLTPigeonDeepEquals(self.list, other.list) && + FLTPigeonDeepEquals(self.stringList, other.stringList) && + FLTPigeonDeepEquals(self.intList, other.intList) && + FLTPigeonDeepEquals(self.doubleList, other.doubleList) && + FLTPigeonDeepEquals(self.boolList, other.boolList) && + FLTPigeonDeepEquals(self.enumList, other.enumList) && + FLTPigeonDeepEquals(self.objectList, other.objectList) && + FLTPigeonDeepEquals(self.listList, other.listList) && + FLTPigeonDeepEquals(self.mapList, other.mapList) && + FLTPigeonDeepEquals(self.recursiveClassList, other.recursiveClassList) && + FLTPigeonDeepEquals(self.map, other.map) && + FLTPigeonDeepEquals(self.stringMap, other.stringMap) && + FLTPigeonDeepEquals(self.intMap, other.intMap) && + FLTPigeonDeepEquals(self.enumMap, other.enumMap) && + FLTPigeonDeepEquals(self.objectMap, other.objectMap) && + FLTPigeonDeepEquals(self.listMap, other.listMap) && + FLTPigeonDeepEquals(self.mapMap, other.mapMap) && + FLTPigeonDeepEquals(self.recursiveClassMap, other.recursiveClassMap); +} + +- (NSUInteger)hash { + NSUInteger result = [self class].hash; + result = result * 31 + FLTPigeonDeepHash(self.aNullableBool); + result = result * 31 + FLTPigeonDeepHash(self.aNullableInt); + result = result * 31 + FLTPigeonDeepHash(self.aNullableInt64); + result = result * 31 + FLTPigeonDeepHash(self.aNullableDouble); + result = result * 31 + FLTPigeonDeepHash(self.aNullableByteArray); + result = result * 31 + FLTPigeonDeepHash(self.aNullable4ByteArray); + result = result * 31 + FLTPigeonDeepHash(self.aNullable8ByteArray); + result = result * 31 + FLTPigeonDeepHash(self.aNullableFloatArray); + result = result * 31 + FLTPigeonDeepHash(self.aNullableEnum); + result = result * 31 + FLTPigeonDeepHash(self.anotherNullableEnum); + result = result * 31 + FLTPigeonDeepHash(self.aNullableString); + result = result * 31 + FLTPigeonDeepHash(self.aNullableObject); + result = result * 31 + FLTPigeonDeepHash(self.allNullableTypes); + result = result * 31 + FLTPigeonDeepHash(self.list); + result = result * 31 + FLTPigeonDeepHash(self.stringList); + result = result * 31 + FLTPigeonDeepHash(self.intList); + result = result * 31 + FLTPigeonDeepHash(self.doubleList); + result = result * 31 + FLTPigeonDeepHash(self.boolList); + result = result * 31 + FLTPigeonDeepHash(self.enumList); + result = result * 31 + FLTPigeonDeepHash(self.objectList); + result = result * 31 + FLTPigeonDeepHash(self.listList); + result = result * 31 + FLTPigeonDeepHash(self.mapList); + result = result * 31 + FLTPigeonDeepHash(self.recursiveClassList); + result = result * 31 + FLTPigeonDeepHash(self.map); + result = result * 31 + FLTPigeonDeepHash(self.stringMap); + result = result * 31 + FLTPigeonDeepHash(self.intMap); + result = result * 31 + FLTPigeonDeepHash(self.enumMap); + result = result * 31 + FLTPigeonDeepHash(self.objectMap); + result = result * 31 + FLTPigeonDeepHash(self.listMap); + result = result * 31 + FLTPigeonDeepHash(self.mapMap); + result = result * 31 + FLTPigeonDeepHash(self.recursiveClassMap); + return result; +} @end @implementation FLTAllNullableTypesWithoutRecursion @@ -517,6 +767,76 @@ + (nullable FLTAllNullableTypesWithoutRecursion *)nullableFromList:(NSArray self.mapMap ?: [NSNull null], ]; } +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[self class]]) { + return NO; + } + FLTAllNullableTypesWithoutRecursion *other = (FLTAllNullableTypesWithoutRecursion *)object; + return FLTPigeonDeepEquals(self.aNullableBool, other.aNullableBool) && + FLTPigeonDeepEquals(self.aNullableInt, other.aNullableInt) && + FLTPigeonDeepEquals(self.aNullableInt64, other.aNullableInt64) && + FLTPigeonDeepEquals(self.aNullableDouble, other.aNullableDouble) && + FLTPigeonDeepEquals(self.aNullableByteArray, other.aNullableByteArray) && + FLTPigeonDeepEquals(self.aNullable4ByteArray, other.aNullable4ByteArray) && + FLTPigeonDeepEquals(self.aNullable8ByteArray, other.aNullable8ByteArray) && + FLTPigeonDeepEquals(self.aNullableFloatArray, other.aNullableFloatArray) && + FLTPigeonDeepEquals(self.aNullableEnum, other.aNullableEnum) && + FLTPigeonDeepEquals(self.anotherNullableEnum, other.anotherNullableEnum) && + FLTPigeonDeepEquals(self.aNullableString, other.aNullableString) && + FLTPigeonDeepEquals(self.aNullableObject, other.aNullableObject) && + FLTPigeonDeepEquals(self.list, other.list) && + FLTPigeonDeepEquals(self.stringList, other.stringList) && + FLTPigeonDeepEquals(self.intList, other.intList) && + FLTPigeonDeepEquals(self.doubleList, other.doubleList) && + FLTPigeonDeepEquals(self.boolList, other.boolList) && + FLTPigeonDeepEquals(self.enumList, other.enumList) && + FLTPigeonDeepEquals(self.objectList, other.objectList) && + FLTPigeonDeepEquals(self.listList, other.listList) && + FLTPigeonDeepEquals(self.mapList, other.mapList) && + FLTPigeonDeepEquals(self.map, other.map) && + FLTPigeonDeepEquals(self.stringMap, other.stringMap) && + FLTPigeonDeepEquals(self.intMap, other.intMap) && + FLTPigeonDeepEquals(self.enumMap, other.enumMap) && + FLTPigeonDeepEquals(self.objectMap, other.objectMap) && + FLTPigeonDeepEquals(self.listMap, other.listMap) && + FLTPigeonDeepEquals(self.mapMap, other.mapMap); +} + +- (NSUInteger)hash { + NSUInteger result = [self class].hash; + result = result * 31 + FLTPigeonDeepHash(self.aNullableBool); + result = result * 31 + FLTPigeonDeepHash(self.aNullableInt); + result = result * 31 + FLTPigeonDeepHash(self.aNullableInt64); + result = result * 31 + FLTPigeonDeepHash(self.aNullableDouble); + result = result * 31 + FLTPigeonDeepHash(self.aNullableByteArray); + result = result * 31 + FLTPigeonDeepHash(self.aNullable4ByteArray); + result = result * 31 + FLTPigeonDeepHash(self.aNullable8ByteArray); + result = result * 31 + FLTPigeonDeepHash(self.aNullableFloatArray); + result = result * 31 + FLTPigeonDeepHash(self.aNullableEnum); + result = result * 31 + FLTPigeonDeepHash(self.anotherNullableEnum); + result = result * 31 + FLTPigeonDeepHash(self.aNullableString); + result = result * 31 + FLTPigeonDeepHash(self.aNullableObject); + result = result * 31 + FLTPigeonDeepHash(self.list); + result = result * 31 + FLTPigeonDeepHash(self.stringList); + result = result * 31 + FLTPigeonDeepHash(self.intList); + result = result * 31 + FLTPigeonDeepHash(self.doubleList); + result = result * 31 + FLTPigeonDeepHash(self.boolList); + result = result * 31 + FLTPigeonDeepHash(self.enumList); + result = result * 31 + FLTPigeonDeepHash(self.objectList); + result = result * 31 + FLTPigeonDeepHash(self.listList); + result = result * 31 + FLTPigeonDeepHash(self.mapList); + result = result * 31 + FLTPigeonDeepHash(self.map); + result = result * 31 + FLTPigeonDeepHash(self.stringMap); + result = result * 31 + FLTPigeonDeepHash(self.intMap); + result = result * 31 + FLTPigeonDeepHash(self.enumMap); + result = result * 31 + FLTPigeonDeepHash(self.objectMap); + result = result * 31 + FLTPigeonDeepHash(self.listMap); + result = result * 31 + FLTPigeonDeepHash(self.mapMap); + return result; +} @end @implementation FLTAllClassesWrapper @@ -567,6 +887,35 @@ + (nullable FLTAllClassesWrapper *)nullableFromList:(NSArray *)list { self.nullableClassMap ?: [NSNull null], ]; } +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[self class]]) { + return NO; + } + FLTAllClassesWrapper *other = (FLTAllClassesWrapper *)object; + return FLTPigeonDeepEquals(self.allNullableTypes, other.allNullableTypes) && + FLTPigeonDeepEquals(self.allNullableTypesWithoutRecursion, + other.allNullableTypesWithoutRecursion) && + FLTPigeonDeepEquals(self.allTypes, other.allTypes) && + FLTPigeonDeepEquals(self.classList, other.classList) && + FLTPigeonDeepEquals(self.nullableClassList, other.nullableClassList) && + FLTPigeonDeepEquals(self.classMap, other.classMap) && + FLTPigeonDeepEquals(self.nullableClassMap, other.nullableClassMap); +} + +- (NSUInteger)hash { + NSUInteger result = [self class].hash; + result = result * 31 + FLTPigeonDeepHash(self.allNullableTypes); + result = result * 31 + FLTPigeonDeepHash(self.allNullableTypesWithoutRecursion); + result = result * 31 + FLTPigeonDeepHash(self.allTypes); + result = result * 31 + FLTPigeonDeepHash(self.classList); + result = result * 31 + FLTPigeonDeepHash(self.nullableClassList); + result = result * 31 + FLTPigeonDeepHash(self.classMap); + result = result * 31 + FLTPigeonDeepHash(self.nullableClassMap); + return result; +} @end @implementation FLTTestMessage @@ -588,6 +937,22 @@ + (nullable FLTTestMessage *)nullableFromList:(NSArray *)list { self.testList ?: [NSNull null], ]; } +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[self class]]) { + return NO; + } + FLTTestMessage *other = (FLTTestMessage *)object; + return FLTPigeonDeepEquals(self.testList, other.testList); +} + +- (NSUInteger)hash { + NSUInteger result = [self class].hash; + result = result * 31 + FLTPigeonDeepHash(self.testList); + return result; +} @end @interface FLTCoreTestsPigeonCodecReader : FlutterStandardReader @@ -1474,6 +1839,88 @@ void SetUpFLTHostIntegrationCoreApiWithSuffix(id binaryM [channel setMessageHandler:nil]; } } + /// Returns the result of platform-side equality check. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.pigeon_integration_tests." + @"HostIntegrationCoreApi.areAllNullableTypesEqual", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FLTGetCoreTestsCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(areAllNullableTypesEqualA:b:error:)], + @"FLTHostIntegrationCoreApi api (%@) doesn't respond to " + @"@selector(areAllNullableTypesEqualA:b:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FLTAllNullableTypes *arg_a = GetNullableObjectAtIndex(args, 0); + FLTAllNullableTypes *arg_b = GetNullableObjectAtIndex(args, 1); + FlutterError *error; + NSNumber *output = [api areAllNullableTypesEqualA:arg_a b:arg_b error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Returns the platform-side hash code for the given object. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.pigeon_integration_tests." + @"HostIntegrationCoreApi.getAllNullableTypesHash", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FLTGetCoreTestsCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(getAllNullableTypesHashValue:error:)], + @"FLTHostIntegrationCoreApi api (%@) doesn't respond to " + @"@selector(getAllNullableTypesHashValue:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FLTAllNullableTypes *arg_value = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + NSNumber *output = [api getAllNullableTypesHashValue:arg_value error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Returns the platform-side hash code for the given object. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.pigeon_integration_tests." + @"HostIntegrationCoreApi.getAllNullableTypesWithoutRecursionHash", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FLTGetCoreTestsCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(getAllNullableTypesWithoutRecursionHashValue: + error:)], + @"FLTHostIntegrationCoreApi api (%@) doesn't respond to " + @"@selector(getAllNullableTypesWithoutRecursionHashValue:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FLTAllNullableTypesWithoutRecursion *arg_value = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + NSNumber *output = [api getAllNullableTypesWithoutRecursionHashValue:arg_value + error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } /// Returns the passed object, to test serialization and deserialization. { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/include/alternate_language_test_plugin/CoreTests.gen.h b/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/include/alternate_language_test_plugin/CoreTests.gen.h index 83f632d43b3b..2b620a11104a 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/include/alternate_language_test_plugin/CoreTests.gen.h +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/darwin/alternate_language_test_plugin/Sources/alternate_language_test_plugin/include/alternate_language_test_plugin/CoreTests.gen.h @@ -438,6 +438,23 @@ NSObject *FLTGetCoreTestsCodec(void); /// @return `nil` only when `error != nil`. - (nullable NSNumber *)echoRequiredInt:(NSInteger)anInt error:(FlutterError *_Nullable *_Nonnull)error; +/// Returns the result of platform-side equality check. +/// +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)areAllNullableTypesEqualA:(FLTAllNullableTypes *)a + b:(FLTAllNullableTypes *)b + error:(FlutterError *_Nullable *_Nonnull)error; +/// Returns the platform-side hash code for the given object. +/// +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)getAllNullableTypesHashValue:(FLTAllNullableTypes *)value + error:(FlutterError *_Nullable *_Nonnull)error; +/// Returns the platform-side hash code for the given object. +/// +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *) + getAllNullableTypesWithoutRecursionHashValue:(FLTAllNullableTypesWithoutRecursion *)value + error:(FlutterError *_Nullable *_Nonnull)error; /// Returns the passed object, to test serialization and deserialization. - (nullable FLTAllNullableTypes *)echoAllNullableTypes:(nullable FLTAllNullableTypes *)everything error:(FlutterError *_Nullable *_Nonnull)error; diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/AllDatatypesTest.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/AllDatatypesTest.m index ddef818e0c5a..a49cccc0cee9 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/AllDatatypesTest.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/AllDatatypesTest.m @@ -114,8 +114,70 @@ - (void)testAllEquals { [self waitForExpectations:@[ expectation ] timeout:1.0]; } -- (void)unusedClassesExist { - XCTAssert([[FLTUnusedClass alloc] init] != nil); +- (void)testEquality { + FLTAllNullableTypes *everything1 = [[FLTAllNullableTypes alloc] init]; + everything1.aNullableBool = @NO; + everything1.aNullableInt = @(1); + everything1.aNullableString = @"123"; + + FLTAllNullableTypes *everything2 = [[FLTAllNullableTypes alloc] init]; + everything2.aNullableBool = @NO; + everything2.aNullableInt = @(1); + everything2.aNullableString = @"123"; + + FLTAllNullableTypes *everything3 = [[FLTAllNullableTypes alloc] init]; + everything3.aNullableBool = @YES; + + XCTAssertEqualObjects(everything1, everything2); + XCTAssertNotEqualObjects(everything1, everything3); + XCTAssertEqual(everything1.hash, everything2.hash); +} + +- (void)testNaNEquality { + FLTAllNullableTypes *everything1 = [[FLTAllNullableTypes alloc] init]; + everything1.aNullableDouble = @(NAN); + + FLTAllNullableTypes *everything2 = [[FLTAllNullableTypes alloc] init]; + everything2.aNullableDouble = @(NAN); + + XCTAssertEqualObjects(everything1, everything2); + XCTAssertEqual(everything1.hash, everything2.hash); +} + +- (void)testCrossTypeEquality { + FLTAllNullableTypes *a = [[FLTAllNullableTypes alloc] init]; + a.aNullableInt = @(1); + + FLTAllNullableTypesWithoutRecursion *b = [[FLTAllNullableTypesWithoutRecursion alloc] init]; + b.aNullableInt = @(1); + + XCTAssertNotEqualObjects(a, b); + XCTAssertNotEqualObjects(b, a); +} + +- (void)testZeroEquality { + FLTAllNullableTypes *a = [[FLTAllNullableTypes alloc] init]; + a.aNullableDouble = @(0.0); + + FLTAllNullableTypes *b = [[FLTAllNullableTypes alloc] init]; + b.aNullableDouble = @(-0.0); + + XCTAssertEqualObjects(a, b); + XCTAssertEqual(a.hash, b.hash); +} + +- (void)testNestedNaNEquality { + FLTAllNullableTypes *a = [[FLTAllNullableTypes alloc] init]; + a.aNullableDouble = @(nan("")); + a.doubleList = @[ @(nan("")) ]; + + FLTAllNullableTypes *b = [[FLTAllNullableTypes alloc] init]; + b.aNullableDouble = @(nan("")); + b.doubleList = @[ @(nan("")) ]; + + // If this fails, Objective-C needs a deepEquals helper too. + XCTAssertEqualObjects(a, b); + XCTAssertEqual(a.hash, b.hash); } @end diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/NonNullFieldsTest.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/NonNullFieldsTest.m index 573bb994f91c..cd0369996a01 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/NonNullFieldsTest.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/NonNullFieldsTest.m @@ -22,4 +22,14 @@ - (void)testMake { XCTAssertEqualObjects(@"hello", request.query); } +- (void)testEquality { + NonNullFieldSearchRequest *request1 = [NonNullFieldSearchRequest makeWithQuery:@"hello"]; + NonNullFieldSearchRequest *request2 = [NonNullFieldSearchRequest makeWithQuery:@"hello"]; + NonNullFieldSearchRequest *request3 = [NonNullFieldSearchRequest makeWithQuery:@"world"]; + + XCTAssertEqualObjects(request1, request2); + XCTAssertNotEqualObjects(request1, request3); + XCTAssertEqual(request1.hash, request2.hash); +} + @end diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart index aedbf2da1644..d115a73ed104 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart @@ -1024,6 +1024,126 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) { final String? receivedNullString = await api.echoNamedNullableString(); expect(receivedNullString, null); }); + + testWidgets('Signed zero equality', (WidgetTester _) async { + final api = HostIntegrationCoreApi(); + + final a = AllNullableTypes(aNullableDouble: 0.0); + final b = AllNullableTypes(aNullableDouble: -0.0); + + expect(await api.areAllNullableTypesEqual(a, b), isTrue); + }); + + testWidgets('Signed zero hashing', (WidgetTester _) async { + final api = HostIntegrationCoreApi(); + + final a = AllNullableTypes(aNullableDouble: 0.0); + final b = AllNullableTypes(aNullableDouble: -0.0); + + final int hashA = await api.getAllNullableTypesHash(a); + final int hashB = await api.getAllNullableTypesHash(b); + expect( + hashA, + hashB, + reason: 'Hash codes for 0.0 and -0.0 should be equal', + ); + }); + + testWidgets('NaN equality', (WidgetTester _) async { + final api = HostIntegrationCoreApi(); + + final a = AllNullableTypes(aNullableDouble: double.nan); + final b = AllNullableTypes(aNullableDouble: double.nan); + + expect(await api.areAllNullableTypesEqual(a, b), isTrue); + }); + + testWidgets('NaN hashing', (WidgetTester _) async { + final api = HostIntegrationCoreApi(); + + final a = AllNullableTypes(aNullableDouble: double.nan); + final b = AllNullableTypes(aNullableDouble: double.nan); + + final int hashA = await api.getAllNullableTypesHash(a); + final int hashB = await api.getAllNullableTypesHash(b); + expect(hashA, hashB, reason: 'Hash codes for two NaNs should be equal'); + }); + + testWidgets('Collection equality with signed zero and NaN', ( + WidgetTester _, + ) async { + final api = HostIntegrationCoreApi(); + + final a = AllNullableTypes( + doubleList: [0.0, double.nan], + stringMap: {'k': 'v', 'n': null}, + ); + final b = AllNullableTypes( + doubleList: [-0.0, double.nan], + stringMap: {'n': null, 'k': 'v'}, + ); + + expect(await api.areAllNullableTypesEqual(a, b), isTrue); + }); + + testWidgets('Collection hashing with signed zero and NaN', ( + WidgetTester _, + ) async { + final api = HostIntegrationCoreApi(); + + final a = AllNullableTypes( + doubleList: [0.0, double.nan], + stringMap: {'k': 'v', 'n': null}, + ); + final b = AllNullableTypes( + doubleList: [-0.0, double.nan], + stringMap: {'n': null, 'k': 'v'}, + ); + + expect( + await api.getAllNullableTypesHash(a), + await api.getAllNullableTypesHash(b), + ); + }); + + testWidgets('Map equality with null values and different keys', ( + WidgetTester _, + ) async { + final api = HostIntegrationCoreApi(); + + final a = AllNullableTypes(intMap: {1: null}); + final b = AllNullableTypes(intMap: {2: null}); + + expect(await api.areAllNullableTypesEqual(a, b), isFalse); + }); + + testWidgets('Deeply nested equality', (WidgetTester _) async { + final api = HostIntegrationCoreApi(); + + final a = AllNullableTypes( + allNullableTypes: AllNullableTypes(aNullableDouble: 0.0), + ); + final b = AllNullableTypes( + allNullableTypes: AllNullableTypes(aNullableDouble: -0.0), + ); + + expect(await api.areAllNullableTypesEqual(a, b), isTrue); + }); + + testWidgets('Hashing inequality across types with same values', ( + WidgetTester _, + ) async { + final api = HostIntegrationCoreApi(); + final a = AllNullableTypes(aNullableInt: 42); + final b = AllNullableTypesWithoutRecursion(aNullableInt: 42); + + expect(a.hashCode, isNot(b.hashCode)); + + expect( + await api.getAllNullableTypesHash(a), + isNot(await api.getAllNullableTypesWithoutRecursionHash(b)), + ); + }); }); group('Host async API tests', () { diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart index b325d041e44a..b6e4374fa70d 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart @@ -52,6 +52,14 @@ List wrapResponse({ } bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -59,16 +67,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += _deepHash(entry.key) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + enum AnEnum { one, two, three, fortyTwo, fourHundredTwentyTwo } enum AnotherEnum { justInCase } @@ -100,12 +144,12 @@ class UnusedClass { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(aField, other.aField); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// A class containing all supported types. @@ -279,12 +323,39 @@ class AllTypes { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(aBool, other.aBool) && + _deepEquals(anInt, other.anInt) && + _deepEquals(anInt64, other.anInt64) && + _deepEquals(aDouble, other.aDouble) && + _deepEquals(aByteArray, other.aByteArray) && + _deepEquals(a4ByteArray, other.a4ByteArray) && + _deepEquals(a8ByteArray, other.a8ByteArray) && + _deepEquals(aFloatArray, other.aFloatArray) && + _deepEquals(anEnum, other.anEnum) && + _deepEquals(anotherEnum, other.anotherEnum) && + _deepEquals(aString, other.aString) && + _deepEquals(anObject, other.anObject) && + _deepEquals(list, other.list) && + _deepEquals(stringList, other.stringList) && + _deepEquals(intList, other.intList) && + _deepEquals(doubleList, other.doubleList) && + _deepEquals(boolList, other.boolList) && + _deepEquals(enumList, other.enumList) && + _deepEquals(objectList, other.objectList) && + _deepEquals(listList, other.listList) && + _deepEquals(mapList, other.mapList) && + _deepEquals(map, other.map) && + _deepEquals(stringMap, other.stringMap) && + _deepEquals(intMap, other.intMap) && + _deepEquals(enumMap, other.enumMap) && + _deepEquals(objectMap, other.objectMap) && + _deepEquals(listMap, other.listMap) && + _deepEquals(mapMap, other.mapMap); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// A class containing all supported nullable types. @@ -477,12 +548,42 @@ class AllNullableTypes { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(aNullableBool, other.aNullableBool) && + _deepEquals(aNullableInt, other.aNullableInt) && + _deepEquals(aNullableInt64, other.aNullableInt64) && + _deepEquals(aNullableDouble, other.aNullableDouble) && + _deepEquals(aNullableByteArray, other.aNullableByteArray) && + _deepEquals(aNullable4ByteArray, other.aNullable4ByteArray) && + _deepEquals(aNullable8ByteArray, other.aNullable8ByteArray) && + _deepEquals(aNullableFloatArray, other.aNullableFloatArray) && + _deepEquals(aNullableEnum, other.aNullableEnum) && + _deepEquals(anotherNullableEnum, other.anotherNullableEnum) && + _deepEquals(aNullableString, other.aNullableString) && + _deepEquals(aNullableObject, other.aNullableObject) && + _deepEquals(allNullableTypes, other.allNullableTypes) && + _deepEquals(list, other.list) && + _deepEquals(stringList, other.stringList) && + _deepEquals(intList, other.intList) && + _deepEquals(doubleList, other.doubleList) && + _deepEquals(boolList, other.boolList) && + _deepEquals(enumList, other.enumList) && + _deepEquals(objectList, other.objectList) && + _deepEquals(listList, other.listList) && + _deepEquals(mapList, other.mapList) && + _deepEquals(recursiveClassList, other.recursiveClassList) && + _deepEquals(map, other.map) && + _deepEquals(stringMap, other.stringMap) && + _deepEquals(intMap, other.intMap) && + _deepEquals(enumMap, other.enumMap) && + _deepEquals(objectMap, other.objectMap) && + _deepEquals(listMap, other.listMap) && + _deepEquals(mapMap, other.mapMap) && + _deepEquals(recursiveClassMap, other.recursiveClassMap); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// The primary purpose for this class is to ensure coverage of Swift structs @@ -661,12 +762,39 @@ class AllNullableTypesWithoutRecursion { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(aNullableBool, other.aNullableBool) && + _deepEquals(aNullableInt, other.aNullableInt) && + _deepEquals(aNullableInt64, other.aNullableInt64) && + _deepEquals(aNullableDouble, other.aNullableDouble) && + _deepEquals(aNullableByteArray, other.aNullableByteArray) && + _deepEquals(aNullable4ByteArray, other.aNullable4ByteArray) && + _deepEquals(aNullable8ByteArray, other.aNullable8ByteArray) && + _deepEquals(aNullableFloatArray, other.aNullableFloatArray) && + _deepEquals(aNullableEnum, other.aNullableEnum) && + _deepEquals(anotherNullableEnum, other.anotherNullableEnum) && + _deepEquals(aNullableString, other.aNullableString) && + _deepEquals(aNullableObject, other.aNullableObject) && + _deepEquals(list, other.list) && + _deepEquals(stringList, other.stringList) && + _deepEquals(intList, other.intList) && + _deepEquals(doubleList, other.doubleList) && + _deepEquals(boolList, other.boolList) && + _deepEquals(enumList, other.enumList) && + _deepEquals(objectList, other.objectList) && + _deepEquals(listList, other.listList) && + _deepEquals(mapList, other.mapList) && + _deepEquals(map, other.map) && + _deepEquals(stringMap, other.stringMap) && + _deepEquals(intMap, other.intMap) && + _deepEquals(enumMap, other.enumMap) && + _deepEquals(objectMap, other.objectMap) && + _deepEquals(listMap, other.listMap) && + _deepEquals(mapMap, other.mapMap); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// A class for testing nested class handling. @@ -740,12 +868,21 @@ class AllClassesWrapper { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(allNullableTypes, other.allNullableTypes) && + _deepEquals( + allNullableTypesWithoutRecursion, + other.allNullableTypesWithoutRecursion, + ) && + _deepEquals(allTypes, other.allTypes) && + _deepEquals(classList, other.classList) && + _deepEquals(nullableClassList, other.nullableClassList) && + _deepEquals(classMap, other.classMap) && + _deepEquals(nullableClassMap, other.nullableClassMap); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// A data class containing a List, used in unit tests. @@ -776,12 +913,12 @@ class TestMessage { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(testList, other.testList); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { @@ -1562,6 +1699,77 @@ class HostIntegrationCoreApi { return pigeonVar_replyValue as int; } + /// Returns the result of platform-side equality check. + Future areAllNullableTypesEqual( + AllNullableTypes a, + AllNullableTypes b, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.areAllNullableTypesEqual$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [a, b], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + )!; + return pigeonVar_replyValue as bool; + } + + /// Returns the platform-side hash code for the given object. + Future getAllNullableTypesHash(AllNullableTypes value) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.getAllNullableTypesHash$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [value], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + )!; + return pigeonVar_replyValue as int; + } + + /// Returns the platform-side hash code for the given object. + Future getAllNullableTypesWithoutRecursionHash( + AllNullableTypesWithoutRecursion value, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.getAllNullableTypesWithoutRecursionHash$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [value], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + )!; + return pigeonVar_replyValue as int; + } + /// Returns the passed object, to test serialization and deserialization. Future echoAllNullableTypes( AllNullableTypes? everything, diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/enum.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/enum.gen.dart index d5cb251222e0..cf5e3ef39b93 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/enum.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/enum.gen.dart @@ -52,6 +52,14 @@ List wrapResponse({ } bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -59,16 +67,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += _deepHash(entry.key) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + /// This comment is to test enum documentation comments. enum EnumState { /// This comment is to test enum member (Pending) documentation comments. @@ -113,12 +157,12 @@ class DataWithEnum { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(state, other.state); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_tests.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_tests.gen.dart index 8ad8dd6ba6c1..ac3db8d170cd 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_tests.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_tests.gen.dart @@ -13,6 +13,14 @@ import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; import 'package:flutter/services.dart'; bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -20,16 +28,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += _deepHash(entry.key) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + enum EventEnum { one, two, three, fortyTwo, fourHundredTwentyTwo } enum AnotherEventEnum { justInCase } @@ -225,12 +269,42 @@ class EventAllNullableTypes { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(aNullableBool, other.aNullableBool) && + _deepEquals(aNullableInt, other.aNullableInt) && + _deepEquals(aNullableInt64, other.aNullableInt64) && + _deepEquals(aNullableDouble, other.aNullableDouble) && + _deepEquals(aNullableByteArray, other.aNullableByteArray) && + _deepEquals(aNullable4ByteArray, other.aNullable4ByteArray) && + _deepEquals(aNullable8ByteArray, other.aNullable8ByteArray) && + _deepEquals(aNullableFloatArray, other.aNullableFloatArray) && + _deepEquals(aNullableEnum, other.aNullableEnum) && + _deepEquals(anotherNullableEnum, other.anotherNullableEnum) && + _deepEquals(aNullableString, other.aNullableString) && + _deepEquals(aNullableObject, other.aNullableObject) && + _deepEquals(allNullableTypes, other.allNullableTypes) && + _deepEquals(list, other.list) && + _deepEquals(stringList, other.stringList) && + _deepEquals(intList, other.intList) && + _deepEquals(doubleList, other.doubleList) && + _deepEquals(boolList, other.boolList) && + _deepEquals(enumList, other.enumList) && + _deepEquals(objectList, other.objectList) && + _deepEquals(listList, other.listList) && + _deepEquals(mapList, other.mapList) && + _deepEquals(recursiveClassList, other.recursiveClassList) && + _deepEquals(map, other.map) && + _deepEquals(stringMap, other.stringMap) && + _deepEquals(intMap, other.intMap) && + _deepEquals(enumMap, other.enumMap) && + _deepEquals(objectMap, other.objectMap) && + _deepEquals(listMap, other.listMap) && + _deepEquals(mapMap, other.mapMap) && + _deepEquals(recursiveClassMap, other.recursiveClassMap); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } sealed class PlatformEvent {} @@ -262,12 +336,12 @@ class IntEvent extends PlatformEvent { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(value, other.value); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class StringEvent extends PlatformEvent { @@ -297,12 +371,12 @@ class StringEvent extends PlatformEvent { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(value, other.value); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class BoolEvent extends PlatformEvent { @@ -332,12 +406,12 @@ class BoolEvent extends PlatformEvent { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(value, other.value); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class DoubleEvent extends PlatformEvent { @@ -367,12 +441,12 @@ class DoubleEvent extends PlatformEvent { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(value, other.value); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class ObjectsEvent extends PlatformEvent { @@ -402,12 +476,12 @@ class ObjectsEvent extends PlatformEvent { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(value, other.value); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class EnumEvent extends PlatformEvent { @@ -437,12 +511,12 @@ class EnumEvent extends PlatformEvent { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(value, other.value); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class ClassEvent extends PlatformEvent { @@ -472,12 +546,12 @@ class ClassEvent extends PlatformEvent { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(value, other.value); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/flutter_unittests.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/flutter_unittests.gen.dart index 0c470ba7e2f7..dc9fe75689e7 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/flutter_unittests.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/flutter_unittests.gen.dart @@ -38,6 +38,14 @@ Object? _extractReplyValueOrThrow( } bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -45,16 +53,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += _deepHash(entry.key) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + class FlutterSearchRequest { FlutterSearchRequest({this.query}); @@ -82,12 +126,12 @@ class FlutterSearchRequest { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(query, other.query); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class FlutterSearchReply { @@ -122,12 +166,12 @@ class FlutterSearchReply { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(result, other.result) && _deepEquals(error, other.error); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class FlutterSearchRequests { @@ -157,12 +201,12 @@ class FlutterSearchRequests { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(requests, other.requests); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class FlutterSearchReplies { @@ -192,12 +236,12 @@ class FlutterSearchReplies { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(replies, other.replies); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/message.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/message.gen.dart index 3c16b1c9c19d..61d19f3d23c9 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/message.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/message.gen.dart @@ -52,6 +52,14 @@ List wrapResponse({ } bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -59,16 +67,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += _deepHash(entry.key) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + /// This comment is to test enum documentation comments. /// /// This comment also tests multiple line comments. @@ -119,12 +163,14 @@ class MessageSearchRequest { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(query, other.query) && + _deepEquals(anInt, other.anInt) && + _deepEquals(aBool, other.aBool); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// This comment is to test class documentation comments. @@ -168,12 +214,14 @@ class MessageSearchReply { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(result, other.result) && + _deepEquals(error, other.error) && + _deepEquals(state, other.state); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// This comment is to test class documentation comments. @@ -205,12 +253,12 @@ class MessageNested { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(request, other.request); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/non_null_fields.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/non_null_fields.gen.dart index d5173300a6b6..d36c6324aab2 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/non_null_fields.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/non_null_fields.gen.dart @@ -52,6 +52,14 @@ List wrapResponse({ } bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -59,16 +67,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += _deepHash(entry.key) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + enum ReplyType { success, error } class NonNullFieldSearchRequest { @@ -99,12 +143,12 @@ class NonNullFieldSearchRequest { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(query, other.query); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class ExtraData { @@ -139,12 +183,13 @@ class ExtraData { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(detailA, other.detailA) && + _deepEquals(detailB, other.detailB); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class NonNullFieldSearchReply { @@ -194,12 +239,16 @@ class NonNullFieldSearchReply { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(result, other.result) && + _deepEquals(error, other.error) && + _deepEquals(indices, other.indices) && + _deepEquals(extraData, other.extraData) && + _deepEquals(type, other.type); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/null_fields.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/null_fields.gen.dart index 0c0fe277fa15..98f15bccd4af 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/null_fields.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/null_fields.gen.dart @@ -52,6 +52,14 @@ List wrapResponse({ } bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -59,16 +67,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += _deepHash(entry.key) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + enum NullFieldsSearchReplyType { success, failure } class NullFieldsSearchRequest { @@ -103,12 +147,13 @@ class NullFieldsSearchRequest { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(query, other.query) && + _deepEquals(identifier, other.identifier); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class NullFieldsSearchReply { @@ -158,12 +203,16 @@ class NullFieldsSearchReply { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(result, other.result) && + _deepEquals(error, other.error) && + _deepEquals(indices, other.indices) && + _deepEquals(request, other.request) && + _deepEquals(type, other.type); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/test/equality_test.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/test/equality_test.dart new file mode 100644 index 000000000000..65dbab12067d --- /dev/null +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/test/equality_test.dart @@ -0,0 +1,228 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:shared_test_plugin_code/src/generated/core_tests.gen.dart'; +import 'package:shared_test_plugin_code/src/generated/non_null_fields.gen.dart'; +import 'package:shared_test_plugin_code/test_types.dart'; + +void main() { + test('NaN equality', () { + final list = [double.nan]; + final map = {1: double.nan}; + final all1 = AllNullableTypes( + aNullableDouble: double.nan, + doubleList: list, + recursiveClassList: [ + AllNullableTypes(aNullableDouble: double.nan), + ], + map: map, + ); + final all2 = AllNullableTypes( + aNullableDouble: double.nan, + doubleList: list, + recursiveClassList: [ + AllNullableTypes(aNullableDouble: double.nan), + ], + map: map, + ); + + expect(all1, all2); + expect(all1.hashCode, all2.hashCode); + }); + + test('Nested collection equality', () { + final all1 = AllNullableTypes( + listList: >[ + [1, 2], + ], + mapMap: >{ + 1: {'a': 'b'}, + }, + ); + final all2 = AllNullableTypes( + listList: >[ + [1, 2], + ], + mapMap: >{ + 1: {'a': 'b'}, + }, + ); + + expect(all1, all2); + expect(all1.hashCode, all2.hashCode); + }); + + test('Cross-type equality returns false', () { + final a = AllNullableTypes(aNullableInt: 1); + final b = AllNullableTypesWithoutRecursion(aNullableInt: 1); + // ignore: unrelated_type_equality_checks + expect(a == b, isFalse); + // ignore: unrelated_type_equality_checks + expect(b == a, isFalse); + }); + + test('non-null fields equality', () { + final request1 = NonNullFieldSearchRequest(query: 'hello'); + final request2 = NonNullFieldSearchRequest(query: 'hello'); + final request3 = NonNullFieldSearchRequest(query: 'world'); + + expect(request1, request2); + expect(request1, isNot(request3)); + expect(request1.hashCode, request2.hashCode); + }); + + group('deep equality', () { + final correctList = ['a', 2, 'three']; + final List matchingList = correctList.toList(); + final differentList = ['a', 2, 'three', 4.0]; + final correctMap = {'a': 1, 'b': 2, 'c': 'three'}; + final matchingMap = {...correctMap}; + final differentKeyMap = {'a': 1, 'b': 2, 'd': 'three'}; + final differentValueMap = {'a': 1, 'b': 2, 'c': 'five'}; + final correctListInMap = { + 'a': 1, + 'b': 2, + 'c': correctList, + }; + final matchingListInMap = { + 'a': 1, + 'b': 2, + 'c': matchingList, + }; + final differentListInMap = { + 'a': 1, + 'b': 2, + 'c': differentList, + }; + final correctMapInList = ['a', 2, correctMap]; + final matchingMapInList = ['a', 2, matchingMap]; + final differentKeyMapInList = ['a', 2, differentKeyMap]; + final differentValueMapInList = ['a', 2, differentValueMap]; + + test('equality method correctly checks deep equality', () { + final AllNullableTypes generic = genericAllNullableTypes; + final AllNullableTypes identical = AllNullableTypes.decode( + generic.encode(), + ); + expect(identical, generic); + }); + + test('equality method correctly identifies non-matching classes', () { + final AllNullableTypes generic = genericAllNullableTypes; + final allNull = AllNullableTypes(); + expect(allNull == generic, false); + }); + + test( + 'equality method correctly identifies non-matching lists in classes', + () { + final withList = AllNullableTypes(list: correctList); + final withDifferentList = AllNullableTypes(list: differentList); + expect(withList == withDifferentList, false); + }, + ); + + test( + 'equality method correctly identifies matching -but unique- lists in classes', + () { + final withList = AllNullableTypes(list: correctList); + final withDifferentList = AllNullableTypes(list: matchingList); + expect(withList, withDifferentList); + }, + ); + + test( + 'equality method correctly identifies non-matching keys in maps in classes', + () { + final withMap = AllNullableTypes(map: correctMap); + final withDifferentMap = AllNullableTypes(map: differentKeyMap); + expect(withMap == withDifferentMap, false); + }, + ); + + test( + 'equality method correctly identifies non-matching values in maps in classes', + () { + final withMap = AllNullableTypes(map: correctMap); + final withDifferentMap = AllNullableTypes(map: differentValueMap); + expect(withMap == withDifferentMap, false); + }, + ); + + test( + 'equality method correctly identifies matching -but unique- maps in classes', + () { + final withMap = AllNullableTypes(map: correctMap); + final withDifferentMap = AllNullableTypes(map: matchingMap); + expect(withMap, withDifferentMap); + }, + ); + test('signed zero equality', () { + final v1 = AllNullableTypes(aNullableDouble: 0.0); + final v2 = AllNullableTypes(aNullableDouble: -0.0); + expect(v1, v2); + expect(v1.hashCode, v2.hashCode); + }); + test('signed zero map key equality', () { + final v1 = AllNullableTypes(map: {0.0: 'a'}); + final v2 = AllNullableTypes(map: {-0.0: 'a'}); + expect(v1, v2); + expect(v1.hashCode, v2.hashCode); + }); + + test( + 'equality method correctly identifies non-matching lists nested in maps in classes', + () { + final withListInMap = AllNullableTypes(map: correctListInMap); + final withDifferentListInMap = AllNullableTypes( + map: differentListInMap, + ); + expect(withListInMap == withDifferentListInMap, false); + }, + ); + + test( + 'equality method correctly identifies matching -but unique- lists nested in maps in classes', + () { + final withListInMap = AllNullableTypes(map: correctListInMap); + final withDifferentListInMap = AllNullableTypes(map: matchingListInMap); + expect(withListInMap, withDifferentListInMap); + }, + ); + + test( + 'equality method correctly identifies non-matching keys in maps nested in lists in classes', + () { + final withMapInList = AllNullableTypes(list: correctMapInList); + final withDifferentMapInList = AllNullableTypes( + list: differentKeyMapInList, + ); + expect(withMapInList == withDifferentMapInList, false); + }, + ); + + test( + 'equality method correctly identifies non-matching values in maps nested in lists in classes', + () { + final withMapInList = AllNullableTypes(list: correctMapInList); + final withDifferentMapInList = AllNullableTypes( + list: differentValueMapInList, + ); + expect(withMapInList == withDifferentMapInList, false); + }, + ); + + test( + 'equality method correctly identifies matching -but unique- maps nested in lists in classes', + () { + final withMapInList = AllNullableTypes(list: correctMapInList); + final withDifferentMapInList = AllNullableTypes( + list: matchingMapInList, + ); + expect(withMapInList, withDifferentMapInList); + }, + ); + }); +} diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/test/generated_dart_test_code_test.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/test/generated_dart_test_code_test.dart index 8d9431687fc0..c5c03e0deede 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/test/generated_dart_test_code_test.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/test/generated_dart_test_code_test.dart @@ -6,10 +6,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:shared_test_plugin_code/src/generated/core_tests.gen.dart' - show AllNullableTypes; import 'package:shared_test_plugin_code/src/generated/message.gen.dart'; -import 'package:shared_test_plugin_code/test_types.dart'; import 'test_message.gen.dart'; @@ -44,146 +41,6 @@ class MockNested implements TestNestedApi { void main() { TestWidgetsFlutterBinding.ensureInitialized(); - group('equality method', () { - final correctList = ['a', 2, 'three']; - final List matchingList = correctList.toList(); - final differentList = ['a', 2, 'three', 4.0]; - final correctMap = {'a': 1, 'b': 2, 'c': 'three'}; - final matchingMap = {...correctMap}; - final differentKeyMap = {'a': 1, 'b': 2, 'd': 'three'}; - final differentValueMap = {'a': 1, 'b': 2, 'c': 'five'}; - final correctListInMap = { - 'a': 1, - 'b': 2, - 'c': correctList, - }; - final matchingListInMap = { - 'a': 1, - 'b': 2, - 'c': matchingList, - }; - final differentListInMap = { - 'a': 1, - 'b': 2, - 'c': differentList, - }; - final correctMapInList = ['a', 2, correctMap]; - final matchingMapInList = ['a', 2, matchingMap]; - final differentKeyMapInList = ['a', 2, differentKeyMap]; - final differentValueMapInList = ['a', 2, differentValueMap]; - - test('equality method correctly checks deep equality', () { - final AllNullableTypes generic = genericAllNullableTypes; - final AllNullableTypes identical = AllNullableTypes.decode( - generic.encode(), - ); - expect(identical, generic); - }); - - test('equality method correctly identifies non-matching classes', () { - final AllNullableTypes generic = genericAllNullableTypes; - final allNull = AllNullableTypes(); - expect(allNull == generic, false); - }); - - test( - 'equality method correctly identifies non-matching lists in classes', - () { - final withList = AllNullableTypes(list: correctList); - final withDifferentList = AllNullableTypes(list: differentList); - expect(withList == withDifferentList, false); - }, - ); - - test( - 'equality method correctly identifies matching -but unique- lists in classes', - () { - final withList = AllNullableTypes(list: correctList); - final withDifferentList = AllNullableTypes(list: matchingList); - expect(withList, withDifferentList); - }, - ); - - test( - 'equality method correctly identifies non-matching keys in maps in classes', - () { - final withMap = AllNullableTypes(map: correctMap); - final withDifferentMap = AllNullableTypes(map: differentKeyMap); - expect(withMap == withDifferentMap, false); - }, - ); - - test( - 'equality method correctly identifies non-matching values in maps in classes', - () { - final withMap = AllNullableTypes(map: correctMap); - final withDifferentMap = AllNullableTypes(map: differentValueMap); - expect(withMap == withDifferentMap, false); - }, - ); - - test( - 'equality method correctly identifies matching -but unique- maps in classes', - () { - final withMap = AllNullableTypes(map: correctMap); - final withDifferentMap = AllNullableTypes(map: matchingMap); - expect(withMap, withDifferentMap); - }, - ); - - test( - 'equality method correctly identifies non-matching lists nested in maps in classes', - () { - final withListInMap = AllNullableTypes(map: correctListInMap); - final withDifferentListInMap = AllNullableTypes( - map: differentListInMap, - ); - expect(withListInMap == withDifferentListInMap, false); - }, - ); - - test( - 'equality method correctly identifies matching -but unique- lists nested in maps in classes', - () { - final withListInMap = AllNullableTypes(map: correctListInMap); - final withDifferentListInMap = AllNullableTypes(map: matchingListInMap); - expect(withListInMap, withDifferentListInMap); - }, - ); - - test( - 'equality method correctly identifies non-matching keys in maps nested in lists in classes', - () { - final withMapInList = AllNullableTypes(list: correctMapInList); - final withDifferentMapInList = AllNullableTypes( - list: differentKeyMapInList, - ); - expect(withMapInList == withDifferentMapInList, false); - }, - ); - - test( - 'equality method correctly identifies non-matching values in maps nested in lists in classes', - () { - final withMapInList = AllNullableTypes(list: correctMapInList); - final withDifferentMapInList = AllNullableTypes( - list: differentValueMapInList, - ); - expect(withMapInList == withDifferentMapInList, false); - }, - ); - - test( - 'equality method correctly identifies matching -but unique- maps nested in lists in classes', - () { - final withMapInList = AllNullableTypes(list: correctMapInList); - final withDifferentMapInList = AllNullableTypes( - list: matchingMapInList, - ); - expect(withMapInList, withDifferentMapInList); - }, - ); - }); test('simple', () async { final api = MessageNestedApi(); final mock = MockNested(); diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt index fe73e18c0998..b5eec31bf9c4 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt @@ -38,7 +38,33 @@ private object CoreTestsPigeonUtils { } } + fun doubleEquals(a: Double, b: Double): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0) 0.0 else a) == (if (b == 0.0) 0.0 else b) || (a.isNaN() && b.isNaN()) + } + + fun floatEquals(a: Float, b: Float): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0f) 0.0f else a) == (if (b == 0.0f) 0.0f else b) || (a.isNaN() && b.isNaN()) + } + + fun doubleHash(d: Double): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (d == 0.0) 0.0 else d + val bits = java.lang.Double.doubleToLongBits(normalized) + return (bits xor (bits ushr 32)).toInt() + } + + fun floatHash(f: Float): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (f == 0.0f) 0.0f else f + return java.lang.Float.floatToIntBits(normalized) + } + fun deepEquals(a: Any?, b: Any?): Boolean { + if (a === b) { + return true + } if (a is ByteArray && b is ByteArray) { return a.contentEquals(b) } @@ -49,20 +75,93 @@ private object CoreTestsPigeonUtils { return a.contentEquals(b) } if (a is DoubleArray && b is DoubleArray) { - return a.contentEquals(b) + if (a.size != b.size) return false + for (i in a.indices) { + if (!doubleEquals(a[i], b[i])) return false + } + return true + } + if (a is FloatArray && b is FloatArray) { + if (a.size != b.size) return false + for (i in a.indices) { + if (!floatEquals(a[i], b[i])) return false + } + return true } if (a is Array<*> && b is Array<*>) { - return a.size == b.size && a.indices.all { deepEquals(a[it], b[it]) } + return a.contentDeepEquals(b) } if (a is List<*> && b is List<*>) { return a.size == b.size && a.indices.all { deepEquals(a[it], b[it]) } } if (a is Map<*, *> && b is Map<*, *>) { - return a.size == b.size && - a.all { (b as Map).contains(it.key) && deepEquals(it.value, b[it.key]) } + if (a.size != b.size) return false + for (entry in a) { + val key = entry.key + var found = false + for (bEntry in b) { + if (deepEquals(key, bEntry.key)) { + if (deepEquals(entry.value, bEntry.value)) { + found = true + break + } else { + return false + } + } + } + if (!found) return false + } + return true + } + if (a is Double && b is Double) { + return doubleEquals(a, b) + } + if (a is Float && b is Float) { + return floatEquals(a, b) } return a == b } + + fun deepHash(value: Any?): Int { + return when (value) { + null -> 0 + is ByteArray -> value.contentHashCode() + is IntArray -> value.contentHashCode() + is LongArray -> value.contentHashCode() + is DoubleArray -> { + var result = 1 + for (item in value) { + result = 31 * result + doubleHash(item) + } + result + } + is FloatArray -> { + var result = 1 + for (item in value) { + result = 31 * result + floatHash(item) + } + result + } + is Array<*> -> value.contentDeepHashCode() + is List<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is Map<*, *> -> { + var result = 0 + for (entry in value) { + result += (deepHash(entry.key) xor deepHash(entry.value)) + } + result + } + is Double -> doubleHash(value) + is Float -> floatHash(value) + else -> value.hashCode() + } + } } /** @@ -118,16 +217,21 @@ data class UnusedClass(val aField: Any? = null) { } override fun equals(other: Any?): Boolean { - if (other !is UnusedClass) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return CoreTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as UnusedClass + return CoreTestsPigeonUtils.deepEquals(this.aField, other.aField) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aField) + return result + } } /** @@ -261,16 +365,75 @@ data class AllTypes( } override fun equals(other: Any?): Boolean { - if (other !is AllTypes) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return CoreTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as AllTypes + return CoreTestsPigeonUtils.deepEquals(this.aBool, other.aBool) && + CoreTestsPigeonUtils.deepEquals(this.anInt, other.anInt) && + CoreTestsPigeonUtils.deepEquals(this.anInt64, other.anInt64) && + CoreTestsPigeonUtils.deepEquals(this.aDouble, other.aDouble) && + CoreTestsPigeonUtils.deepEquals(this.aByteArray, other.aByteArray) && + CoreTestsPigeonUtils.deepEquals(this.a4ByteArray, other.a4ByteArray) && + CoreTestsPigeonUtils.deepEquals(this.a8ByteArray, other.a8ByteArray) && + CoreTestsPigeonUtils.deepEquals(this.aFloatArray, other.aFloatArray) && + CoreTestsPigeonUtils.deepEquals(this.anEnum, other.anEnum) && + CoreTestsPigeonUtils.deepEquals(this.anotherEnum, other.anotherEnum) && + CoreTestsPigeonUtils.deepEquals(this.aString, other.aString) && + CoreTestsPigeonUtils.deepEquals(this.anObject, other.anObject) && + CoreTestsPigeonUtils.deepEquals(this.list, other.list) && + CoreTestsPigeonUtils.deepEquals(this.stringList, other.stringList) && + CoreTestsPigeonUtils.deepEquals(this.intList, other.intList) && + CoreTestsPigeonUtils.deepEquals(this.doubleList, other.doubleList) && + CoreTestsPigeonUtils.deepEquals(this.boolList, other.boolList) && + CoreTestsPigeonUtils.deepEquals(this.enumList, other.enumList) && + CoreTestsPigeonUtils.deepEquals(this.objectList, other.objectList) && + CoreTestsPigeonUtils.deepEquals(this.listList, other.listList) && + CoreTestsPigeonUtils.deepEquals(this.mapList, other.mapList) && + CoreTestsPigeonUtils.deepEquals(this.map, other.map) && + CoreTestsPigeonUtils.deepEquals(this.stringMap, other.stringMap) && + CoreTestsPigeonUtils.deepEquals(this.intMap, other.intMap) && + CoreTestsPigeonUtils.deepEquals(this.enumMap, other.enumMap) && + CoreTestsPigeonUtils.deepEquals(this.objectMap, other.objectMap) && + CoreTestsPigeonUtils.deepEquals(this.listMap, other.listMap) && + CoreTestsPigeonUtils.deepEquals(this.mapMap, other.mapMap) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aBool) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.anInt) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.anInt64) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aDouble) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aByteArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.a4ByteArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.a8ByteArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aFloatArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.anEnum) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.anotherEnum) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aString) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.anObject) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.list) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.stringList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.intList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.doubleList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.boolList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.enumList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.objectList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.listList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.mapList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.map) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.stringMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.intMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.enumMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.objectMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.listMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.mapMap) + return result + } } /** @@ -416,16 +579,81 @@ data class AllNullableTypes( } override fun equals(other: Any?): Boolean { - if (other !is AllNullableTypes) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return CoreTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as AllNullableTypes + return CoreTestsPigeonUtils.deepEquals(this.aNullableBool, other.aNullableBool) && + CoreTestsPigeonUtils.deepEquals(this.aNullableInt, other.aNullableInt) && + CoreTestsPigeonUtils.deepEquals(this.aNullableInt64, other.aNullableInt64) && + CoreTestsPigeonUtils.deepEquals(this.aNullableDouble, other.aNullableDouble) && + CoreTestsPigeonUtils.deepEquals(this.aNullableByteArray, other.aNullableByteArray) && + CoreTestsPigeonUtils.deepEquals(this.aNullable4ByteArray, other.aNullable4ByteArray) && + CoreTestsPigeonUtils.deepEquals(this.aNullable8ByteArray, other.aNullable8ByteArray) && + CoreTestsPigeonUtils.deepEquals(this.aNullableFloatArray, other.aNullableFloatArray) && + CoreTestsPigeonUtils.deepEquals(this.aNullableEnum, other.aNullableEnum) && + CoreTestsPigeonUtils.deepEquals(this.anotherNullableEnum, other.anotherNullableEnum) && + CoreTestsPigeonUtils.deepEquals(this.aNullableString, other.aNullableString) && + CoreTestsPigeonUtils.deepEquals(this.aNullableObject, other.aNullableObject) && + CoreTestsPigeonUtils.deepEquals(this.allNullableTypes, other.allNullableTypes) && + CoreTestsPigeonUtils.deepEquals(this.list, other.list) && + CoreTestsPigeonUtils.deepEquals(this.stringList, other.stringList) && + CoreTestsPigeonUtils.deepEquals(this.intList, other.intList) && + CoreTestsPigeonUtils.deepEquals(this.doubleList, other.doubleList) && + CoreTestsPigeonUtils.deepEquals(this.boolList, other.boolList) && + CoreTestsPigeonUtils.deepEquals(this.enumList, other.enumList) && + CoreTestsPigeonUtils.deepEquals(this.objectList, other.objectList) && + CoreTestsPigeonUtils.deepEquals(this.listList, other.listList) && + CoreTestsPigeonUtils.deepEquals(this.mapList, other.mapList) && + CoreTestsPigeonUtils.deepEquals(this.recursiveClassList, other.recursiveClassList) && + CoreTestsPigeonUtils.deepEquals(this.map, other.map) && + CoreTestsPigeonUtils.deepEquals(this.stringMap, other.stringMap) && + CoreTestsPigeonUtils.deepEquals(this.intMap, other.intMap) && + CoreTestsPigeonUtils.deepEquals(this.enumMap, other.enumMap) && + CoreTestsPigeonUtils.deepEquals(this.objectMap, other.objectMap) && + CoreTestsPigeonUtils.deepEquals(this.listMap, other.listMap) && + CoreTestsPigeonUtils.deepEquals(this.mapMap, other.mapMap) && + CoreTestsPigeonUtils.deepEquals(this.recursiveClassMap, other.recursiveClassMap) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableBool) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableInt) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableInt64) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableDouble) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableByteArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullable4ByteArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullable8ByteArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableFloatArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableEnum) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.anotherNullableEnum) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableString) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableObject) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.allNullableTypes) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.list) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.stringList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.intList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.doubleList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.boolList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.enumList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.objectList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.listList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.mapList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.recursiveClassList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.map) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.stringMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.intMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.enumMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.objectMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.listMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.mapMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.recursiveClassMap) + return result + } } /** @@ -560,16 +788,75 @@ data class AllNullableTypesWithoutRecursion( } override fun equals(other: Any?): Boolean { - if (other !is AllNullableTypesWithoutRecursion) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return CoreTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as AllNullableTypesWithoutRecursion + return CoreTestsPigeonUtils.deepEquals(this.aNullableBool, other.aNullableBool) && + CoreTestsPigeonUtils.deepEquals(this.aNullableInt, other.aNullableInt) && + CoreTestsPigeonUtils.deepEquals(this.aNullableInt64, other.aNullableInt64) && + CoreTestsPigeonUtils.deepEquals(this.aNullableDouble, other.aNullableDouble) && + CoreTestsPigeonUtils.deepEquals(this.aNullableByteArray, other.aNullableByteArray) && + CoreTestsPigeonUtils.deepEquals(this.aNullable4ByteArray, other.aNullable4ByteArray) && + CoreTestsPigeonUtils.deepEquals(this.aNullable8ByteArray, other.aNullable8ByteArray) && + CoreTestsPigeonUtils.deepEquals(this.aNullableFloatArray, other.aNullableFloatArray) && + CoreTestsPigeonUtils.deepEquals(this.aNullableEnum, other.aNullableEnum) && + CoreTestsPigeonUtils.deepEquals(this.anotherNullableEnum, other.anotherNullableEnum) && + CoreTestsPigeonUtils.deepEquals(this.aNullableString, other.aNullableString) && + CoreTestsPigeonUtils.deepEquals(this.aNullableObject, other.aNullableObject) && + CoreTestsPigeonUtils.deepEquals(this.list, other.list) && + CoreTestsPigeonUtils.deepEquals(this.stringList, other.stringList) && + CoreTestsPigeonUtils.deepEquals(this.intList, other.intList) && + CoreTestsPigeonUtils.deepEquals(this.doubleList, other.doubleList) && + CoreTestsPigeonUtils.deepEquals(this.boolList, other.boolList) && + CoreTestsPigeonUtils.deepEquals(this.enumList, other.enumList) && + CoreTestsPigeonUtils.deepEquals(this.objectList, other.objectList) && + CoreTestsPigeonUtils.deepEquals(this.listList, other.listList) && + CoreTestsPigeonUtils.deepEquals(this.mapList, other.mapList) && + CoreTestsPigeonUtils.deepEquals(this.map, other.map) && + CoreTestsPigeonUtils.deepEquals(this.stringMap, other.stringMap) && + CoreTestsPigeonUtils.deepEquals(this.intMap, other.intMap) && + CoreTestsPigeonUtils.deepEquals(this.enumMap, other.enumMap) && + CoreTestsPigeonUtils.deepEquals(this.objectMap, other.objectMap) && + CoreTestsPigeonUtils.deepEquals(this.listMap, other.listMap) && + CoreTestsPigeonUtils.deepEquals(this.mapMap, other.mapMap) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableBool) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableInt) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableInt64) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableDouble) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableByteArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullable4ByteArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullable8ByteArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableFloatArray) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableEnum) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.anotherNullableEnum) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableString) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.aNullableObject) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.list) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.stringList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.intList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.doubleList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.boolList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.enumList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.objectList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.listList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.mapList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.map) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.stringMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.intMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.enumMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.objectMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.listMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.mapMap) + return result + } } /** @@ -623,16 +910,34 @@ data class AllClassesWrapper( } override fun equals(other: Any?): Boolean { - if (other !is AllClassesWrapper) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return CoreTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as AllClassesWrapper + return CoreTestsPigeonUtils.deepEquals(this.allNullableTypes, other.allNullableTypes) && + CoreTestsPigeonUtils.deepEquals( + this.allNullableTypesWithoutRecursion, other.allNullableTypesWithoutRecursion) && + CoreTestsPigeonUtils.deepEquals(this.allTypes, other.allTypes) && + CoreTestsPigeonUtils.deepEquals(this.classList, other.classList) && + CoreTestsPigeonUtils.deepEquals(this.nullableClassList, other.nullableClassList) && + CoreTestsPigeonUtils.deepEquals(this.classMap, other.classMap) && + CoreTestsPigeonUtils.deepEquals(this.nullableClassMap, other.nullableClassMap) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.allNullableTypes) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.allNullableTypesWithoutRecursion) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.allTypes) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.classList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.nullableClassList) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.classMap) + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.nullableClassMap) + return result + } } /** @@ -655,16 +960,21 @@ data class TestMessage(val testList: List? = null) { } override fun equals(other: Any?): Boolean { - if (other !is TestMessage) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return CoreTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as TestMessage + return CoreTestsPigeonUtils.deepEquals(this.testList, other.testList) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + CoreTestsPigeonUtils.deepHash(this.testList) + return result + } } private open class CoreTestsPigeonCodec : StandardMessageCodec() { @@ -808,6 +1118,12 @@ interface HostIntegrationCoreApi { fun echoOptionalDefaultDouble(aDouble: Double): Double /** Returns passed in int. */ fun echoRequiredInt(anInt: Long): Long + /** Returns the result of platform-side equality check. */ + fun areAllNullableTypesEqual(a: AllNullableTypes, b: AllNullableTypes): Boolean + /** Returns the platform-side hash code for the given object. */ + fun getAllNullableTypesHash(value: AllNullableTypes): Long + /** Returns the platform-side hash code for the given object. */ + fun getAllNullableTypesWithoutRecursionHash(value: AllNullableTypesWithoutRecursion): Long /** Returns the passed object, to test serialization and deserialization. */ fun echoAllNullableTypes(everything: AllNullableTypes?): AllNullableTypes? /** Returns the passed object, to test serialization and deserialization. */ @@ -1900,6 +2216,73 @@ interface HostIntegrationCoreApi { channel.setMessageHandler(null) } } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.areAllNullableTypesEqual$separatedMessageChannelSuffix", + codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val aArg = args[0] as AllNullableTypes + val bArg = args[1] as AllNullableTypes + val wrapped: List = + try { + listOf(api.areAllNullableTypesEqual(aArg, bArg)) + } catch (exception: Throwable) { + CoreTestsPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.getAllNullableTypesHash$separatedMessageChannelSuffix", + codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val valueArg = args[0] as AllNullableTypes + val wrapped: List = + try { + listOf(api.getAllNullableTypesHash(valueArg)) + } catch (exception: Throwable) { + CoreTestsPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.getAllNullableTypesWithoutRecursionHash$separatedMessageChannelSuffix", + codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val valueArg = args[0] as AllNullableTypesWithoutRecursion + val wrapped: List = + try { + listOf(api.getAllNullableTypesWithoutRecursionHash(valueArg)) + } catch (exception: Throwable) { + CoreTestsPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } run { val channel = BasicMessageChannel( diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/EventChannelTests.gen.kt b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/EventChannelTests.gen.kt index a3f79976d792..ba1bdae7763f 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/EventChannelTests.gen.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/EventChannelTests.gen.kt @@ -16,7 +16,33 @@ import java.io.ByteArrayOutputStream import java.nio.ByteBuffer private object EventChannelTestsPigeonUtils { + fun doubleEquals(a: Double, b: Double): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0) 0.0 else a) == (if (b == 0.0) 0.0 else b) || (a.isNaN() && b.isNaN()) + } + + fun floatEquals(a: Float, b: Float): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0f) 0.0f else a) == (if (b == 0.0f) 0.0f else b) || (a.isNaN() && b.isNaN()) + } + + fun doubleHash(d: Double): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (d == 0.0) 0.0 else d + val bits = java.lang.Double.doubleToLongBits(normalized) + return (bits xor (bits ushr 32)).toInt() + } + + fun floatHash(f: Float): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (f == 0.0f) 0.0f else f + return java.lang.Float.floatToIntBits(normalized) + } + fun deepEquals(a: Any?, b: Any?): Boolean { + if (a === b) { + return true + } if (a is ByteArray && b is ByteArray) { return a.contentEquals(b) } @@ -27,20 +53,93 @@ private object EventChannelTestsPigeonUtils { return a.contentEquals(b) } if (a is DoubleArray && b is DoubleArray) { - return a.contentEquals(b) + if (a.size != b.size) return false + for (i in a.indices) { + if (!doubleEquals(a[i], b[i])) return false + } + return true + } + if (a is FloatArray && b is FloatArray) { + if (a.size != b.size) return false + for (i in a.indices) { + if (!floatEquals(a[i], b[i])) return false + } + return true } if (a is Array<*> && b is Array<*>) { - return a.size == b.size && a.indices.all { deepEquals(a[it], b[it]) } + return a.contentDeepEquals(b) } if (a is List<*> && b is List<*>) { return a.size == b.size && a.indices.all { deepEquals(a[it], b[it]) } } if (a is Map<*, *> && b is Map<*, *>) { - return a.size == b.size && - a.all { (b as Map).contains(it.key) && deepEquals(it.value, b[it.key]) } + if (a.size != b.size) return false + for (entry in a) { + val key = entry.key + var found = false + for (bEntry in b) { + if (deepEquals(key, bEntry.key)) { + if (deepEquals(entry.value, bEntry.value)) { + found = true + break + } else { + return false + } + } + } + if (!found) return false + } + return true + } + if (a is Double && b is Double) { + return doubleEquals(a, b) + } + if (a is Float && b is Float) { + return floatEquals(a, b) } return a == b } + + fun deepHash(value: Any?): Int { + return when (value) { + null -> 0 + is ByteArray -> value.contentHashCode() + is IntArray -> value.contentHashCode() + is LongArray -> value.contentHashCode() + is DoubleArray -> { + var result = 1 + for (item in value) { + result = 31 * result + doubleHash(item) + } + result + } + is FloatArray -> { + var result = 1 + for (item in value) { + result = 31 * result + floatHash(item) + } + result + } + is Array<*> -> value.contentDeepHashCode() + is List<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is Map<*, *> -> { + var result = 0 + for (entry in value) { + result += (deepHash(entry.key) xor deepHash(entry.value)) + } + result + } + is Double -> doubleHash(value) + is Float -> floatHash(value) + else -> value.hashCode() + } + } } /** @@ -223,16 +322,87 @@ data class EventAllNullableTypes( } override fun equals(other: Any?): Boolean { - if (other !is EventAllNullableTypes) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return EventChannelTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as EventAllNullableTypes + return EventChannelTestsPigeonUtils.deepEquals(this.aNullableBool, other.aNullableBool) && + EventChannelTestsPigeonUtils.deepEquals(this.aNullableInt, other.aNullableInt) && + EventChannelTestsPigeonUtils.deepEquals(this.aNullableInt64, other.aNullableInt64) && + EventChannelTestsPigeonUtils.deepEquals(this.aNullableDouble, other.aNullableDouble) && + EventChannelTestsPigeonUtils.deepEquals( + this.aNullableByteArray, other.aNullableByteArray) && + EventChannelTestsPigeonUtils.deepEquals( + this.aNullable4ByteArray, other.aNullable4ByteArray) && + EventChannelTestsPigeonUtils.deepEquals( + this.aNullable8ByteArray, other.aNullable8ByteArray) && + EventChannelTestsPigeonUtils.deepEquals( + this.aNullableFloatArray, other.aNullableFloatArray) && + EventChannelTestsPigeonUtils.deepEquals(this.aNullableEnum, other.aNullableEnum) && + EventChannelTestsPigeonUtils.deepEquals( + this.anotherNullableEnum, other.anotherNullableEnum) && + EventChannelTestsPigeonUtils.deepEquals(this.aNullableString, other.aNullableString) && + EventChannelTestsPigeonUtils.deepEquals(this.aNullableObject, other.aNullableObject) && + EventChannelTestsPigeonUtils.deepEquals(this.allNullableTypes, other.allNullableTypes) && + EventChannelTestsPigeonUtils.deepEquals(this.list, other.list) && + EventChannelTestsPigeonUtils.deepEquals(this.stringList, other.stringList) && + EventChannelTestsPigeonUtils.deepEquals(this.intList, other.intList) && + EventChannelTestsPigeonUtils.deepEquals(this.doubleList, other.doubleList) && + EventChannelTestsPigeonUtils.deepEquals(this.boolList, other.boolList) && + EventChannelTestsPigeonUtils.deepEquals(this.enumList, other.enumList) && + EventChannelTestsPigeonUtils.deepEquals(this.objectList, other.objectList) && + EventChannelTestsPigeonUtils.deepEquals(this.listList, other.listList) && + EventChannelTestsPigeonUtils.deepEquals(this.mapList, other.mapList) && + EventChannelTestsPigeonUtils.deepEquals( + this.recursiveClassList, other.recursiveClassList) && + EventChannelTestsPigeonUtils.deepEquals(this.map, other.map) && + EventChannelTestsPigeonUtils.deepEquals(this.stringMap, other.stringMap) && + EventChannelTestsPigeonUtils.deepEquals(this.intMap, other.intMap) && + EventChannelTestsPigeonUtils.deepEquals(this.enumMap, other.enumMap) && + EventChannelTestsPigeonUtils.deepEquals(this.objectMap, other.objectMap) && + EventChannelTestsPigeonUtils.deepEquals(this.listMap, other.listMap) && + EventChannelTestsPigeonUtils.deepEquals(this.mapMap, other.mapMap) && + EventChannelTestsPigeonUtils.deepEquals(this.recursiveClassMap, other.recursiveClassMap) + } + + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullableBool) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullableInt) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullableInt64) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullableDouble) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullableByteArray) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullable4ByteArray) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullable8ByteArray) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullableFloatArray) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullableEnum) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.anotherNullableEnum) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullableString) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.aNullableObject) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.allNullableTypes) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.list) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.stringList) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.intList) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.doubleList) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.boolList) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.enumList) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.objectList) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.listList) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.mapList) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.recursiveClassList) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.map) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.stringMap) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.intMap) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.enumMap) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.objectMap) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.listMap) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.mapMap) + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.recursiveClassMap) + return result } - - override fun hashCode(): Int = toList().hashCode() } /** @@ -256,16 +426,21 @@ data class IntEvent(val value: Long) : PlatformEvent() { } override fun equals(other: Any?): Boolean { - if (other !is IntEvent) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return EventChannelTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as IntEvent + return EventChannelTestsPigeonUtils.deepEquals(this.value, other.value) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.value) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -284,16 +459,21 @@ data class StringEvent(val value: String) : PlatformEvent() { } override fun equals(other: Any?): Boolean { - if (other !is StringEvent) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return EventChannelTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as StringEvent + return EventChannelTestsPigeonUtils.deepEquals(this.value, other.value) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.value) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -312,16 +492,21 @@ data class BoolEvent(val value: Boolean) : PlatformEvent() { } override fun equals(other: Any?): Boolean { - if (other !is BoolEvent) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return EventChannelTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as BoolEvent + return EventChannelTestsPigeonUtils.deepEquals(this.value, other.value) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.value) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -340,16 +525,21 @@ data class DoubleEvent(val value: Double) : PlatformEvent() { } override fun equals(other: Any?): Boolean { - if (other !is DoubleEvent) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return EventChannelTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as DoubleEvent + return EventChannelTestsPigeonUtils.deepEquals(this.value, other.value) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.value) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -368,16 +558,21 @@ data class ObjectsEvent(val value: Any) : PlatformEvent() { } override fun equals(other: Any?): Boolean { - if (other !is ObjectsEvent) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return EventChannelTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as ObjectsEvent + return EventChannelTestsPigeonUtils.deepEquals(this.value, other.value) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.value) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -396,16 +591,21 @@ data class EnumEvent(val value: EventEnum) : PlatformEvent() { } override fun equals(other: Any?): Boolean { - if (other !is EnumEvent) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return EventChannelTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as EnumEvent + return EventChannelTestsPigeonUtils.deepEquals(this.value, other.value) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.value) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -424,16 +624,21 @@ data class ClassEvent(val value: EventAllNullableTypes) : PlatformEvent() { } override fun equals(other: Any?): Boolean { - if (other !is ClassEvent) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return EventChannelTestsPigeonUtils.deepEquals(toList(), other.toList()) + val other = other as ClassEvent + return EventChannelTestsPigeonUtils.deepEquals(this.value, other.value) } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + EventChannelTestsPigeonUtils.deepHash(this.value) + return result + } } private open class EventChannelTestsPigeonCodec : StandardMessageCodec() { diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt index e032596170cc..ea402e91d7a4 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt @@ -53,6 +53,20 @@ class TestPlugin : FlutterPlugin, HostIntegrationCoreApi { return everything } + override fun areAllNullableTypesEqual(a: AllNullableTypes, b: AllNullableTypes): Boolean { + return a == b + } + + override fun getAllNullableTypesHash(value: AllNullableTypes): Long { + return value.hashCode().toLong() + } + + override fun getAllNullableTypesWithoutRecursionHash( + value: AllNullableTypesWithoutRecursion + ): Long { + return value.hashCode().toLong() + } + override fun echoAllNullableTypesWithoutRecursion( everything: AllNullableTypesWithoutRecursion? ): AllNullableTypesWithoutRecursion? { diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AllDatatypesTest.kt b/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AllDatatypesTest.kt index e2f80062c6e2..6946fa864d03 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AllDatatypesTest.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AllDatatypesTest.kt @@ -227,4 +227,53 @@ internal class AllDatatypesTest { val withDifferentMapInList = AllNullableTypes(list = matchingMapInList) assertEquals(withMapInList, withDifferentMapInList) } + + @Test + fun `equality method correctly identifies NaN matches`() { + val withNaN = AllNullableTypes(aNullableDouble = Double.NaN) + val withAnotherNaN = AllNullableTypes(aNullableDouble = Double.NaN) + assertEquals(withNaN, withAnotherNaN) + assertEquals(withNaN.hashCode(), withAnotherNaN.hashCode()) + } + + @Test + fun `cross-type equality returns false`() { + val a = AllNullableTypes(aNullableInt = 1) + val b = AllNullableTypesWithoutRecursion(aNullableInt = 1) + assertNotEquals(a, b) + assertNotEquals(b, a) + } + + @Test + fun `byteArray equality`() { + val a = AllNullableTypes(aNullableByteArray = byteArrayOf(1, 2, 3)) + val b = AllNullableTypes(aNullableByteArray = byteArrayOf(1, 2, 3)) + assertEquals(a, b) + assertEquals(a.hashCode(), b.hashCode()) + } + + @Test + fun `zero equality`() { + val a = AllNullableTypes(aNullableDouble = 0.0) + val b = AllNullableTypes(aNullableDouble = -0.0) + // In many platforms, 0.0 and -0.0 are treated as equal. + assertEquals(a, b) + assertEquals(a.hashCode(), b.hashCode()) + } + + @Test + fun `zero map key equality`() { + val a = AllNullableTypes(map = mapOf(0.0 to "a")) + val b = AllNullableTypes(map = mapOf(-0.0 to "a")) + assertEquals(a, b) + assertEquals(a.hashCode(), b.hashCode()) + } + + @Test + fun `nested NaN equality`() { + val a = AllNullableTypes(doubleList = listOf(Double.NaN)) + val b = AllNullableTypes(doubleList = listOf(Double.NaN)) + assertEquals(a, b) + assertEquals(a.hashCode(), b.hashCode()) + } } diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/NonNullFieldsTests.kt b/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/NonNullFieldsTests.kt index e5e97394f18f..fad1532b0599 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/NonNullFieldsTests.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/NonNullFieldsTests.kt @@ -14,4 +14,15 @@ class NonNullFieldsTests { val request = NonNullFieldSearchRequest("hello") assertEquals("hello", request.query) } + + @Test + fun testEquality() { + val request1 = NonNullFieldSearchRequest("hello") + val request2 = NonNullFieldSearchRequest("hello") + val request3 = NonNullFieldSearchRequest("world") + + assertEquals(request1, request2) + assert(request1 != request3) + assertEquals(request1.hashCode(), request2.hashCode()) + } } diff --git a/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/CoreTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/CoreTests.gen.swift index ddea768974b8..1ebfa898b1ef 100644 --- a/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/CoreTests.gen.swift +++ b/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/CoreTests.gen.swift @@ -54,7 +54,7 @@ private func wrapError(_ error: Any) -> [Any?] { } return [ "\(error)", - "\(type(of: error))", + "\(Swift.type(of: error))", "Stacktrace: \(Thread.callStackSymbols)", ] } @@ -74,6 +74,19 @@ private func nilOrValue(_ value: Any?) -> T? { return value as! T? } +private func doubleEqualsCoreTests(_ lhs: Double, _ rhs: Double) -> Bool { + return (lhs.isNaN && rhs.isNaN) || lhs == rhs +} + +private func doubleHashCoreTests(_ value: Double, _ hasher: inout Hasher) { + if value.isNaN { + hasher.combine(0x7FF8_0000_0000_0000) + } else { + // Normalize -0.0 to 0.0 + hasher.combine(value == 0 ? 0 : value) + } +} + func deepEqualsCoreTests(_ lhs: Any?, _ rhs: Any?) -> Bool { let cleanLhs = nilOrValue(lhs) as Any? let cleanRhs = nilOrValue(rhs) as Any? @@ -84,56 +97,90 @@ func deepEqualsCoreTests(_ lhs: Any?, _ rhs: Any?) -> Bool { case (nil, _), (_, nil): return false - case is (Void, Void): + case (let lhs as AnyObject, let rhs as AnyObject) where lhs === rhs: return true - case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable): - return cleanLhsHashable == cleanRhsHashable + case is (Void, Void): + return true - case let (cleanLhsArray, cleanRhsArray) as ([Any?], [Any?]): - guard cleanLhsArray.count == cleanRhsArray.count else { return false } - for (index, element) in cleanLhsArray.enumerated() { - if !deepEqualsCoreTests(element, cleanRhsArray[index]) { + case (let lhsArray, let rhsArray) as ([Any?], [Any?]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !deepEqualsCoreTests(element, rhsArray[index]) { return false } } return true - case let (cleanLhsDictionary, cleanRhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): - guard cleanLhsDictionary.count == cleanRhsDictionary.count else { return false } - for (key, cleanLhsValue) in cleanLhsDictionary { - guard cleanRhsDictionary.index(forKey: key) != nil else { return false } - if !deepEqualsCoreTests(cleanLhsValue, cleanRhsDictionary[key]!) { + case (let lhsArray, let rhsArray) as ([Double], [Double]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !doubleEqualsCoreTests(element, rhsArray[index]) { return false } } return true + case (let lhsDictionary, let rhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): + guard lhsDictionary.count == rhsDictionary.count else { return false } + for (lhsKey, lhsValue) in lhsDictionary { + var found = false + for (rhsKey, rhsValue) in rhsDictionary { + if deepEqualsCoreTests(lhsKey, rhsKey) { + if deepEqualsCoreTests(lhsValue, rhsValue) { + found = true + break + } else { + return false + } + } + } + if !found { return false } + } + return true + + case (let lhs as Double, let rhs as Double): + return doubleEqualsCoreTests(lhs, rhs) + + case (let lhsHashable, let rhsHashable) as (AnyHashable, AnyHashable): + return lhsHashable == rhsHashable + default: - // Any other type shouldn't be able to be used with pigeon. File an issue if you find this to be untrue. return false } } func deepHashCoreTests(value: Any?, hasher: inout Hasher) { - if let valueList = value as? [AnyHashable] { - for item in valueList { deepHashCoreTests(value: item, hasher: &hasher) } - return + let cleanValue = nilOrValue(value) as Any? + if let cleanValue = cleanValue { + if let doubleValue = cleanValue as? Double { + doubleHashCoreTests(doubleValue, &hasher) + } else if let valueList = cleanValue as? [Any?] { + for item in valueList { + deepHashCoreTests(value: item, hasher: &hasher) + } + } else if let valueList = cleanValue as? [Double] { + for item in valueList { + doubleHashCoreTests(item, &hasher) + } + } else if let valueDict = cleanValue as? [AnyHashable: Any?] { + var result = 0 + for (key, value) in valueDict { + var entryKeyHasher = Hasher() + deepHashCoreTests(value: key, hasher: &entryKeyHasher) + var entryValueHasher = Hasher() + deepHashCoreTests(value: value, hasher: &entryValueHasher) + result = result &+ (entryKeyHasher.finalize() ^ entryValueHasher.finalize()) + } + hasher.combine(result) + } else if let hashableValue = cleanValue as? AnyHashable { + hasher.combine(hashableValue) + } else { + hasher.combine(String(describing: cleanValue)) + } + } else { + hasher.combine(0) } - - if let valueDict = value as? [AnyHashable: AnyHashable] { - for key in valueDict.keys { - hasher.combine(key) - deepHashCoreTests(value: valueDict[key]!, hasher: &hasher) - } - return - } - - if let hashableValue = value as? AnyHashable { - hasher.combine(hashableValue.hashValue) - } - - return hasher.combine(String(describing: value)) } enum AnEnum: Int { @@ -166,10 +213,15 @@ struct UnusedClass: Hashable { ] } static func == (lhs: UnusedClass, rhs: UnusedClass) -> Bool { - return deepEqualsCoreTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsCoreTests(lhs.aField, rhs.aField) } + func hash(into hasher: inout Hasher) { - deepHashCoreTests(value: toList(), hasher: &hasher) + hasher.combine("UnusedClass") + deepHashCoreTests(value: aField, hasher: &hasher) } } @@ -301,10 +353,66 @@ struct AllTypes: Hashable { ] } static func == (lhs: AllTypes, rhs: AllTypes) -> Bool { - return deepEqualsCoreTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsCoreTests(lhs.aBool, rhs.aBool) && deepEqualsCoreTests(lhs.anInt, rhs.anInt) + && deepEqualsCoreTests(lhs.anInt64, rhs.anInt64) + && deepEqualsCoreTests(lhs.aDouble, rhs.aDouble) + && deepEqualsCoreTests(lhs.aByteArray, rhs.aByteArray) + && deepEqualsCoreTests(lhs.a4ByteArray, rhs.a4ByteArray) + && deepEqualsCoreTests(lhs.a8ByteArray, rhs.a8ByteArray) + && deepEqualsCoreTests(lhs.aFloatArray, rhs.aFloatArray) + && deepEqualsCoreTests(lhs.anEnum, rhs.anEnum) + && deepEqualsCoreTests(lhs.anotherEnum, rhs.anotherEnum) + && deepEqualsCoreTests(lhs.aString, rhs.aString) + && deepEqualsCoreTests(lhs.anObject, rhs.anObject) && deepEqualsCoreTests(lhs.list, rhs.list) + && deepEqualsCoreTests(lhs.stringList, rhs.stringList) + && deepEqualsCoreTests(lhs.intList, rhs.intList) + && deepEqualsCoreTests(lhs.doubleList, rhs.doubleList) + && deepEqualsCoreTests(lhs.boolList, rhs.boolList) + && deepEqualsCoreTests(lhs.enumList, rhs.enumList) + && deepEqualsCoreTests(lhs.objectList, rhs.objectList) + && deepEqualsCoreTests(lhs.listList, rhs.listList) + && deepEqualsCoreTests(lhs.mapList, rhs.mapList) && deepEqualsCoreTests(lhs.map, rhs.map) + && deepEqualsCoreTests(lhs.stringMap, rhs.stringMap) + && deepEqualsCoreTests(lhs.intMap, rhs.intMap) + && deepEqualsCoreTests(lhs.enumMap, rhs.enumMap) + && deepEqualsCoreTests(lhs.objectMap, rhs.objectMap) + && deepEqualsCoreTests(lhs.listMap, rhs.listMap) + && deepEqualsCoreTests(lhs.mapMap, rhs.mapMap) } + func hash(into hasher: inout Hasher) { - deepHashCoreTests(value: toList(), hasher: &hasher) + hasher.combine("AllTypes") + deepHashCoreTests(value: aBool, hasher: &hasher) + deepHashCoreTests(value: anInt, hasher: &hasher) + deepHashCoreTests(value: anInt64, hasher: &hasher) + deepHashCoreTests(value: aDouble, hasher: &hasher) + deepHashCoreTests(value: aByteArray, hasher: &hasher) + deepHashCoreTests(value: a4ByteArray, hasher: &hasher) + deepHashCoreTests(value: a8ByteArray, hasher: &hasher) + deepHashCoreTests(value: aFloatArray, hasher: &hasher) + deepHashCoreTests(value: anEnum, hasher: &hasher) + deepHashCoreTests(value: anotherEnum, hasher: &hasher) + deepHashCoreTests(value: aString, hasher: &hasher) + deepHashCoreTests(value: anObject, hasher: &hasher) + deepHashCoreTests(value: list, hasher: &hasher) + deepHashCoreTests(value: stringList, hasher: &hasher) + deepHashCoreTests(value: intList, hasher: &hasher) + deepHashCoreTests(value: doubleList, hasher: &hasher) + deepHashCoreTests(value: boolList, hasher: &hasher) + deepHashCoreTests(value: enumList, hasher: &hasher) + deepHashCoreTests(value: objectList, hasher: &hasher) + deepHashCoreTests(value: listList, hasher: &hasher) + deepHashCoreTests(value: mapList, hasher: &hasher) + deepHashCoreTests(value: map, hasher: &hasher) + deepHashCoreTests(value: stringMap, hasher: &hasher) + deepHashCoreTests(value: intMap, hasher: &hasher) + deepHashCoreTests(value: enumMap, hasher: &hasher) + deepHashCoreTests(value: objectMap, hasher: &hasher) + deepHashCoreTests(value: listMap, hasher: &hasher) + deepHashCoreTests(value: mapMap, hasher: &hasher) } } @@ -513,13 +621,77 @@ class AllNullableTypes: Hashable { ] } static func == (lhs: AllNullableTypes, rhs: AllNullableTypes) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } if lhs === rhs { return true } - return deepEqualsCoreTests(lhs.toList(), rhs.toList()) + return deepEqualsCoreTests(lhs.aNullableBool, rhs.aNullableBool) + && deepEqualsCoreTests(lhs.aNullableInt, rhs.aNullableInt) + && deepEqualsCoreTests(lhs.aNullableInt64, rhs.aNullableInt64) + && deepEqualsCoreTests(lhs.aNullableDouble, rhs.aNullableDouble) + && deepEqualsCoreTests(lhs.aNullableByteArray, rhs.aNullableByteArray) + && deepEqualsCoreTests(lhs.aNullable4ByteArray, rhs.aNullable4ByteArray) + && deepEqualsCoreTests(lhs.aNullable8ByteArray, rhs.aNullable8ByteArray) + && deepEqualsCoreTests(lhs.aNullableFloatArray, rhs.aNullableFloatArray) + && deepEqualsCoreTests(lhs.aNullableEnum, rhs.aNullableEnum) + && deepEqualsCoreTests(lhs.anotherNullableEnum, rhs.anotherNullableEnum) + && deepEqualsCoreTests(lhs.aNullableString, rhs.aNullableString) + && deepEqualsCoreTests(lhs.aNullableObject, rhs.aNullableObject) + && deepEqualsCoreTests(lhs.allNullableTypes, rhs.allNullableTypes) + && deepEqualsCoreTests(lhs.list, rhs.list) + && deepEqualsCoreTests(lhs.stringList, rhs.stringList) + && deepEqualsCoreTests(lhs.intList, rhs.intList) + && deepEqualsCoreTests(lhs.doubleList, rhs.doubleList) + && deepEqualsCoreTests(lhs.boolList, rhs.boolList) + && deepEqualsCoreTests(lhs.enumList, rhs.enumList) + && deepEqualsCoreTests(lhs.objectList, rhs.objectList) + && deepEqualsCoreTests(lhs.listList, rhs.listList) + && deepEqualsCoreTests(lhs.mapList, rhs.mapList) + && deepEqualsCoreTests(lhs.recursiveClassList, rhs.recursiveClassList) + && deepEqualsCoreTests(lhs.map, rhs.map) && deepEqualsCoreTests(lhs.stringMap, rhs.stringMap) + && deepEqualsCoreTests(lhs.intMap, rhs.intMap) + && deepEqualsCoreTests(lhs.enumMap, rhs.enumMap) + && deepEqualsCoreTests(lhs.objectMap, rhs.objectMap) + && deepEqualsCoreTests(lhs.listMap, rhs.listMap) + && deepEqualsCoreTests(lhs.mapMap, rhs.mapMap) + && deepEqualsCoreTests(lhs.recursiveClassMap, rhs.recursiveClassMap) } + func hash(into hasher: inout Hasher) { - deepHashCoreTests(value: toList(), hasher: &hasher) + hasher.combine("AllNullableTypes") + deepHashCoreTests(value: aNullableBool, hasher: &hasher) + deepHashCoreTests(value: aNullableInt, hasher: &hasher) + deepHashCoreTests(value: aNullableInt64, hasher: &hasher) + deepHashCoreTests(value: aNullableDouble, hasher: &hasher) + deepHashCoreTests(value: aNullableByteArray, hasher: &hasher) + deepHashCoreTests(value: aNullable4ByteArray, hasher: &hasher) + deepHashCoreTests(value: aNullable8ByteArray, hasher: &hasher) + deepHashCoreTests(value: aNullableFloatArray, hasher: &hasher) + deepHashCoreTests(value: aNullableEnum, hasher: &hasher) + deepHashCoreTests(value: anotherNullableEnum, hasher: &hasher) + deepHashCoreTests(value: aNullableString, hasher: &hasher) + deepHashCoreTests(value: aNullableObject, hasher: &hasher) + deepHashCoreTests(value: allNullableTypes, hasher: &hasher) + deepHashCoreTests(value: list, hasher: &hasher) + deepHashCoreTests(value: stringList, hasher: &hasher) + deepHashCoreTests(value: intList, hasher: &hasher) + deepHashCoreTests(value: doubleList, hasher: &hasher) + deepHashCoreTests(value: boolList, hasher: &hasher) + deepHashCoreTests(value: enumList, hasher: &hasher) + deepHashCoreTests(value: objectList, hasher: &hasher) + deepHashCoreTests(value: listList, hasher: &hasher) + deepHashCoreTests(value: mapList, hasher: &hasher) + deepHashCoreTests(value: recursiveClassList, hasher: &hasher) + deepHashCoreTests(value: map, hasher: &hasher) + deepHashCoreTests(value: stringMap, hasher: &hasher) + deepHashCoreTests(value: intMap, hasher: &hasher) + deepHashCoreTests(value: enumMap, hasher: &hasher) + deepHashCoreTests(value: objectMap, hasher: &hasher) + deepHashCoreTests(value: listMap, hasher: &hasher) + deepHashCoreTests(value: mapMap, hasher: &hasher) + deepHashCoreTests(value: recursiveClassMap, hasher: &hasher) } } @@ -655,10 +827,68 @@ struct AllNullableTypesWithoutRecursion: Hashable { static func == (lhs: AllNullableTypesWithoutRecursion, rhs: AllNullableTypesWithoutRecursion) -> Bool { - return deepEqualsCoreTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsCoreTests(lhs.aNullableBool, rhs.aNullableBool) + && deepEqualsCoreTests(lhs.aNullableInt, rhs.aNullableInt) + && deepEqualsCoreTests(lhs.aNullableInt64, rhs.aNullableInt64) + && deepEqualsCoreTests(lhs.aNullableDouble, rhs.aNullableDouble) + && deepEqualsCoreTests(lhs.aNullableByteArray, rhs.aNullableByteArray) + && deepEqualsCoreTests(lhs.aNullable4ByteArray, rhs.aNullable4ByteArray) + && deepEqualsCoreTests(lhs.aNullable8ByteArray, rhs.aNullable8ByteArray) + && deepEqualsCoreTests(lhs.aNullableFloatArray, rhs.aNullableFloatArray) + && deepEqualsCoreTests(lhs.aNullableEnum, rhs.aNullableEnum) + && deepEqualsCoreTests(lhs.anotherNullableEnum, rhs.anotherNullableEnum) + && deepEqualsCoreTests(lhs.aNullableString, rhs.aNullableString) + && deepEqualsCoreTests(lhs.aNullableObject, rhs.aNullableObject) + && deepEqualsCoreTests(lhs.list, rhs.list) + && deepEqualsCoreTests(lhs.stringList, rhs.stringList) + && deepEqualsCoreTests(lhs.intList, rhs.intList) + && deepEqualsCoreTests(lhs.doubleList, rhs.doubleList) + && deepEqualsCoreTests(lhs.boolList, rhs.boolList) + && deepEqualsCoreTests(lhs.enumList, rhs.enumList) + && deepEqualsCoreTests(lhs.objectList, rhs.objectList) + && deepEqualsCoreTests(lhs.listList, rhs.listList) + && deepEqualsCoreTests(lhs.mapList, rhs.mapList) && deepEqualsCoreTests(lhs.map, rhs.map) + && deepEqualsCoreTests(lhs.stringMap, rhs.stringMap) + && deepEqualsCoreTests(lhs.intMap, rhs.intMap) + && deepEqualsCoreTests(lhs.enumMap, rhs.enumMap) + && deepEqualsCoreTests(lhs.objectMap, rhs.objectMap) + && deepEqualsCoreTests(lhs.listMap, rhs.listMap) + && deepEqualsCoreTests(lhs.mapMap, rhs.mapMap) } + func hash(into hasher: inout Hasher) { - deepHashCoreTests(value: toList(), hasher: &hasher) + hasher.combine("AllNullableTypesWithoutRecursion") + deepHashCoreTests(value: aNullableBool, hasher: &hasher) + deepHashCoreTests(value: aNullableInt, hasher: &hasher) + deepHashCoreTests(value: aNullableInt64, hasher: &hasher) + deepHashCoreTests(value: aNullableDouble, hasher: &hasher) + deepHashCoreTests(value: aNullableByteArray, hasher: &hasher) + deepHashCoreTests(value: aNullable4ByteArray, hasher: &hasher) + deepHashCoreTests(value: aNullable8ByteArray, hasher: &hasher) + deepHashCoreTests(value: aNullableFloatArray, hasher: &hasher) + deepHashCoreTests(value: aNullableEnum, hasher: &hasher) + deepHashCoreTests(value: anotherNullableEnum, hasher: &hasher) + deepHashCoreTests(value: aNullableString, hasher: &hasher) + deepHashCoreTests(value: aNullableObject, hasher: &hasher) + deepHashCoreTests(value: list, hasher: &hasher) + deepHashCoreTests(value: stringList, hasher: &hasher) + deepHashCoreTests(value: intList, hasher: &hasher) + deepHashCoreTests(value: doubleList, hasher: &hasher) + deepHashCoreTests(value: boolList, hasher: &hasher) + deepHashCoreTests(value: enumList, hasher: &hasher) + deepHashCoreTests(value: objectList, hasher: &hasher) + deepHashCoreTests(value: listList, hasher: &hasher) + deepHashCoreTests(value: mapList, hasher: &hasher) + deepHashCoreTests(value: map, hasher: &hasher) + deepHashCoreTests(value: stringMap, hasher: &hasher) + deepHashCoreTests(value: intMap, hasher: &hasher) + deepHashCoreTests(value: enumMap, hasher: &hasher) + deepHashCoreTests(value: objectMap, hasher: &hasher) + deepHashCoreTests(value: listMap, hasher: &hasher) + deepHashCoreTests(value: mapMap, hasher: &hasher) } } @@ -712,10 +942,28 @@ struct AllClassesWrapper: Hashable { ] } static func == (lhs: AllClassesWrapper, rhs: AllClassesWrapper) -> Bool { - return deepEqualsCoreTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsCoreTests(lhs.allNullableTypes, rhs.allNullableTypes) + && deepEqualsCoreTests( + lhs.allNullableTypesWithoutRecursion, rhs.allNullableTypesWithoutRecursion) + && deepEqualsCoreTests(lhs.allTypes, rhs.allTypes) + && deepEqualsCoreTests(lhs.classList, rhs.classList) + && deepEqualsCoreTests(lhs.nullableClassList, rhs.nullableClassList) + && deepEqualsCoreTests(lhs.classMap, rhs.classMap) + && deepEqualsCoreTests(lhs.nullableClassMap, rhs.nullableClassMap) } + func hash(into hasher: inout Hasher) { - deepHashCoreTests(value: toList(), hasher: &hasher) + hasher.combine("AllClassesWrapper") + deepHashCoreTests(value: allNullableTypes, hasher: &hasher) + deepHashCoreTests(value: allNullableTypesWithoutRecursion, hasher: &hasher) + deepHashCoreTests(value: allTypes, hasher: &hasher) + deepHashCoreTests(value: classList, hasher: &hasher) + deepHashCoreTests(value: nullableClassList, hasher: &hasher) + deepHashCoreTests(value: classMap, hasher: &hasher) + deepHashCoreTests(value: nullableClassMap, hasher: &hasher) } } @@ -739,10 +987,15 @@ struct TestMessage: Hashable { ] } static func == (lhs: TestMessage, rhs: TestMessage) -> Bool { - return deepEqualsCoreTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsCoreTests(lhs.testList, rhs.testList) } + func hash(into hasher: inout Hasher) { - deepHashCoreTests(value: toList(), hasher: &hasher) + hasher.combine("TestMessage") + deepHashCoreTests(value: testList, hasher: &hasher) } } @@ -893,6 +1146,13 @@ protocol HostIntegrationCoreApi { func echoOptionalDefault(_ aDouble: Double) throws -> Double /// Returns passed in int. func echoRequired(_ anInt: Int64) throws -> Int64 + /// Returns the result of platform-side equality check. + func areAllNullableTypesEqual(a: AllNullableTypes, b: AllNullableTypes) throws -> Bool + /// Returns the platform-side hash code for the given object. + func getAllNullableTypesHash(value: AllNullableTypes) throws -> Int64 + /// Returns the platform-side hash code for the given object. + func getAllNullableTypesWithoutRecursionHash(value: AllNullableTypesWithoutRecursion) throws + -> Int64 /// Returns the passed object, to test serialization and deserialization. func echo(_ everything: AllNullableTypes?) throws -> AllNullableTypes? /// Returns the passed object, to test serialization and deserialization. @@ -1785,6 +2045,64 @@ class HostIntegrationCoreApiSetup { } else { echoRequiredIntChannel.setMessageHandler(nil) } + /// Returns the result of platform-side equality check. + let areAllNullableTypesEqualChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.areAllNullableTypesEqual\(channelSuffix)", + binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + areAllNullableTypesEqualChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let aArg = args[0] as! AllNullableTypes + let bArg = args[1] as! AllNullableTypes + do { + let result = try api.areAllNullableTypesEqual(a: aArg, b: bArg) + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + areAllNullableTypesEqualChannel.setMessageHandler(nil) + } + /// Returns the platform-side hash code for the given object. + let getAllNullableTypesHashChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.getAllNullableTypesHash\(channelSuffix)", + binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getAllNullableTypesHashChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let valueArg = args[0] as! AllNullableTypes + do { + let result = try api.getAllNullableTypesHash(value: valueArg) + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + getAllNullableTypesHashChannel.setMessageHandler(nil) + } + /// Returns the platform-side hash code for the given object. + let getAllNullableTypesWithoutRecursionHashChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.getAllNullableTypesWithoutRecursionHash\(channelSuffix)", + binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getAllNullableTypesWithoutRecursionHashChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let valueArg = args[0] as! AllNullableTypesWithoutRecursion + do { + let result = try api.getAllNullableTypesWithoutRecursionHash(value: valueArg) + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + getAllNullableTypesWithoutRecursionHashChannel.setMessageHandler(nil) + } /// Returns the passed object, to test serialization and deserialization. let echoAllNullableTypesChannel = FlutterBasicMessageChannel( name: diff --git a/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/EventChannelTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/EventChannelTests.gen.swift index 6eeace16d903..ac5e8d7dea66 100644 --- a/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/EventChannelTests.gen.swift +++ b/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/EventChannelTests.gen.swift @@ -42,6 +42,19 @@ private func nilOrValue(_ value: Any?) -> T? { return value as! T? } +private func doubleEqualsEventChannelTests(_ lhs: Double, _ rhs: Double) -> Bool { + return (lhs.isNaN && rhs.isNaN) || lhs == rhs +} + +private func doubleHashEventChannelTests(_ value: Double, _ hasher: inout Hasher) { + if value.isNaN { + hasher.combine(0x7FF8_0000_0000_0000) + } else { + // Normalize -0.0 to 0.0 + hasher.combine(value == 0 ? 0 : value) + } +} + func deepEqualsEventChannelTests(_ lhs: Any?, _ rhs: Any?) -> Bool { let cleanLhs = nilOrValue(lhs) as Any? let cleanRhs = nilOrValue(rhs) as Any? @@ -52,56 +65,90 @@ func deepEqualsEventChannelTests(_ lhs: Any?, _ rhs: Any?) -> Bool { case (nil, _), (_, nil): return false - case is (Void, Void): + case (let lhs as AnyObject, let rhs as AnyObject) where lhs === rhs: return true - case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable): - return cleanLhsHashable == cleanRhsHashable + case is (Void, Void): + return true - case let (cleanLhsArray, cleanRhsArray) as ([Any?], [Any?]): - guard cleanLhsArray.count == cleanRhsArray.count else { return false } - for (index, element) in cleanLhsArray.enumerated() { - if !deepEqualsEventChannelTests(element, cleanRhsArray[index]) { + case (let lhsArray, let rhsArray) as ([Any?], [Any?]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !deepEqualsEventChannelTests(element, rhsArray[index]) { return false } } return true - case let (cleanLhsDictionary, cleanRhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): - guard cleanLhsDictionary.count == cleanRhsDictionary.count else { return false } - for (key, cleanLhsValue) in cleanLhsDictionary { - guard cleanRhsDictionary.index(forKey: key) != nil else { return false } - if !deepEqualsEventChannelTests(cleanLhsValue, cleanRhsDictionary[key]!) { + case (let lhsArray, let rhsArray) as ([Double], [Double]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !doubleEqualsEventChannelTests(element, rhsArray[index]) { return false } } return true + case (let lhsDictionary, let rhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): + guard lhsDictionary.count == rhsDictionary.count else { return false } + for (lhsKey, lhsValue) in lhsDictionary { + var found = false + for (rhsKey, rhsValue) in rhsDictionary { + if deepEqualsEventChannelTests(lhsKey, rhsKey) { + if deepEqualsEventChannelTests(lhsValue, rhsValue) { + found = true + break + } else { + return false + } + } + } + if !found { return false } + } + return true + + case (let lhs as Double, let rhs as Double): + return doubleEqualsEventChannelTests(lhs, rhs) + + case (let lhsHashable, let rhsHashable) as (AnyHashable, AnyHashable): + return lhsHashable == rhsHashable + default: - // Any other type shouldn't be able to be used with pigeon. File an issue if you find this to be untrue. return false } } func deepHashEventChannelTests(value: Any?, hasher: inout Hasher) { - if let valueList = value as? [AnyHashable] { - for item in valueList { deepHashEventChannelTests(value: item, hasher: &hasher) } - return - } - - if let valueDict = value as? [AnyHashable: AnyHashable] { - for key in valueDict.keys { - hasher.combine(key) - deepHashEventChannelTests(value: valueDict[key]!, hasher: &hasher) + let cleanValue = nilOrValue(value) as Any? + if let cleanValue = cleanValue { + if let doubleValue = cleanValue as? Double { + doubleHashEventChannelTests(doubleValue, &hasher) + } else if let valueList = cleanValue as? [Any?] { + for item in valueList { + deepHashEventChannelTests(value: item, hasher: &hasher) + } + } else if let valueList = cleanValue as? [Double] { + for item in valueList { + doubleHashEventChannelTests(item, &hasher) + } + } else if let valueDict = cleanValue as? [AnyHashable: Any?] { + var result = 0 + for (key, value) in valueDict { + var entryKeyHasher = Hasher() + deepHashEventChannelTests(value: key, hasher: &entryKeyHasher) + var entryValueHasher = Hasher() + deepHashEventChannelTests(value: value, hasher: &entryValueHasher) + result = result &+ (entryKeyHasher.finalize() ^ entryValueHasher.finalize()) + } + hasher.combine(result) + } else if let hashableValue = cleanValue as? AnyHashable { + hasher.combine(hashableValue) + } else { + hasher.combine(String(describing: cleanValue)) } - return - } - - if let hashableValue = value as? AnyHashable { - hasher.combine(hashableValue.hashValue) + } else { + hasher.combine(0) } - - return hasher.combine(String(describing: value)) } enum EventEnum: Int { @@ -321,13 +368,78 @@ class EventAllNullableTypes: Hashable { ] } static func == (lhs: EventAllNullableTypes, rhs: EventAllNullableTypes) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } if lhs === rhs { return true } - return deepEqualsEventChannelTests(lhs.toList(), rhs.toList()) + return deepEqualsEventChannelTests(lhs.aNullableBool, rhs.aNullableBool) + && deepEqualsEventChannelTests(lhs.aNullableInt, rhs.aNullableInt) + && deepEqualsEventChannelTests(lhs.aNullableInt64, rhs.aNullableInt64) + && deepEqualsEventChannelTests(lhs.aNullableDouble, rhs.aNullableDouble) + && deepEqualsEventChannelTests(lhs.aNullableByteArray, rhs.aNullableByteArray) + && deepEqualsEventChannelTests(lhs.aNullable4ByteArray, rhs.aNullable4ByteArray) + && deepEqualsEventChannelTests(lhs.aNullable8ByteArray, rhs.aNullable8ByteArray) + && deepEqualsEventChannelTests(lhs.aNullableFloatArray, rhs.aNullableFloatArray) + && deepEqualsEventChannelTests(lhs.aNullableEnum, rhs.aNullableEnum) + && deepEqualsEventChannelTests(lhs.anotherNullableEnum, rhs.anotherNullableEnum) + && deepEqualsEventChannelTests(lhs.aNullableString, rhs.aNullableString) + && deepEqualsEventChannelTests(lhs.aNullableObject, rhs.aNullableObject) + && deepEqualsEventChannelTests(lhs.allNullableTypes, rhs.allNullableTypes) + && deepEqualsEventChannelTests(lhs.list, rhs.list) + && deepEqualsEventChannelTests(lhs.stringList, rhs.stringList) + && deepEqualsEventChannelTests(lhs.intList, rhs.intList) + && deepEqualsEventChannelTests(lhs.doubleList, rhs.doubleList) + && deepEqualsEventChannelTests(lhs.boolList, rhs.boolList) + && deepEqualsEventChannelTests(lhs.enumList, rhs.enumList) + && deepEqualsEventChannelTests(lhs.objectList, rhs.objectList) + && deepEqualsEventChannelTests(lhs.listList, rhs.listList) + && deepEqualsEventChannelTests(lhs.mapList, rhs.mapList) + && deepEqualsEventChannelTests(lhs.recursiveClassList, rhs.recursiveClassList) + && deepEqualsEventChannelTests(lhs.map, rhs.map) + && deepEqualsEventChannelTests(lhs.stringMap, rhs.stringMap) + && deepEqualsEventChannelTests(lhs.intMap, rhs.intMap) + && deepEqualsEventChannelTests(lhs.enumMap, rhs.enumMap) + && deepEqualsEventChannelTests(lhs.objectMap, rhs.objectMap) + && deepEqualsEventChannelTests(lhs.listMap, rhs.listMap) + && deepEqualsEventChannelTests(lhs.mapMap, rhs.mapMap) + && deepEqualsEventChannelTests(lhs.recursiveClassMap, rhs.recursiveClassMap) } + func hash(into hasher: inout Hasher) { - deepHashEventChannelTests(value: toList(), hasher: &hasher) + hasher.combine("EventAllNullableTypes") + deepHashEventChannelTests(value: aNullableBool, hasher: &hasher) + deepHashEventChannelTests(value: aNullableInt, hasher: &hasher) + deepHashEventChannelTests(value: aNullableInt64, hasher: &hasher) + deepHashEventChannelTests(value: aNullableDouble, hasher: &hasher) + deepHashEventChannelTests(value: aNullableByteArray, hasher: &hasher) + deepHashEventChannelTests(value: aNullable4ByteArray, hasher: &hasher) + deepHashEventChannelTests(value: aNullable8ByteArray, hasher: &hasher) + deepHashEventChannelTests(value: aNullableFloatArray, hasher: &hasher) + deepHashEventChannelTests(value: aNullableEnum, hasher: &hasher) + deepHashEventChannelTests(value: anotherNullableEnum, hasher: &hasher) + deepHashEventChannelTests(value: aNullableString, hasher: &hasher) + deepHashEventChannelTests(value: aNullableObject, hasher: &hasher) + deepHashEventChannelTests(value: allNullableTypes, hasher: &hasher) + deepHashEventChannelTests(value: list, hasher: &hasher) + deepHashEventChannelTests(value: stringList, hasher: &hasher) + deepHashEventChannelTests(value: intList, hasher: &hasher) + deepHashEventChannelTests(value: doubleList, hasher: &hasher) + deepHashEventChannelTests(value: boolList, hasher: &hasher) + deepHashEventChannelTests(value: enumList, hasher: &hasher) + deepHashEventChannelTests(value: objectList, hasher: &hasher) + deepHashEventChannelTests(value: listList, hasher: &hasher) + deepHashEventChannelTests(value: mapList, hasher: &hasher) + deepHashEventChannelTests(value: recursiveClassList, hasher: &hasher) + deepHashEventChannelTests(value: map, hasher: &hasher) + deepHashEventChannelTests(value: stringMap, hasher: &hasher) + deepHashEventChannelTests(value: intMap, hasher: &hasher) + deepHashEventChannelTests(value: enumMap, hasher: &hasher) + deepHashEventChannelTests(value: objectMap, hasher: &hasher) + deepHashEventChannelTests(value: listMap, hasher: &hasher) + deepHashEventChannelTests(value: mapMap, hasher: &hasher) + deepHashEventChannelTests(value: recursiveClassMap, hasher: &hasher) } } @@ -355,10 +467,15 @@ struct IntEvent: PlatformEvent { ] } static func == (lhs: IntEvent, rhs: IntEvent) -> Bool { - return deepEqualsEventChannelTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsEventChannelTests(lhs.value, rhs.value) } + func hash(into hasher: inout Hasher) { - deepHashEventChannelTests(value: toList(), hasher: &hasher) + hasher.combine("IntEvent") + deepHashEventChannelTests(value: value, hasher: &hasher) } } @@ -380,10 +497,15 @@ struct StringEvent: PlatformEvent { ] } static func == (lhs: StringEvent, rhs: StringEvent) -> Bool { - return deepEqualsEventChannelTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsEventChannelTests(lhs.value, rhs.value) } + func hash(into hasher: inout Hasher) { - deepHashEventChannelTests(value: toList(), hasher: &hasher) + hasher.combine("StringEvent") + deepHashEventChannelTests(value: value, hasher: &hasher) } } @@ -405,10 +527,15 @@ struct BoolEvent: PlatformEvent { ] } static func == (lhs: BoolEvent, rhs: BoolEvent) -> Bool { - return deepEqualsEventChannelTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsEventChannelTests(lhs.value, rhs.value) } + func hash(into hasher: inout Hasher) { - deepHashEventChannelTests(value: toList(), hasher: &hasher) + hasher.combine("BoolEvent") + deepHashEventChannelTests(value: value, hasher: &hasher) } } @@ -430,10 +557,15 @@ struct DoubleEvent: PlatformEvent { ] } static func == (lhs: DoubleEvent, rhs: DoubleEvent) -> Bool { - return deepEqualsEventChannelTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsEventChannelTests(lhs.value, rhs.value) } + func hash(into hasher: inout Hasher) { - deepHashEventChannelTests(value: toList(), hasher: &hasher) + hasher.combine("DoubleEvent") + deepHashEventChannelTests(value: value, hasher: &hasher) } } @@ -455,10 +587,15 @@ struct ObjectsEvent: PlatformEvent { ] } static func == (lhs: ObjectsEvent, rhs: ObjectsEvent) -> Bool { - return deepEqualsEventChannelTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsEventChannelTests(lhs.value, rhs.value) } + func hash(into hasher: inout Hasher) { - deepHashEventChannelTests(value: toList(), hasher: &hasher) + hasher.combine("ObjectsEvent") + deepHashEventChannelTests(value: value, hasher: &hasher) } } @@ -480,10 +617,15 @@ struct EnumEvent: PlatformEvent { ] } static func == (lhs: EnumEvent, rhs: EnumEvent) -> Bool { - return deepEqualsEventChannelTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsEventChannelTests(lhs.value, rhs.value) } + func hash(into hasher: inout Hasher) { - deepHashEventChannelTests(value: toList(), hasher: &hasher) + hasher.combine("EnumEvent") + deepHashEventChannelTests(value: value, hasher: &hasher) } } @@ -505,10 +647,15 @@ struct ClassEvent: PlatformEvent { ] } static func == (lhs: ClassEvent, rhs: ClassEvent) -> Bool { - return deepEqualsEventChannelTests(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsEventChannelTests(lhs.value, rhs.value) } + func hash(into hasher: inout Hasher) { - deepHashEventChannelTests(value: toList(), hasher: &hasher) + hasher.combine("ClassEvent") + deepHashEventChannelTests(value: value, hasher: &hasher) } } diff --git a/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/ProxyApiTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/ProxyApiTests.gen.swift index 3e392185d448..5eb4b81803ad 100644 --- a/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/ProxyApiTests.gen.swift +++ b/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/ProxyApiTests.gen.swift @@ -54,7 +54,7 @@ private func wrapError(_ error: Any) -> [Any?] { } return [ "\(error)", - "\(type(of: error))", + "\(Swift.type(of: error))", "Stacktrace: \(Thread.callStackSymbols)", ] } diff --git a/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/TestPlugin.swift b/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/TestPlugin.swift index fec488571752..89d25d32f58e 100644 --- a/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/TestPlugin.swift +++ b/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/TestPlugin.swift @@ -70,6 +70,22 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { func echo(_ everything: AllNullableTypes?) -> AllNullableTypes? { return everything } + + func areAllNullableTypesEqual(a: AllNullableTypes, b: AllNullableTypes) -> Bool { + return a == b + } + + func getAllNullableTypesHash(value: AllNullableTypes) -> Int64 { + var hasher = Hasher() + value.hash(into: &hasher) + return Int64(hasher.finalize()) + } + + func getAllNullableTypesWithoutRecursionHash(value: AllNullableTypesWithoutRecursion) -> Int64 { + var hasher = Hasher() + value.hash(into: &hasher) + return Int64(hasher.finalize()) + } func echo(_ everything: AllNullableTypesWithoutRecursion?) throws -> AllNullableTypesWithoutRecursion? { diff --git a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AllDatatypesTests.swift b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AllDatatypesTests.swift index bd9ab4ae67e2..bcbc0c8dd98c 100644 --- a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AllDatatypesTests.swift +++ b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AllDatatypesTests.swift @@ -187,4 +187,90 @@ struct AllDatatypesTests { withMapInList == withMatchingMapInList, "Instances with equivalent nested maps in lists should be equal") } + + @Test + func equalityWithNaN() throws { + let list = [Double.nan] + let map: [Int64: Double?] = [1: Double.nan] + let a = AllNullableTypes( + aNullableDouble: Double.nan, + doubleList: list, + recursiveClassList: [AllNullableTypes(aNullableDouble: Double.nan)], + map: map + ) + let b = AllNullableTypes( + aNullableDouble: Double.nan, + doubleList: list, + recursiveClassList: [AllNullableTypes(aNullableDouble: Double.nan)], + map: map + ) + #expect(a == b) + } + + @Test + func hashWithNaN() throws { + let a = AllNullableTypes(aNullableDouble: Double.nan) + let b = AllNullableTypes(aNullableDouble: Double.nan) + + var hasherA = Hasher() + a.hash(into: &hasherA) + let hashA = hasherA.finalize() + + var hasherB = Hasher() + b.hash(into: &hasherB) + let hashB = hasherB.finalize() + + #expect(hashA == hashB) + } + + @Test + func structEquality() { + let a = AllNullableTypesWithoutRecursion(aNullableInt: 1) + let b = AllNullableTypesWithoutRecursion(aNullableInt: 1) + let c = AllNullableTypesWithoutRecursion(aNullableInt: 2) + #expect(a == b) + #expect(a != c) + } + + @Test + func crossTypeEquality() { + let a = AllNullableTypes(aNullableInt: 1) + let b = AllNullableTypesWithoutRecursion(aNullableInt: 1) + // They are different types, so they shouldn't be equal even if we cast to Any + let anyA: Any = a + let anyB: Any = b + #expect(!(anyA as? AllNullableTypesWithoutRecursion == b)) + #expect(!(anyB as? AllNullableTypes == a)) + } + + @Test + func typedDataEquality() { + let data1 = "1234".data(using: .utf8)! + let data2 = "1234".data(using: .utf8)! + // Ensure they are different instances in memory if possible, + // though Data in Swift is a value type. + // FlutterStandardTypedData is a class. + let a = AllNullableTypes(aNullableByteArray: FlutterStandardTypedData(bytes: data1)) + let c = a + c.aNullableByteArray = FlutterStandardTypedData(bytes: data2) + + #expect(a == c) + } + + @Test + func signedZeroEquality() { + let a = AllNullableTypes(aNullableDouble: 0.0) + let b = AllNullableTypes(aNullableDouble: -0.0) + #expect(a == b) + + var hasherA = Hasher() + a.hash(into: &hasherA) + let hashA = hasherA.finalize() + + var hasherB = Hasher() + b.hash(into: &hasherB) + let hashB = hasherB.finalize() + + #expect(hashA == hashB) + } } diff --git a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/MultipleArityTests.swift b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/MultipleArityTests.swift index dec835076052..7a87a0052231 100644 --- a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/MultipleArityTests.swift +++ b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/MultipleArityTests.swift @@ -15,7 +15,7 @@ class MockMultipleArityHostApi: MultipleArityHostApi { @MainActor struct MultipleArityTests { - var codec = FlutterStandardMessageCodec.sharedInstance() + let codec = FlutterStandardMessageCodec.sharedInstance() @Test func simpleHost() async throws { diff --git a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/NonNullFieldsTest.swift b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/NonNullFieldsTest.swift index 927117fa0874..bb06e1bbf2b2 100644 --- a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/NonNullFieldsTest.swift +++ b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/NonNullFieldsTest.swift @@ -12,4 +12,15 @@ struct NonNullFieldsTests { let request = NonNullFieldSearchRequest(query: "hello") #expect(request.query == "hello") } + + @Test + func testEquality() { + let request1 = NonNullFieldSearchRequest(query: "hello") + let request2 = NonNullFieldSearchRequest(query: "hello") + let request3 = NonNullFieldSearchRequest(query: "world") + + #expect(request1 == request2) + #expect(request1 != request3) + #expect(request1.hashValue == request2.hashValue) + } } diff --git a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/NullableReturnsTests.swift b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/NullableReturnsTests.swift index 6d12dbae93ca..e2925038f6b9 100644 --- a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/NullableReturnsTests.swift +++ b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/NullableReturnsTests.swift @@ -20,7 +20,7 @@ class MockNullableArgHostApi: NullableArgHostApi { @MainActor struct NullableReturnsTests { - var codec = FlutterStandardMessageCodec.sharedInstance() + let codec = FlutterStandardMessageCodec.sharedInstance() @Test func nullableParameterWithFlutterApi() async throws { diff --git a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/PrimitiveTests.swift b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/PrimitiveTests.swift index 62b300b9ab5b..0a3228e86eaf 100644 --- a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/PrimitiveTests.swift +++ b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/PrimitiveTests.swift @@ -21,7 +21,7 @@ class MockPrimitiveHostApi: PrimitiveHostApi { @MainActor struct PrimitiveTests { - var codec = FlutterStandardMessageCodec.sharedInstance() + let codec = FlutterStandardMessageCodec.sharedInstance() @Test func intPrimitiveHost() async throws { diff --git a/packages/pigeon/platform_tests/test_plugin/linux/CMakeLists.txt b/packages/pigeon/platform_tests/test_plugin/linux/CMakeLists.txt index 3d2845f8d3e4..c2cdee101723 100644 --- a/packages/pigeon/platform_tests/test_plugin/linux/CMakeLists.txt +++ b/packages/pigeon/platform_tests/test_plugin/linux/CMakeLists.txt @@ -100,6 +100,7 @@ add_executable(${TEST_RUNNER} test/nullable_returns_test.cc test/null_fields_test.cc test/primitive_test.cc + test/equality_test.cc # Test utilities. test/utils/fake_host_messenger.cc test/utils/fake_host_messenger.h diff --git a/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.cc b/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.cc index ae3763bf5e0e..2eb72f58e03b 100644 --- a/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.cc +++ b/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.cc @@ -7,6 +7,186 @@ #include "core_tests.gen.h" +#include + +#include +static guint G_GNUC_UNUSED flpigeon_hash_double(double v) { + if (std::isnan(v)) return (guint)0x7FF80000; + if (v == 0.0) v = 0.0; + union { + double d; + uint64_t u; + } u; + u.d = v; + return (guint)(u.u ^ (u.u >> 32)); +} +static gboolean G_GNUC_UNUSED flpigeon_equals_double(double a, double b) { + return (a == b) || (std::isnan(a) && std::isnan(b)); +} +static gboolean G_GNUC_UNUSED flpigeon_deep_equals(FlValue* a, FlValue* b) { + if (a == b) { + return TRUE; + } + if (a == nullptr || b == nullptr) { + return FALSE; + } + if (fl_value_get_type(a) != fl_value_get_type(b)) { + return FALSE; + } + switch (fl_value_get_type(a)) { + case FL_VALUE_TYPE_NULL: + return TRUE; + case FL_VALUE_TYPE_BOOL: + return fl_value_get_bool(a) == fl_value_get_bool(b); + case FL_VALUE_TYPE_INT: + return fl_value_get_int(a) == fl_value_get_int(b); + case FL_VALUE_TYPE_FLOAT: { + return flpigeon_equals_double(fl_value_get_float(a), + fl_value_get_float(b)); + } + case FL_VALUE_TYPE_STRING: + return g_strcmp0(fl_value_get_string(a), fl_value_get_string(b)) == 0; + case FL_VALUE_TYPE_UINT8_LIST: + return fl_value_get_length(a) == fl_value_get_length(b) && + memcmp(fl_value_get_uint8_list(a), fl_value_get_uint8_list(b), + fl_value_get_length(a)) == 0; + case FL_VALUE_TYPE_INT32_LIST: + return fl_value_get_length(a) == fl_value_get_length(b) && + memcmp(fl_value_get_int32_list(a), fl_value_get_int32_list(b), + fl_value_get_length(a) * sizeof(int32_t)) == 0; + case FL_VALUE_TYPE_INT64_LIST: + return fl_value_get_length(a) == fl_value_get_length(b) && + memcmp(fl_value_get_int64_list(a), fl_value_get_int64_list(b), + fl_value_get_length(a) * sizeof(int64_t)) == 0; + case FL_VALUE_TYPE_FLOAT_LIST: { + size_t len = fl_value_get_length(a); + if (len != fl_value_get_length(b)) { + return FALSE; + } + const double* a_data = fl_value_get_float_list(a); + const double* b_data = fl_value_get_float_list(b); + for (size_t i = 0; i < len; i++) { + if (!flpigeon_equals_double(a_data[i], b_data[i])) { + return FALSE; + } + } + return TRUE; + } + case FL_VALUE_TYPE_LIST: { + size_t len = fl_value_get_length(a); + if (len != fl_value_get_length(b)) { + return FALSE; + } + for (size_t i = 0; i < len; i++) { + if (!flpigeon_deep_equals(fl_value_get_list_value(a, i), + fl_value_get_list_value(b, i))) { + return FALSE; + } + } + return TRUE; + } + case FL_VALUE_TYPE_MAP: { + size_t len = fl_value_get_length(a); + if (len != fl_value_get_length(b)) { + return FALSE; + } + for (size_t i = 0; i < len; i++) { + FlValue* key = fl_value_get_map_key(a, i); + FlValue* val = fl_value_get_map_value(a, i); + gboolean found = FALSE; + for (size_t j = 0; j < len; j++) { + FlValue* b_key = fl_value_get_map_key(b, j); + if (flpigeon_deep_equals(key, b_key)) { + FlValue* b_val = fl_value_get_map_value(b, j); + if (flpigeon_deep_equals(val, b_val)) { + found = TRUE; + break; + } else { + return FALSE; + } + } + } + if (!found) { + return FALSE; + } + } + return TRUE; + } + default: + return FALSE; + } + return FALSE; +} +static guint G_GNUC_UNUSED flpigeon_deep_hash(FlValue* value) { + if (value == nullptr) return 0; + switch (fl_value_get_type(value)) { + case FL_VALUE_TYPE_NULL: + return 0; + case FL_VALUE_TYPE_BOOL: + return fl_value_get_bool(value) ? 1231 : 1237; + case FL_VALUE_TYPE_INT: { + int64_t v = fl_value_get_int(value); + return (guint)(v ^ (v >> 32)); + } + case FL_VALUE_TYPE_FLOAT: + return flpigeon_hash_double(fl_value_get_float(value)); + case FL_VALUE_TYPE_STRING: + return g_str_hash(fl_value_get_string(value)); + case FL_VALUE_TYPE_UINT8_LIST: { + guint result = 1; + size_t len = fl_value_get_length(value); + const uint8_t* data = fl_value_get_uint8_list(value); + for (size_t i = 0; i < len; i++) result = result * 31 + data[i]; + return result; + } + case FL_VALUE_TYPE_INT32_LIST: { + guint result = 1; + size_t len = fl_value_get_length(value); + const int32_t* data = fl_value_get_int32_list(value); + for (size_t i = 0; i < len; i++) result = result * 31 + (guint)data[i]; + return result; + } + case FL_VALUE_TYPE_INT64_LIST: { + guint result = 1; + size_t len = fl_value_get_length(value); + const int64_t* data = fl_value_get_int64_list(value); + for (size_t i = 0; i < len; i++) + result = result * 31 + (guint)(data[i] ^ (data[i] >> 32)); + return result; + } + case FL_VALUE_TYPE_FLOAT_LIST: { + guint result = 1; + size_t len = fl_value_get_length(value); + const double* data = fl_value_get_float_list(value); + for (size_t i = 0; i < len; i++) { + result = result * 31 + flpigeon_hash_double(data[i]); + } + return result; + } + case FL_VALUE_TYPE_LIST: { + guint result = 1; + size_t len = fl_value_get_length(value); + for (size_t i = 0; i < len; i++) { + result = + result * 31 + flpigeon_deep_hash(fl_value_get_list_value(value, i)); + } + return result; + } + case FL_VALUE_TYPE_MAP: { + guint result = 0; + size_t len = fl_value_get_length(value); + for (size_t i = 0; i < len; i++) { + result += (flpigeon_deep_hash(fl_value_get_map_key(value, i)) ^ + flpigeon_deep_hash(fl_value_get_map_value(value, i))); + } + return result; + } + default: + return (guint)fl_value_get_type(value); + } + return 0; +} + struct _CoreTestsPigeonTestUnusedClass { GObject parent_instance; @@ -69,6 +249,28 @@ core_tests_pigeon_test_unused_class_new_from_list(FlValue* values) { return core_tests_pigeon_test_unused_class_new(a_field); } +gboolean core_tests_pigeon_test_unused_class_equals( + CoreTestsPigeonTestUnusedClass* a, CoreTestsPigeonTestUnusedClass* b) { + if (a == b) { + return TRUE; + } + if (a == nullptr || b == nullptr) { + return FALSE; + } + if (!flpigeon_deep_equals(a->a_field, b->a_field)) { + return FALSE; + } + return TRUE; +} + +guint core_tests_pigeon_test_unused_class_hash( + CoreTestsPigeonTestUnusedClass* self) { + g_return_val_if_fail(CORE_TESTS_PIGEON_TEST_IS_UNUSED_CLASS(self), 0); + guint result = 0; + result = result * 31 + flpigeon_deep_hash(self->a_field); + return result; +} + struct _CoreTestsPigeonTestAllTypes { GObject parent_instance; @@ -497,6 +699,205 @@ core_tests_pigeon_test_all_types_new_from_list(FlValue* values) { object_map, list_map, map_map); } +gboolean core_tests_pigeon_test_all_types_equals( + CoreTestsPigeonTestAllTypes* a, CoreTestsPigeonTestAllTypes* b) { + if (a == b) { + return TRUE; + } + if (a == nullptr || b == nullptr) { + return FALSE; + } + if (a->a_bool != b->a_bool) { + return FALSE; + } + if (a->an_int != b->an_int) { + return FALSE; + } + if (a->an_int64 != b->an_int64) { + return FALSE; + } + if (!flpigeon_equals_double(a->a_double, b->a_double)) { + return FALSE; + } + if (a->a_byte_array != b->a_byte_array) { + if (a->a_byte_array == nullptr || b->a_byte_array == nullptr) { + return FALSE; + } + if (a->a_byte_array_length != b->a_byte_array_length) { + return FALSE; + } + if (memcmp(a->a_byte_array, b->a_byte_array, + a->a_byte_array_length * sizeof(uint8_t)) != 0) { + return FALSE; + } + } + if (a->a4_byte_array != b->a4_byte_array) { + if (a->a4_byte_array == nullptr || b->a4_byte_array == nullptr) { + return FALSE; + } + if (a->a4_byte_array_length != b->a4_byte_array_length) { + return FALSE; + } + if (memcmp(a->a4_byte_array, b->a4_byte_array, + a->a4_byte_array_length * sizeof(int32_t)) != 0) { + return FALSE; + } + } + if (a->a8_byte_array != b->a8_byte_array) { + if (a->a8_byte_array == nullptr || b->a8_byte_array == nullptr) { + return FALSE; + } + if (a->a8_byte_array_length != b->a8_byte_array_length) { + return FALSE; + } + if (memcmp(a->a8_byte_array, b->a8_byte_array, + a->a8_byte_array_length * sizeof(int64_t)) != 0) { + return FALSE; + } + } + if (a->a_float_array != b->a_float_array) { + if (a->a_float_array == nullptr || b->a_float_array == nullptr) { + return FALSE; + } + if (a->a_float_array_length != b->a_float_array_length) { + return FALSE; + } + for (size_t i = 0; i < a->a_float_array_length; i++) { + if (!flpigeon_equals_double(a->a_float_array[i], b->a_float_array[i])) { + return FALSE; + } + } + } + if (a->an_enum != b->an_enum) { + return FALSE; + } + if (a->another_enum != b->another_enum) { + return FALSE; + } + if (g_strcmp0(a->a_string, b->a_string) != 0) { + return FALSE; + } + if (!flpigeon_deep_equals(a->an_object, b->an_object)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->list, b->list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->string_list, b->string_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->int_list, b->int_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->double_list, b->double_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->bool_list, b->bool_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->enum_list, b->enum_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->object_list, b->object_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->list_list, b->list_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->map_list, b->map_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->map, b->map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->string_map, b->string_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->int_map, b->int_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->enum_map, b->enum_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->object_map, b->object_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->list_map, b->list_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->map_map, b->map_map)) { + return FALSE; + } + return TRUE; +} + +guint core_tests_pigeon_test_all_types_hash(CoreTestsPigeonTestAllTypes* self) { + g_return_val_if_fail(CORE_TESTS_PIGEON_TEST_IS_ALL_TYPES(self), 0); + guint result = 0; + result = result * 31 + (guint)self->a_bool; + result = result * 31 + (guint)self->an_int; + result = result * 31 + (guint)self->an_int64; + result = result * 31 + flpigeon_hash_double(self->a_double); + { + size_t len = self->a_byte_array_length; + const uint8_t* data = self->a_byte_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + (guint)data[i]; + } + } + } + { + size_t len = self->a4_byte_array_length; + const int32_t* data = self->a4_byte_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + (guint)data[i]; + } + } + } + { + size_t len = self->a8_byte_array_length; + const int64_t* data = self->a8_byte_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + (guint)(data[i] ^ (data[i] >> 32)); + } + } + } + { + size_t len = self->a_float_array_length; + const double* data = self->a_float_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + flpigeon_hash_double(data[i]); + } + } + } + result = result * 31 + (guint)self->an_enum; + result = result * 31 + (guint)self->another_enum; + result = result * 31 + + (self->a_string != nullptr ? g_str_hash(self->a_string) : 0); + result = result * 31 + flpigeon_deep_hash(self->an_object); + result = result * 31 + flpigeon_deep_hash(self->list); + result = result * 31 + flpigeon_deep_hash(self->string_list); + result = result * 31 + flpigeon_deep_hash(self->int_list); + result = result * 31 + flpigeon_deep_hash(self->double_list); + result = result * 31 + flpigeon_deep_hash(self->bool_list); + result = result * 31 + flpigeon_deep_hash(self->enum_list); + result = result * 31 + flpigeon_deep_hash(self->object_list); + result = result * 31 + flpigeon_deep_hash(self->list_list); + result = result * 31 + flpigeon_deep_hash(self->map_list); + result = result * 31 + flpigeon_deep_hash(self->map); + result = result * 31 + flpigeon_deep_hash(self->string_map); + result = result * 31 + flpigeon_deep_hash(self->int_map); + result = result * 31 + flpigeon_deep_hash(self->enum_map); + result = result * 31 + flpigeon_deep_hash(self->object_map); + result = result * 31 + flpigeon_deep_hash(self->list_map); + result = result * 31 + flpigeon_deep_hash(self->map_map); + return result; +} + struct _CoreTestsPigeonTestAllNullableTypes { GObject parent_instance; @@ -1331,6 +1732,263 @@ core_tests_pigeon_test_all_nullable_types_new_from_list(FlValue* values) { recursive_class_map); } +gboolean core_tests_pigeon_test_all_nullable_types_equals( + CoreTestsPigeonTestAllNullableTypes* a, + CoreTestsPigeonTestAllNullableTypes* b) { + if (a == b) { + return TRUE; + } + if (a == nullptr || b == nullptr) { + return FALSE; + } + if ((a->a_nullable_bool == nullptr) != (b->a_nullable_bool == nullptr)) { + return FALSE; + } + if (a->a_nullable_bool != nullptr && + *a->a_nullable_bool != *b->a_nullable_bool) { + return FALSE; + } + if ((a->a_nullable_int == nullptr) != (b->a_nullable_int == nullptr)) { + return FALSE; + } + if (a->a_nullable_int != nullptr && + *a->a_nullable_int != *b->a_nullable_int) { + return FALSE; + } + if ((a->a_nullable_int64 == nullptr) != (b->a_nullable_int64 == nullptr)) { + return FALSE; + } + if (a->a_nullable_int64 != nullptr && + *a->a_nullable_int64 != *b->a_nullable_int64) { + return FALSE; + } + if ((a->a_nullable_double == nullptr) != (b->a_nullable_double == nullptr)) { + return FALSE; + } + if (a->a_nullable_double != nullptr && + !flpigeon_equals_double(*a->a_nullable_double, *b->a_nullable_double)) { + return FALSE; + } + if (a->a_nullable_byte_array != b->a_nullable_byte_array) { + if (a->a_nullable_byte_array == nullptr || + b->a_nullable_byte_array == nullptr) { + return FALSE; + } + if (a->a_nullable_byte_array_length != b->a_nullable_byte_array_length) { + return FALSE; + } + if (memcmp(a->a_nullable_byte_array, b->a_nullable_byte_array, + a->a_nullable_byte_array_length * sizeof(uint8_t)) != 0) { + return FALSE; + } + } + if (a->a_nullable4_byte_array != b->a_nullable4_byte_array) { + if (a->a_nullable4_byte_array == nullptr || + b->a_nullable4_byte_array == nullptr) { + return FALSE; + } + if (a->a_nullable4_byte_array_length != b->a_nullable4_byte_array_length) { + return FALSE; + } + if (memcmp(a->a_nullable4_byte_array, b->a_nullable4_byte_array, + a->a_nullable4_byte_array_length * sizeof(int32_t)) != 0) { + return FALSE; + } + } + if (a->a_nullable8_byte_array != b->a_nullable8_byte_array) { + if (a->a_nullable8_byte_array == nullptr || + b->a_nullable8_byte_array == nullptr) { + return FALSE; + } + if (a->a_nullable8_byte_array_length != b->a_nullable8_byte_array_length) { + return FALSE; + } + if (memcmp(a->a_nullable8_byte_array, b->a_nullable8_byte_array, + a->a_nullable8_byte_array_length * sizeof(int64_t)) != 0) { + return FALSE; + } + } + if (a->a_nullable_float_array != b->a_nullable_float_array) { + if (a->a_nullable_float_array == nullptr || + b->a_nullable_float_array == nullptr) { + return FALSE; + } + if (a->a_nullable_float_array_length != b->a_nullable_float_array_length) { + return FALSE; + } + for (size_t i = 0; i < a->a_nullable_float_array_length; i++) { + if (!flpigeon_equals_double(a->a_nullable_float_array[i], + b->a_nullable_float_array[i])) { + return FALSE; + } + } + } + if ((a->a_nullable_enum == nullptr) != (b->a_nullable_enum == nullptr)) { + return FALSE; + } + if (a->a_nullable_enum != nullptr && + *a->a_nullable_enum != *b->a_nullable_enum) { + return FALSE; + } + if ((a->another_nullable_enum == nullptr) != + (b->another_nullable_enum == nullptr)) { + return FALSE; + } + if (a->another_nullable_enum != nullptr && + *a->another_nullable_enum != *b->another_nullable_enum) { + return FALSE; + } + if (g_strcmp0(a->a_nullable_string, b->a_nullable_string) != 0) { + return FALSE; + } + if (!flpigeon_deep_equals(a->a_nullable_object, b->a_nullable_object)) { + return FALSE; + } + if (!core_tests_pigeon_test_all_nullable_types_equals( + a->all_nullable_types, b->all_nullable_types)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->list, b->list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->string_list, b->string_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->int_list, b->int_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->double_list, b->double_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->bool_list, b->bool_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->enum_list, b->enum_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->object_list, b->object_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->list_list, b->list_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->map_list, b->map_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->recursive_class_list, b->recursive_class_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->map, b->map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->string_map, b->string_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->int_map, b->int_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->enum_map, b->enum_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->object_map, b->object_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->list_map, b->list_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->map_map, b->map_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->recursive_class_map, b->recursive_class_map)) { + return FALSE; + } + return TRUE; +} + +guint core_tests_pigeon_test_all_nullable_types_hash( + CoreTestsPigeonTestAllNullableTypes* self) { + g_return_val_if_fail(CORE_TESTS_PIGEON_TEST_IS_ALL_NULLABLE_TYPES(self), 0); + guint result = 0; + result = + result * 31 + + (self->a_nullable_bool != nullptr ? (guint)*self->a_nullable_bool : 0); + result = result * 31 + + (self->a_nullable_int != nullptr ? (guint)*self->a_nullable_int : 0); + result = + result * 31 + + (self->a_nullable_int64 != nullptr ? (guint)*self->a_nullable_int64 : 0); + result = result * 31 + (self->a_nullable_double != nullptr + ? flpigeon_hash_double(*self->a_nullable_double) + : 0); + { + size_t len = self->a_nullable_byte_array_length; + const uint8_t* data = self->a_nullable_byte_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + (guint)data[i]; + } + } + } + { + size_t len = self->a_nullable4_byte_array_length; + const int32_t* data = self->a_nullable4_byte_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + (guint)data[i]; + } + } + } + { + size_t len = self->a_nullable8_byte_array_length; + const int64_t* data = self->a_nullable8_byte_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + (guint)(data[i] ^ (data[i] >> 32)); + } + } + } + { + size_t len = self->a_nullable_float_array_length; + const double* data = self->a_nullable_float_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + flpigeon_hash_double(data[i]); + } + } + } + result = + result * 31 + + (self->a_nullable_enum != nullptr ? (guint)*self->a_nullable_enum : 0); + result = result * 31 + (self->another_nullable_enum != nullptr + ? (guint)*self->another_nullable_enum + : 0); + result = result * 31 + (self->a_nullable_string != nullptr + ? g_str_hash(self->a_nullable_string) + : 0); + result = result * 31 + flpigeon_deep_hash(self->a_nullable_object); + result = result * 31 + core_tests_pigeon_test_all_nullable_types_hash( + self->all_nullable_types); + result = result * 31 + flpigeon_deep_hash(self->list); + result = result * 31 + flpigeon_deep_hash(self->string_list); + result = result * 31 + flpigeon_deep_hash(self->int_list); + result = result * 31 + flpigeon_deep_hash(self->double_list); + result = result * 31 + flpigeon_deep_hash(self->bool_list); + result = result * 31 + flpigeon_deep_hash(self->enum_list); + result = result * 31 + flpigeon_deep_hash(self->object_list); + result = result * 31 + flpigeon_deep_hash(self->list_list); + result = result * 31 + flpigeon_deep_hash(self->map_list); + result = result * 31 + flpigeon_deep_hash(self->recursive_class_list); + result = result * 31 + flpigeon_deep_hash(self->map); + result = result * 31 + flpigeon_deep_hash(self->string_map); + result = result * 31 + flpigeon_deep_hash(self->int_map); + result = result * 31 + flpigeon_deep_hash(self->enum_map); + result = result * 31 + flpigeon_deep_hash(self->object_map); + result = result * 31 + flpigeon_deep_hash(self->list_map); + result = result * 31 + flpigeon_deep_hash(self->map_map); + result = result * 31 + flpigeon_deep_hash(self->recursive_class_map); + return result; +} + struct _CoreTestsPigeonTestAllNullableTypesWithoutRecursion { GObject parent_instance; @@ -2145,6 +2803,250 @@ core_tests_pigeon_test_all_nullable_types_without_recursion_new_from_list( list_map, map_map); } +gboolean core_tests_pigeon_test_all_nullable_types_without_recursion_equals( + CoreTestsPigeonTestAllNullableTypesWithoutRecursion* a, + CoreTestsPigeonTestAllNullableTypesWithoutRecursion* b) { + if (a == b) { + return TRUE; + } + if (a == nullptr || b == nullptr) { + return FALSE; + } + if ((a->a_nullable_bool == nullptr) != (b->a_nullable_bool == nullptr)) { + return FALSE; + } + if (a->a_nullable_bool != nullptr && + *a->a_nullable_bool != *b->a_nullable_bool) { + return FALSE; + } + if ((a->a_nullable_int == nullptr) != (b->a_nullable_int == nullptr)) { + return FALSE; + } + if (a->a_nullable_int != nullptr && + *a->a_nullable_int != *b->a_nullable_int) { + return FALSE; + } + if ((a->a_nullable_int64 == nullptr) != (b->a_nullable_int64 == nullptr)) { + return FALSE; + } + if (a->a_nullable_int64 != nullptr && + *a->a_nullable_int64 != *b->a_nullable_int64) { + return FALSE; + } + if ((a->a_nullable_double == nullptr) != (b->a_nullable_double == nullptr)) { + return FALSE; + } + if (a->a_nullable_double != nullptr && + !flpigeon_equals_double(*a->a_nullable_double, *b->a_nullable_double)) { + return FALSE; + } + if (a->a_nullable_byte_array != b->a_nullable_byte_array) { + if (a->a_nullable_byte_array == nullptr || + b->a_nullable_byte_array == nullptr) { + return FALSE; + } + if (a->a_nullable_byte_array_length != b->a_nullable_byte_array_length) { + return FALSE; + } + if (memcmp(a->a_nullable_byte_array, b->a_nullable_byte_array, + a->a_nullable_byte_array_length * sizeof(uint8_t)) != 0) { + return FALSE; + } + } + if (a->a_nullable4_byte_array != b->a_nullable4_byte_array) { + if (a->a_nullable4_byte_array == nullptr || + b->a_nullable4_byte_array == nullptr) { + return FALSE; + } + if (a->a_nullable4_byte_array_length != b->a_nullable4_byte_array_length) { + return FALSE; + } + if (memcmp(a->a_nullable4_byte_array, b->a_nullable4_byte_array, + a->a_nullable4_byte_array_length * sizeof(int32_t)) != 0) { + return FALSE; + } + } + if (a->a_nullable8_byte_array != b->a_nullable8_byte_array) { + if (a->a_nullable8_byte_array == nullptr || + b->a_nullable8_byte_array == nullptr) { + return FALSE; + } + if (a->a_nullable8_byte_array_length != b->a_nullable8_byte_array_length) { + return FALSE; + } + if (memcmp(a->a_nullable8_byte_array, b->a_nullable8_byte_array, + a->a_nullable8_byte_array_length * sizeof(int64_t)) != 0) { + return FALSE; + } + } + if (a->a_nullable_float_array != b->a_nullable_float_array) { + if (a->a_nullable_float_array == nullptr || + b->a_nullable_float_array == nullptr) { + return FALSE; + } + if (a->a_nullable_float_array_length != b->a_nullable_float_array_length) { + return FALSE; + } + for (size_t i = 0; i < a->a_nullable_float_array_length; i++) { + if (!flpigeon_equals_double(a->a_nullable_float_array[i], + b->a_nullable_float_array[i])) { + return FALSE; + } + } + } + if ((a->a_nullable_enum == nullptr) != (b->a_nullable_enum == nullptr)) { + return FALSE; + } + if (a->a_nullable_enum != nullptr && + *a->a_nullable_enum != *b->a_nullable_enum) { + return FALSE; + } + if ((a->another_nullable_enum == nullptr) != + (b->another_nullable_enum == nullptr)) { + return FALSE; + } + if (a->another_nullable_enum != nullptr && + *a->another_nullable_enum != *b->another_nullable_enum) { + return FALSE; + } + if (g_strcmp0(a->a_nullable_string, b->a_nullable_string) != 0) { + return FALSE; + } + if (!flpigeon_deep_equals(a->a_nullable_object, b->a_nullable_object)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->list, b->list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->string_list, b->string_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->int_list, b->int_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->double_list, b->double_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->bool_list, b->bool_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->enum_list, b->enum_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->object_list, b->object_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->list_list, b->list_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->map_list, b->map_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->map, b->map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->string_map, b->string_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->int_map, b->int_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->enum_map, b->enum_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->object_map, b->object_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->list_map, b->list_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->map_map, b->map_map)) { + return FALSE; + } + return TRUE; +} + +guint core_tests_pigeon_test_all_nullable_types_without_recursion_hash( + CoreTestsPigeonTestAllNullableTypesWithoutRecursion* self) { + g_return_val_if_fail( + CORE_TESTS_PIGEON_TEST_IS_ALL_NULLABLE_TYPES_WITHOUT_RECURSION(self), 0); + guint result = 0; + result = + result * 31 + + (self->a_nullable_bool != nullptr ? (guint)*self->a_nullable_bool : 0); + result = result * 31 + + (self->a_nullable_int != nullptr ? (guint)*self->a_nullable_int : 0); + result = + result * 31 + + (self->a_nullable_int64 != nullptr ? (guint)*self->a_nullable_int64 : 0); + result = result * 31 + (self->a_nullable_double != nullptr + ? flpigeon_hash_double(*self->a_nullable_double) + : 0); + { + size_t len = self->a_nullable_byte_array_length; + const uint8_t* data = self->a_nullable_byte_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + (guint)data[i]; + } + } + } + { + size_t len = self->a_nullable4_byte_array_length; + const int32_t* data = self->a_nullable4_byte_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + (guint)data[i]; + } + } + } + { + size_t len = self->a_nullable8_byte_array_length; + const int64_t* data = self->a_nullable8_byte_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + (guint)(data[i] ^ (data[i] >> 32)); + } + } + } + { + size_t len = self->a_nullable_float_array_length; + const double* data = self->a_nullable_float_array; + if (data != nullptr) { + for (size_t i = 0; i < len; i++) { + result = result * 31 + flpigeon_hash_double(data[i]); + } + } + } + result = + result * 31 + + (self->a_nullable_enum != nullptr ? (guint)*self->a_nullable_enum : 0); + result = result * 31 + (self->another_nullable_enum != nullptr + ? (guint)*self->another_nullable_enum + : 0); + result = result * 31 + (self->a_nullable_string != nullptr + ? g_str_hash(self->a_nullable_string) + : 0); + result = result * 31 + flpigeon_deep_hash(self->a_nullable_object); + result = result * 31 + flpigeon_deep_hash(self->list); + result = result * 31 + flpigeon_deep_hash(self->string_list); + result = result * 31 + flpigeon_deep_hash(self->int_list); + result = result * 31 + flpigeon_deep_hash(self->double_list); + result = result * 31 + flpigeon_deep_hash(self->bool_list); + result = result * 31 + flpigeon_deep_hash(self->enum_list); + result = result * 31 + flpigeon_deep_hash(self->object_list); + result = result * 31 + flpigeon_deep_hash(self->list_list); + result = result * 31 + flpigeon_deep_hash(self->map_list); + result = result * 31 + flpigeon_deep_hash(self->map); + result = result * 31 + flpigeon_deep_hash(self->string_map); + result = result * 31 + flpigeon_deep_hash(self->int_map); + result = result * 31 + flpigeon_deep_hash(self->enum_map); + result = result * 31 + flpigeon_deep_hash(self->object_map); + result = result * 31 + flpigeon_deep_hash(self->list_map); + result = result * 31 + flpigeon_deep_hash(self->map_map); + return result; +} + struct _CoreTestsPigeonTestAllClassesWrapper { GObject parent_instance; @@ -2347,6 +3249,59 @@ core_tests_pigeon_test_all_classes_wrapper_new_from_list(FlValue* values) { class_list, nullable_class_list, class_map, nullable_class_map); } +gboolean core_tests_pigeon_test_all_classes_wrapper_equals( + CoreTestsPigeonTestAllClassesWrapper* a, + CoreTestsPigeonTestAllClassesWrapper* b) { + if (a == b) { + return TRUE; + } + if (a == nullptr || b == nullptr) { + return FALSE; + } + if (!core_tests_pigeon_test_all_nullable_types_equals( + a->all_nullable_types, b->all_nullable_types)) { + return FALSE; + } + if (!core_tests_pigeon_test_all_nullable_types_without_recursion_equals( + a->all_nullable_types_without_recursion, + b->all_nullable_types_without_recursion)) { + return FALSE; + } + if (!core_tests_pigeon_test_all_types_equals(a->all_types, b->all_types)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->class_list, b->class_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->nullable_class_list, b->nullable_class_list)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->class_map, b->class_map)) { + return FALSE; + } + if (!flpigeon_deep_equals(a->nullable_class_map, b->nullable_class_map)) { + return FALSE; + } + return TRUE; +} + +guint core_tests_pigeon_test_all_classes_wrapper_hash( + CoreTestsPigeonTestAllClassesWrapper* self) { + g_return_val_if_fail(CORE_TESTS_PIGEON_TEST_IS_ALL_CLASSES_WRAPPER(self), 0); + guint result = 0; + result = result * 31 + core_tests_pigeon_test_all_nullable_types_hash( + self->all_nullable_types); + result = result * 31 + + core_tests_pigeon_test_all_nullable_types_without_recursion_hash( + self->all_nullable_types_without_recursion); + result = result * 31 + core_tests_pigeon_test_all_types_hash(self->all_types); + result = result * 31 + flpigeon_deep_hash(self->class_list); + result = result * 31 + flpigeon_deep_hash(self->nullable_class_list); + result = result * 31 + flpigeon_deep_hash(self->class_map); + result = result * 31 + flpigeon_deep_hash(self->nullable_class_map); + return result; +} + struct _CoreTestsPigeonTestTestMessage { GObject parent_instance; @@ -2409,6 +3364,28 @@ core_tests_pigeon_test_test_message_new_from_list(FlValue* values) { return core_tests_pigeon_test_test_message_new(test_list); } +gboolean core_tests_pigeon_test_test_message_equals( + CoreTestsPigeonTestTestMessage* a, CoreTestsPigeonTestTestMessage* b) { + if (a == b) { + return TRUE; + } + if (a == nullptr || b == nullptr) { + return FALSE; + } + if (!flpigeon_deep_equals(a->test_list, b->test_list)) { + return FALSE; + } + return TRUE; +} + +guint core_tests_pigeon_test_test_message_hash( + CoreTestsPigeonTestTestMessage* self) { + g_return_val_if_fail(CORE_TESTS_PIGEON_TEST_IS_TEST_MESSAGE(self), 0); + guint result = 0; + result = result * 31 + flpigeon_deep_hash(self->test_list); + return result; +} + struct _CoreTestsPigeonTestMessageCodec { FlStandardMessageCodec parent_instance; }; @@ -4840,6 +5817,208 @@ core_tests_pigeon_test_host_integration_core_api_echo_required_int_response_new_ return self; } +struct + _CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE( + CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse, + core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response, + G_TYPE_OBJECT) + +static void +core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_dispose( + GObject* object) { + CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_ARE_ALL_NULLABLE_TYPES_EQUAL_RESPONSE( + object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS( + core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_parent_class) + ->dispose(object); +} + +static void +core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_init( + CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse* + self) {} + +static void +core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_class_init( + CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponseClass* + klass) { + G_OBJECT_CLASS(klass)->dispose = + core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_dispose; +} + +CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse* +core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_new( + gboolean return_value) { + CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_ARE_ALL_NULLABLE_TYPES_EQUAL_RESPONSE( + g_object_new( + core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_get_type(), + nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_bool(return_value)); + return self; +} + +CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse* +core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_new_error( + const gchar* code, const gchar* message, FlValue* details) { + CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_ARE_ALL_NULLABLE_TYPES_EQUAL_RESPONSE( + g_object_new( + core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_get_type(), + nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, + fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) + : fl_value_new_null()); + return self; +} + +struct + _CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE( + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse, + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response, + G_TYPE_OBJECT) + +static void +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_dispose( + GObject* object) { + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_GET_ALL_NULLABLE_TYPES_HASH_RESPONSE( + object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS( + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_parent_class) + ->dispose(object); +} + +static void +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_init( + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse* + self) {} + +static void +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_class_init( + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponseClass* + klass) { + G_OBJECT_CLASS(klass)->dispose = + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_dispose; +} + +CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse* +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_new( + int64_t return_value) { + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_GET_ALL_NULLABLE_TYPES_HASH_RESPONSE( + g_object_new( + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_get_type(), + nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_int(return_value)); + return self; +} + +CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse* +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_new_error( + const gchar* code, const gchar* message, FlValue* details) { + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_GET_ALL_NULLABLE_TYPES_HASH_RESPONSE( + g_object_new( + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_get_type(), + nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, + fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) + : fl_value_new_null()); + return self; +} + +struct + _CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE( + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse, + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response, + G_TYPE_OBJECT) + +static void +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_dispose( + GObject* object) { + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse* + self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_GET_ALL_NULLABLE_TYPES_WITHOUT_RECURSION_HASH_RESPONSE( + object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS( + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_parent_class) + ->dispose(object); +} + +static void +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_init( + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse* + self) {} + +static void +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_class_init( + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponseClass* + klass) { + G_OBJECT_CLASS(klass)->dispose = + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_dispose; +} + +CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse* +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_new( + int64_t return_value) { + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse* + self = CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_GET_ALL_NULLABLE_TYPES_WITHOUT_RECURSION_HASH_RESPONSE( + g_object_new( + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_get_type(), + nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_int(return_value)); + return self; +} + +CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse* +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_new_error( + const gchar* code, const gchar* message, FlValue* details) { + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse* + self = CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_GET_ALL_NULLABLE_TYPES_WITHOUT_RECURSION_HASH_RESPONSE( + g_object_new( + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_get_type(), + nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, + fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) + : fl_value_new_null()); + return self; +} + struct _CoreTestsPigeonTestHostIntegrationCoreApiEchoAllNullableTypesResponse { GObject parent_instance; @@ -14726,6 +15905,112 @@ core_tests_pigeon_test_host_integration_core_api_echo_required_int_cb( } } +static void +core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_cb( + FlBasicMessageChannel* channel, FlValue* message_, + FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + CoreTestsPigeonTestHostIntegrationCoreApi* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API(user_data); + + if (self->vtable == nullptr || + self->vtable->are_all_nullable_types_equal == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + CoreTestsPigeonTestAllNullableTypes* a = + CORE_TESTS_PIGEON_TEST_ALL_NULLABLE_TYPES( + fl_value_get_custom_value_object(value0)); + FlValue* value1 = fl_value_get_list_value(message_, 1); + CoreTestsPigeonTestAllNullableTypes* b = + CORE_TESTS_PIGEON_TEST_ALL_NULLABLE_TYPES( + fl_value_get_custom_value_object(value1)); + g_autoptr( + CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse) + response = + self->vtable->are_all_nullable_types_equal(a, b, self->user_data); + if (response == nullptr) { + g_warning("No response returned to %s.%s", "HostIntegrationCoreApi", + "areAllNullableTypesEqual"); + return; + } + + g_autoptr(GError) error = NULL; + if (!fl_basic_message_channel_respond(channel, response_handle, + response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "HostIntegrationCoreApi", + "areAllNullableTypesEqual", error->message); + } +} + +static void +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_cb( + FlBasicMessageChannel* channel, FlValue* message_, + FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + CoreTestsPigeonTestHostIntegrationCoreApi* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API(user_data); + + if (self->vtable == nullptr || + self->vtable->get_all_nullable_types_hash == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + CoreTestsPigeonTestAllNullableTypes* value = + CORE_TESTS_PIGEON_TEST_ALL_NULLABLE_TYPES( + fl_value_get_custom_value_object(value0)); + g_autoptr( + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse) + response = + self->vtable->get_all_nullable_types_hash(value, self->user_data); + if (response == nullptr) { + g_warning("No response returned to %s.%s", "HostIntegrationCoreApi", + "getAllNullableTypesHash"); + return; + } + + g_autoptr(GError) error = NULL; + if (!fl_basic_message_channel_respond(channel, response_handle, + response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "HostIntegrationCoreApi", + "getAllNullableTypesHash", error->message); + } +} + +static void +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_cb( + FlBasicMessageChannel* channel, FlValue* message_, + FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + CoreTestsPigeonTestHostIntegrationCoreApi* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API(user_data); + + if (self->vtable == nullptr || + self->vtable->get_all_nullable_types_without_recursion_hash == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + CoreTestsPigeonTestAllNullableTypesWithoutRecursion* value = + CORE_TESTS_PIGEON_TEST_ALL_NULLABLE_TYPES_WITHOUT_RECURSION( + fl_value_get_custom_value_object(value0)); + g_autoptr( + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse) + response = self->vtable->get_all_nullable_types_without_recursion_hash( + value, self->user_data); + if (response == nullptr) { + g_warning("No response returned to %s.%s", "HostIntegrationCoreApi", + "getAllNullableTypesWithoutRecursionHash"); + return; + } + + g_autoptr(GError) error = NULL; + if (!fl_basic_message_channel_respond(channel, response_handle, + response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "HostIntegrationCoreApi", + "getAllNullableTypesWithoutRecursionHash", error->message); + } +} + static void core_tests_pigeon_test_host_integration_core_api_echo_all_nullable_types_cb( FlBasicMessageChannel* channel, FlValue* message_, @@ -18082,6 +19367,45 @@ void core_tests_pigeon_test_host_integration_core_api_set_method_handlers( echo_required_int_channel, core_tests_pigeon_test_host_integration_core_api_echo_required_int_cb, g_object_ref(api_data), g_object_unref); + g_autofree gchar* are_all_nullable_types_equal_channel_name = g_strdup_printf( + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "areAllNullableTypesEqual%s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) are_all_nullable_types_equal_channel = + fl_basic_message_channel_new(messenger, + are_all_nullable_types_equal_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler( + are_all_nullable_types_equal_channel, + core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_cb, + g_object_ref(api_data), g_object_unref); + g_autofree gchar* get_all_nullable_types_hash_channel_name = g_strdup_printf( + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "getAllNullableTypesHash%s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) get_all_nullable_types_hash_channel = + fl_basic_message_channel_new(messenger, + get_all_nullable_types_hash_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler( + get_all_nullable_types_hash_channel, + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_cb, + g_object_ref(api_data), g_object_unref); + g_autofree gchar* get_all_nullable_types_without_recursion_hash_channel_name = + g_strdup_printf( + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "getAllNullableTypesWithoutRecursionHash%s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) + get_all_nullable_types_without_recursion_hash_channel = + fl_basic_message_channel_new( + messenger, + get_all_nullable_types_without_recursion_hash_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler( + get_all_nullable_types_without_recursion_hash_channel, + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_cb, + g_object_ref(api_data), g_object_unref); g_autofree gchar* echo_all_nullable_types_channel_name = g_strdup_printf( "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." "echoAllNullableTypes%s", @@ -19917,6 +21241,40 @@ void core_tests_pigeon_test_host_integration_core_api_clear_method_handlers( FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler(echo_required_int_channel, nullptr, nullptr, nullptr); + g_autofree gchar* are_all_nullable_types_equal_channel_name = g_strdup_printf( + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "areAllNullableTypesEqual%s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) are_all_nullable_types_equal_channel = + fl_basic_message_channel_new(messenger, + are_all_nullable_types_equal_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler( + are_all_nullable_types_equal_channel, nullptr, nullptr, nullptr); + g_autofree gchar* get_all_nullable_types_hash_channel_name = g_strdup_printf( + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "getAllNullableTypesHash%s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) get_all_nullable_types_hash_channel = + fl_basic_message_channel_new(messenger, + get_all_nullable_types_hash_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler( + get_all_nullable_types_hash_channel, nullptr, nullptr, nullptr); + g_autofree gchar* get_all_nullable_types_without_recursion_hash_channel_name = + g_strdup_printf( + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "getAllNullableTypesWithoutRecursionHash%s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) + get_all_nullable_types_without_recursion_hash_channel = + fl_basic_message_channel_new( + messenger, + get_all_nullable_types_without_recursion_hash_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler( + get_all_nullable_types_without_recursion_hash_channel, nullptr, nullptr, + nullptr); g_autofree gchar* echo_all_nullable_types_channel_name = g_strdup_printf( "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." "echoAllNullableTypes%s", diff --git a/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.h b/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.h index f0f342e75439..322b9bc8a6b5 100644 --- a/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.h +++ b/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.h @@ -69,6 +69,29 @@ CoreTestsPigeonTestUnusedClass* core_tests_pigeon_test_unused_class_new( FlValue* core_tests_pigeon_test_unused_class_get_a_field( CoreTestsPigeonTestUnusedClass* object); +/** + * core_tests_pigeon_test_unused_class_equals: + * @a: a #CoreTestsPigeonTestUnusedClass. + * @b: another #CoreTestsPigeonTestUnusedClass. + * + * Checks if two #CoreTestsPigeonTestUnusedClass objects are equal. + * + * Returns: TRUE if @a and @b are equal. + */ +gboolean core_tests_pigeon_test_unused_class_equals( + CoreTestsPigeonTestUnusedClass* a, CoreTestsPigeonTestUnusedClass* b); + +/** + * core_tests_pigeon_test_unused_class_hash: + * @object: a #CoreTestsPigeonTestUnusedClass. + * + * Calculates a hash code for a #CoreTestsPigeonTestUnusedClass object. + * + * Returns: the hash code. + */ +guint core_tests_pigeon_test_unused_class_hash( + CoreTestsPigeonTestUnusedClass* object); + /** * CoreTestsPigeonTestAllTypes: * @@ -445,6 +468,29 @@ FlValue* core_tests_pigeon_test_all_types_get_list_map( FlValue* core_tests_pigeon_test_all_types_get_map_map( CoreTestsPigeonTestAllTypes* object); +/** + * core_tests_pigeon_test_all_types_equals: + * @a: a #CoreTestsPigeonTestAllTypes. + * @b: another #CoreTestsPigeonTestAllTypes. + * + * Checks if two #CoreTestsPigeonTestAllTypes objects are equal. + * + * Returns: TRUE if @a and @b are equal. + */ +gboolean core_tests_pigeon_test_all_types_equals( + CoreTestsPigeonTestAllTypes* a, CoreTestsPigeonTestAllTypes* b); + +/** + * core_tests_pigeon_test_all_types_hash: + * @object: a #CoreTestsPigeonTestAllTypes. + * + * Calculates a hash code for a #CoreTestsPigeonTestAllTypes object. + * + * Returns: the hash code. + */ +guint core_tests_pigeon_test_all_types_hash( + CoreTestsPigeonTestAllTypes* object); + /** * CoreTestsPigeonTestAllNullableTypes: * @@ -868,6 +914,30 @@ FlValue* core_tests_pigeon_test_all_nullable_types_get_map_map( FlValue* core_tests_pigeon_test_all_nullable_types_get_recursive_class_map( CoreTestsPigeonTestAllNullableTypes* object); +/** + * core_tests_pigeon_test_all_nullable_types_equals: + * @a: a #CoreTestsPigeonTestAllNullableTypes. + * @b: another #CoreTestsPigeonTestAllNullableTypes. + * + * Checks if two #CoreTestsPigeonTestAllNullableTypes objects are equal. + * + * Returns: TRUE if @a and @b are equal. + */ +gboolean core_tests_pigeon_test_all_nullable_types_equals( + CoreTestsPigeonTestAllNullableTypes* a, + CoreTestsPigeonTestAllNullableTypes* b); + +/** + * core_tests_pigeon_test_all_nullable_types_hash: + * @object: a #CoreTestsPigeonTestAllNullableTypes. + * + * Calculates a hash code for a #CoreTestsPigeonTestAllNullableTypes object. + * + * Returns: the hash code. + */ +guint core_tests_pigeon_test_all_nullable_types_hash( + CoreTestsPigeonTestAllNullableTypes* object); + /** * CoreTestsPigeonTestAllNullableTypesWithoutRecursion: * @@ -1279,6 +1349,32 @@ FlValue* core_tests_pigeon_test_all_nullable_types_without_recursion_get_map_map( CoreTestsPigeonTestAllNullableTypesWithoutRecursion* object); +/** + * core_tests_pigeon_test_all_nullable_types_without_recursion_equals: + * @a: a #CoreTestsPigeonTestAllNullableTypesWithoutRecursion. + * @b: another #CoreTestsPigeonTestAllNullableTypesWithoutRecursion. + * + * Checks if two #CoreTestsPigeonTestAllNullableTypesWithoutRecursion objects + * are equal. + * + * Returns: TRUE if @a and @b are equal. + */ +gboolean core_tests_pigeon_test_all_nullable_types_without_recursion_equals( + CoreTestsPigeonTestAllNullableTypesWithoutRecursion* a, + CoreTestsPigeonTestAllNullableTypesWithoutRecursion* b); + +/** + * core_tests_pigeon_test_all_nullable_types_without_recursion_hash: + * @object: a #CoreTestsPigeonTestAllNullableTypesWithoutRecursion. + * + * Calculates a hash code for a + * #CoreTestsPigeonTestAllNullableTypesWithoutRecursion object. + * + * Returns: the hash code. + */ +guint core_tests_pigeon_test_all_nullable_types_without_recursion_hash( + CoreTestsPigeonTestAllNullableTypesWithoutRecursion* object); + /** * CoreTestsPigeonTestAllClassesWrapper: * @@ -1396,6 +1492,30 @@ FlValue* core_tests_pigeon_test_all_classes_wrapper_get_class_map( FlValue* core_tests_pigeon_test_all_classes_wrapper_get_nullable_class_map( CoreTestsPigeonTestAllClassesWrapper* object); +/** + * core_tests_pigeon_test_all_classes_wrapper_equals: + * @a: a #CoreTestsPigeonTestAllClassesWrapper. + * @b: another #CoreTestsPigeonTestAllClassesWrapper. + * + * Checks if two #CoreTestsPigeonTestAllClassesWrapper objects are equal. + * + * Returns: TRUE if @a and @b are equal. + */ +gboolean core_tests_pigeon_test_all_classes_wrapper_equals( + CoreTestsPigeonTestAllClassesWrapper* a, + CoreTestsPigeonTestAllClassesWrapper* b); + +/** + * core_tests_pigeon_test_all_classes_wrapper_hash: + * @object: a #CoreTestsPigeonTestAllClassesWrapper. + * + * Calculates a hash code for a #CoreTestsPigeonTestAllClassesWrapper object. + * + * Returns: the hash code. + */ +guint core_tests_pigeon_test_all_classes_wrapper_hash( + CoreTestsPigeonTestAllClassesWrapper* object); + /** * CoreTestsPigeonTestTestMessage: * @@ -1428,6 +1548,29 @@ CoreTestsPigeonTestTestMessage* core_tests_pigeon_test_test_message_new( FlValue* core_tests_pigeon_test_test_message_get_test_list( CoreTestsPigeonTestTestMessage* object); +/** + * core_tests_pigeon_test_test_message_equals: + * @a: a #CoreTestsPigeonTestTestMessage. + * @b: another #CoreTestsPigeonTestTestMessage. + * + * Checks if two #CoreTestsPigeonTestTestMessage objects are equal. + * + * Returns: TRUE if @a and @b are equal. + */ +gboolean core_tests_pigeon_test_test_message_equals( + CoreTestsPigeonTestTestMessage* a, CoreTestsPigeonTestTestMessage* b); + +/** + * core_tests_pigeon_test_test_message_hash: + * @object: a #CoreTestsPigeonTestTestMessage. + * + * Calculates a hash code for a #CoreTestsPigeonTestTestMessage object. + * + * Returns: the hash code. + */ +guint core_tests_pigeon_test_test_message_hash( + CoreTestsPigeonTestTestMessage* object); + G_DECLARE_FINAL_TYPE(CoreTestsPigeonTestMessageCodec, core_tests_pigeon_test_message_codec, CORE_TESTS_PIGEON_TEST, MESSAGE_CODEC, @@ -2451,6 +2594,110 @@ CoreTestsPigeonTestHostIntegrationCoreApiEchoRequiredIntResponse* core_tests_pigeon_test_host_integration_core_api_echo_required_int_response_new_error( const gchar* code, const gchar* message, FlValue* details); +G_DECLARE_FINAL_TYPE( + CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse, + core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response, + CORE_TESTS_PIGEON_TEST, + HOST_INTEGRATION_CORE_API_ARE_ALL_NULLABLE_TYPES_EQUAL_RESPONSE, GObject) + +/** + * core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_new: + * + * Creates a new response to HostIntegrationCoreApi.areAllNullableTypesEqual. + * + * Returns: a new + * #CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse + */ +CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse* +core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_new( + gboolean return_value); + +/** + * core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_new_error: + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Creates a new error response to + * HostIntegrationCoreApi.areAllNullableTypesEqual. + * + * Returns: a new + * #CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse + */ +CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse* +core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_new_error( + const gchar* code, const gchar* message, FlValue* details); + +G_DECLARE_FINAL_TYPE( + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse, + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response, + CORE_TESTS_PIGEON_TEST, + HOST_INTEGRATION_CORE_API_GET_ALL_NULLABLE_TYPES_HASH_RESPONSE, GObject) + +/** + * core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_new: + * + * Creates a new response to HostIntegrationCoreApi.getAllNullableTypesHash. + * + * Returns: a new + * #CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse + */ +CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse* +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_new( + int64_t return_value); + +/** + * core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_new_error: + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Creates a new error response to + * HostIntegrationCoreApi.getAllNullableTypesHash. + * + * Returns: a new + * #CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse + */ +CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse* +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_new_error( + const gchar* code, const gchar* message, FlValue* details); + +G_DECLARE_FINAL_TYPE( + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse, + core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response, + CORE_TESTS_PIGEON_TEST, + HOST_INTEGRATION_CORE_API_GET_ALL_NULLABLE_TYPES_WITHOUT_RECURSION_HASH_RESPONSE, + GObject) + +/** + * core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_new: + * + * Creates a new response to + * HostIntegrationCoreApi.getAllNullableTypesWithoutRecursionHash. + * + * Returns: a new + * #CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse + */ +CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse* +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_new( + int64_t return_value); + +/** + * core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_new_error: + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Creates a new error response to + * HostIntegrationCoreApi.getAllNullableTypesWithoutRecursionHash. + * + * Returns: a new + * #CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse + */ +CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse* +core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_new_error( + const gchar* code, const gchar* message, FlValue* details); + G_DECLARE_FINAL_TYPE( CoreTestsPigeonTestHostIntegrationCoreApiEchoAllNullableTypesResponse, core_tests_pigeon_test_host_integration_core_api_echo_all_nullable_types_response, @@ -3605,6 +3852,17 @@ typedef struct { *echo_optional_default_double)(double a_double, gpointer user_data); CoreTestsPigeonTestHostIntegrationCoreApiEchoRequiredIntResponse* ( *echo_required_int)(int64_t an_int, gpointer user_data); + CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse* ( + *are_all_nullable_types_equal)(CoreTestsPigeonTestAllNullableTypes* a, + CoreTestsPigeonTestAllNullableTypes* b, + gpointer user_data); + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse* ( + *get_all_nullable_types_hash)(CoreTestsPigeonTestAllNullableTypes* value, + gpointer user_data); + CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse* ( + *get_all_nullable_types_without_recursion_hash)( + CoreTestsPigeonTestAllNullableTypesWithoutRecursion* value, + gpointer user_data); CoreTestsPigeonTestHostIntegrationCoreApiEchoAllNullableTypesResponse* ( *echo_all_nullable_types)(CoreTestsPigeonTestAllNullableTypes* everything, gpointer user_data); diff --git a/packages/pigeon/platform_tests/test_plugin/linux/test/equality_test.cc b/packages/pigeon/platform_tests/test_plugin/linux/test/equality_test.cc new file mode 100644 index 000000000000..ab14ebe7f295 --- /dev/null +++ b/packages/pigeon/platform_tests/test_plugin/linux/test/equality_test.cc @@ -0,0 +1,186 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include + +#include "pigeon/core_tests.gen.h" + +static CoreTestsPigeonTestAllNullableTypes* create_empty_all_nullable_types() { + return core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, nullptr, nullptr, 0, nullptr, 0, nullptr, 0, + nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); +} + +TEST(Equality, AllNullableTypesNaN) { + double nan_val = NAN; + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all1 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, &nan_val, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr); + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all2 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, &nan_val, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr); + + EXPECT_TRUE(core_tests_pigeon_test_all_nullable_types_equals(all1, all2)); + EXPECT_EQ(core_tests_pigeon_test_all_nullable_types_hash(all1), + core_tests_pigeon_test_all_nullable_types_hash(all2)); +} + +TEST(Equality, AllNullableTypesCollectionNaN) { + g_autoptr(FlValue) list1 = fl_value_new_list(); + fl_value_append_take(list1, fl_value_new_float(NAN)); + + g_autoptr(FlValue) list2 = fl_value_new_list(); + fl_value_append_take(list2, fl_value_new_float(NAN)); + + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all1 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, nullptr, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, list1, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr); + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all2 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, nullptr, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, list2, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr); + + EXPECT_TRUE(core_tests_pigeon_test_all_nullable_types_equals(all1, all2)); + EXPECT_EQ(core_tests_pigeon_test_all_nullable_types_hash(all1), + core_tests_pigeon_test_all_nullable_types_hash(all2)); +} + +TEST(Equality, AllNullableTypesRecursive) { + g_autoptr(CoreTestsPigeonTestAllNullableTypes) nested1 = + create_empty_all_nullable_types(); + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all1 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, nullptr, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nested1, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr); + + g_autoptr(CoreTestsPigeonTestAllNullableTypes) nested2 = + create_empty_all_nullable_types(); + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all2 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, nullptr, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nested2, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr); + + EXPECT_TRUE(core_tests_pigeon_test_all_nullable_types_equals(all1, all2)); + EXPECT_EQ(core_tests_pigeon_test_all_nullable_types_hash(all1), + core_tests_pigeon_test_all_nullable_types_hash(all2)); +} + +TEST(Equality, AllTypesNumericLists) { + uint8_t bytes[] = {1, 2, 3}; + int32_t ints32[] = {4, 5}; + double doubles[] = {1.1, 2.2}; + + g_autoptr(CoreTestsPigeonTestAllTypes) all1 = + core_tests_pigeon_test_all_types_new( + TRUE, 1, 2, 3.3, bytes, 3, ints32, 2, nullptr, 0, doubles, 2, + PIGEON_INTEGRATION_TESTS_AN_ENUM_ONE, + PIGEON_INTEGRATION_TESTS_ANOTHER_ENUM_JUST_IN_CASE, "hello", nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr); + + g_autoptr(CoreTestsPigeonTestAllTypes) all2 = + core_tests_pigeon_test_all_types_new( + TRUE, 1, 2, 3.3, bytes, 3, ints32, 2, nullptr, 0, doubles, 2, + PIGEON_INTEGRATION_TESTS_AN_ENUM_ONE, + PIGEON_INTEGRATION_TESTS_ANOTHER_ENUM_JUST_IN_CASE, "hello", nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr); + + EXPECT_TRUE(core_tests_pigeon_test_all_types_equals(all1, all2)); + EXPECT_EQ(core_tests_pigeon_test_all_types_hash(all1), + core_tests_pigeon_test_all_types_hash(all2)); + + // Change one element in a numeric list + doubles[1] = 2.3; + g_autoptr(CoreTestsPigeonTestAllTypes) all3 = + core_tests_pigeon_test_all_types_new( + TRUE, 1, 2, 3.3, bytes, 3, ints32, 2, nullptr, 0, doubles, 2, + PIGEON_INTEGRATION_TESTS_AN_ENUM_ONE, + PIGEON_INTEGRATION_TESTS_ANOTHER_ENUM_JUST_IN_CASE, "hello", nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr); + + EXPECT_FALSE(core_tests_pigeon_test_all_types_equals(all1, all3)); + EXPECT_NE(core_tests_pigeon_test_all_types_hash(all1), + core_tests_pigeon_test_all_types_hash(all3)); +} + +TEST(Equality, SignedZero) { + double p_zero = 0.0; + double n_zero = -0.0; + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all1 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, &p_zero, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr); + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all2 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, &n_zero, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr); + + EXPECT_TRUE(core_tests_pigeon_test_all_nullable_types_equals(all1, all2)); + EXPECT_EQ(core_tests_pigeon_test_all_nullable_types_hash(all1), + core_tests_pigeon_test_all_nullable_types_hash(all2)); +} + +TEST(Equality, SignedZeroMapKey) { + double p_zero = 0.0; + double n_zero = -0.0; + g_autoptr(FlValue) map1 = fl_value_new_map(); + fl_value_set_take(map1, fl_value_new_float(p_zero), fl_value_new_string("a")); + g_autoptr(FlValue) map2 = fl_value_new_map(); + fl_value_set_take(map2, fl_value_new_float(n_zero), fl_value_new_string("a")); + + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all1 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, nullptr, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, map1, nullptr, + nullptr, nullptr); + g_autoptr(CoreTestsPigeonTestAllNullableTypes) all2 = + core_tests_pigeon_test_all_nullable_types_new( + nullptr, nullptr, nullptr, nullptr, nullptr, 0, nullptr, 0, nullptr, + 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, map2, nullptr, + nullptr, nullptr); + + EXPECT_TRUE(core_tests_pigeon_test_all_nullable_types_equals(all1, all2)); + EXPECT_EQ(core_tests_pigeon_test_all_nullable_types_hash(all1), + core_tests_pigeon_test_all_nullable_types_hash(all2)); +} diff --git a/packages/pigeon/platform_tests/test_plugin/linux/test_plugin.cc b/packages/pigeon/platform_tests/test_plugin/linux/test_plugin.cc index 95c7aa410da0..693bb17eefee 100644 --- a/packages/pigeon/platform_tests/test_plugin/linux/test_plugin.cc +++ b/packages/pigeon/platform_tests/test_plugin/linux/test_plugin.cc @@ -253,6 +253,29 @@ echo_all_nullable_types(CoreTestsPigeonTestAllNullableTypes* everything, everything); } +static CoreTestsPigeonTestHostIntegrationCoreApiAreAllNullableTypesEqualResponse* +are_all_nullable_types_equal(CoreTestsPigeonTestAllNullableTypes* a, + CoreTestsPigeonTestAllNullableTypes* b, + gpointer user_data) { + return core_tests_pigeon_test_host_integration_core_api_are_all_nullable_types_equal_response_new( + core_tests_pigeon_test_all_nullable_types_equals(a, b)); +} + +static CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesHashResponse* +get_all_nullable_types_hash(CoreTestsPigeonTestAllNullableTypes* value, + gpointer user_data) { + return core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_hash_response_new( + core_tests_pigeon_test_all_nullable_types_hash(value)); +} + +static CoreTestsPigeonTestHostIntegrationCoreApiGetAllNullableTypesWithoutRecursionHashResponse* +get_all_nullable_types_without_recursion_hash( + CoreTestsPigeonTestAllNullableTypesWithoutRecursion* value, + gpointer user_data) { + return core_tests_pigeon_test_host_integration_core_api_get_all_nullable_types_without_recursion_hash_response_new( + core_tests_pigeon_test_all_nullable_types_without_recursion_hash(value)); +} + static CoreTestsPigeonTestHostIntegrationCoreApiEchoAllNullableTypesWithoutRecursionResponse* echo_all_nullable_types_without_recursion( @@ -3224,6 +3247,10 @@ static CoreTestsPigeonTestHostIntegrationCoreApiVTable host_core_api_vtable = { .echo_named_default_string = echo_named_default_string, .echo_optional_default_double = echo_optional_default_double, .echo_required_int = echo_required_int, + .are_all_nullable_types_equal = are_all_nullable_types_equal, + .get_all_nullable_types_hash = get_all_nullable_types_hash, + .get_all_nullable_types_without_recursion_hash = + get_all_nullable_types_without_recursion_hash, .echo_all_nullable_types = echo_all_nullable_types, .echo_all_nullable_types_without_recursion = echo_all_nullable_types_without_recursion, diff --git a/packages/pigeon/platform_tests/test_plugin/windows/CMakeLists.txt b/packages/pigeon/platform_tests/test_plugin/windows/CMakeLists.txt index e69e6bc75130..fff3f37c5d5c 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/CMakeLists.txt +++ b/packages/pigeon/platform_tests/test_plugin/windows/CMakeLists.txt @@ -66,6 +66,9 @@ target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) # https://developercommunity.visualstudio.com/t/stdany-doesnt-link-when-exceptions-are-disabled/376072 # TODO(stuartmorgan): Remove this once CI is using VS 2022 or later. target_compile_definitions(${PLUGIN_NAME} PRIVATE "_HAS_EXCEPTIONS=1") +if (MSVC) + target_compile_options(${PLUGIN_NAME} PRIVATE "/bigobj") +endif() # List of absolute paths to libraries that should be bundled with the plugin. # This list could contain prebuilt libraries, or libraries created by an @@ -126,6 +129,9 @@ add_custom_command(TARGET ${TEST_RUNNER} POST_BUILD # https://developercommunity.visualstudio.com/t/stdany-doesnt-link-when-exceptions-are-disabled/376072 # TODO(stuartmorgan): Remove this once CI is using VS 2022 or later. target_compile_definitions(${TEST_RUNNER} PRIVATE "_HAS_EXCEPTIONS=1") +if (MSVC) + target_compile_options(${TEST_RUNNER} PRIVATE "/bigobj") +endif() include(GoogleTest) gtest_discover_tests(${TEST_RUNNER}) diff --git a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp index b8c9e6860572..deb17caadc31 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp +++ b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp @@ -14,16 +14,18 @@ #include #include +#include +#include #include #include #include namespace core_tests_pigeontest { -using flutter::BasicMessageChannel; -using flutter::CustomEncodableValue; -using flutter::EncodableList; -using flutter::EncodableMap; -using flutter::EncodableValue; +using ::flutter::BasicMessageChannel; +using ::flutter::CustomEncodableValue; +using ::flutter::EncodableList; +using ::flutter::EncodableMap; +using ::flutter::EncodableValue; FlutterError CreateConnectionError(const std::string channel_name) { return FlutterError( @@ -32,6 +34,210 @@ FlutterError CreateConnectionError(const std::string channel_name) { EncodableValue("")); } +template +bool PigeonInternalDeepEquals(const T& a, const T& b); + +inline bool PigeonInternalDeepEquals(const double& a, const double& b); + +template +bool PigeonInternalDeepEquals(const std::vector& a, const std::vector& b); + +template +bool PigeonInternalDeepEquals(const std::map& a, const std::map& b); + +template +bool PigeonInternalDeepEquals(const std::optional& a, + const std::optional& b); + +template +bool PigeonInternalDeepEquals(const std::unique_ptr& a, + const std::unique_ptr& b); + +inline bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, + const ::flutter::EncodableValue& b); + +template +bool PigeonInternalDeepEquals(const T& a, const T& b) { + return a == b; +} + +template +bool PigeonInternalDeepEquals(const std::vector& a, + const std::vector& b) { + if (a.size() != b.size()) { + return false; + } + for (size_t i = 0; i < a.size(); ++i) { + if (!PigeonInternalDeepEquals(a[i], b[i])) { + return false; + } + } + return true; +} + +template +bool PigeonInternalDeepEquals(const std::map& a, + const std::map& b) { + if (a.size() != b.size()) { + return false; + } + for (const auto& kv : a) { + bool found = false; + for (const auto& b_kv : b) { + if (PigeonInternalDeepEquals(kv.first, b_kv.first)) { + if (PigeonInternalDeepEquals(kv.second, b_kv.second)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; +} + +inline bool PigeonInternalDeepEquals(const double& a, const double& b) { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (a == b) || (std::isnan(a) && std::isnan(b)); +} + +template +bool PigeonInternalDeepEquals(const std::optional& a, + const std::optional& b) { + if (!a && !b) { + return true; + } + if (!a || !b) { + return false; + } + return PigeonInternalDeepEquals(*a, *b); +} + +template +bool PigeonInternalDeepEquals(const std::unique_ptr& a, + const std::unique_ptr& b) { + if (!a && !b) { + return true; + } + if (!a || !b) { + return false; + } + return PigeonInternalDeepEquals(*a, *b); +} + +inline bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, + const ::flutter::EncodableValue& b) { + if (a.index() != b.index()) { + return false; + } + if (const double* da = std::get_if(&a)) { + return PigeonInternalDeepEquals(*da, std::get(b)); + } else if (const ::flutter::EncodableList* la = + std::get_if<::flutter::EncodableList>(&a)) { + return PigeonInternalDeepEquals(*la, std::get<::flutter::EncodableList>(b)); + } else if (const ::flutter::EncodableMap* ma = + std::get_if<::flutter::EncodableMap>(&a)) { + return PigeonInternalDeepEquals(*ma, std::get<::flutter::EncodableMap>(b)); + } + return a == b; +} + +template +size_t PigeonInternalDeepHash(const T& v); + +inline size_t PigeonInternalDeepHash(const double& v); + +template +size_t PigeonInternalDeepHash(const std::vector& v); + +template +size_t PigeonInternalDeepHash(const std::map& v); + +template +size_t PigeonInternalDeepHash(const std::optional& v); + +template +size_t PigeonInternalDeepHash(const std::unique_ptr& v); + +inline size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v); + +template +size_t PigeonInternalDeepHash(const T& v) { + return std::hash()(v); +} + +template +size_t PigeonInternalDeepHash(const std::vector& v) { + size_t result = 0; + for (const auto& item : v) { + result = result * 31 + PigeonInternalDeepHash(item); + } + return result; +} + +template +size_t PigeonInternalDeepHash(const std::map& v) { + size_t result = 0; + for (const auto& kv : v) { + result = result * 31 + PigeonInternalDeepHash(kv.first); + result = result * 31 + PigeonInternalDeepHash(kv.second); + } + return result; +} + +inline size_t PigeonInternalDeepHash(const double& v) { + if (std::isnan(v)) { + // Normalize NaN to a consistent hash. + return std::hash()(std::numeric_limits::quiet_NaN()); + } + if (v == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return std::hash()(0.0); + } + return std::hash()(v); +} + +template +size_t PigeonInternalDeepHash(const std::optional& v) { + return v ? PigeonInternalDeepHash(*v) : 0; +} + +template +size_t PigeonInternalDeepHash(const std::unique_ptr& v) { + return v ? PigeonInternalDeepHash(*v) : 0; +} + +inline size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v) { + size_t result = v.index(); + if (const double* dv = std::get_if(&v)) { + result = result * 31 + PigeonInternalDeepHash(*dv); + } else if (const ::flutter::EncodableList* lv = + std::get_if<::flutter::EncodableList>(&v)) { + result = result * 31 + PigeonInternalDeepHash(*lv); + } else if (const ::flutter::EncodableMap* mv = + std::get_if<::flutter::EncodableMap>(&v)) { + result = result * 31 + PigeonInternalDeepHash(*mv); + } else { + std::visit( + [&result](const auto& val) { + using T = std::decay_t; + if constexpr (!std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v) { + result = result * 31 + PigeonInternalDeepHash(val); + } + }, + v); + } + return result; +} + // UnusedClass UnusedClass::UnusedClass() {} @@ -69,6 +275,22 @@ UnusedClass UnusedClass::FromEncodableList(const EncodableList& list) { return decoded; } +bool UnusedClass::operator==(const UnusedClass& other) const { + return PigeonInternalDeepEquals(a_field_, other.a_field_); +} + +bool UnusedClass::operator!=(const UnusedClass& other) const { + return !(*this == other); +} + +size_t UnusedClass::Hash() const { + size_t result = 0; + result = result * 31 + PigeonInternalDeepHash(a_field_); + return result; +} + +size_t PigeonInternalDeepHash(const UnusedClass& v) { return v.Hash(); } + // AllTypes AllTypes::AllTypes(bool a_bool, int64_t an_int, int64_t an_int64, @@ -337,6 +559,76 @@ AllTypes AllTypes::FromEncodableList(const EncodableList& list) { return decoded; } +bool AllTypes::operator==(const AllTypes& other) const { + return PigeonInternalDeepEquals(a_bool_, other.a_bool_) && + PigeonInternalDeepEquals(an_int_, other.an_int_) && + PigeonInternalDeepEquals(an_int64_, other.an_int64_) && + PigeonInternalDeepEquals(a_double_, other.a_double_) && + PigeonInternalDeepEquals(a_byte_array_, other.a_byte_array_) && + PigeonInternalDeepEquals(a4_byte_array_, other.a4_byte_array_) && + PigeonInternalDeepEquals(a8_byte_array_, other.a8_byte_array_) && + PigeonInternalDeepEquals(a_float_array_, other.a_float_array_) && + PigeonInternalDeepEquals(an_enum_, other.an_enum_) && + PigeonInternalDeepEquals(another_enum_, other.another_enum_) && + PigeonInternalDeepEquals(a_string_, other.a_string_) && + PigeonInternalDeepEquals(an_object_, other.an_object_) && + PigeonInternalDeepEquals(list_, other.list_) && + PigeonInternalDeepEquals(string_list_, other.string_list_) && + PigeonInternalDeepEquals(int_list_, other.int_list_) && + PigeonInternalDeepEquals(double_list_, other.double_list_) && + PigeonInternalDeepEquals(bool_list_, other.bool_list_) && + PigeonInternalDeepEquals(enum_list_, other.enum_list_) && + PigeonInternalDeepEquals(object_list_, other.object_list_) && + PigeonInternalDeepEquals(list_list_, other.list_list_) && + PigeonInternalDeepEquals(map_list_, other.map_list_) && + PigeonInternalDeepEquals(map_, other.map_) && + PigeonInternalDeepEquals(string_map_, other.string_map_) && + PigeonInternalDeepEquals(int_map_, other.int_map_) && + PigeonInternalDeepEquals(enum_map_, other.enum_map_) && + PigeonInternalDeepEquals(object_map_, other.object_map_) && + PigeonInternalDeepEquals(list_map_, other.list_map_) && + PigeonInternalDeepEquals(map_map_, other.map_map_); +} + +bool AllTypes::operator!=(const AllTypes& other) const { + return !(*this == other); +} + +size_t AllTypes::Hash() const { + size_t result = 0; + result = result * 31 + PigeonInternalDeepHash(a_bool_); + result = result * 31 + PigeonInternalDeepHash(an_int_); + result = result * 31 + PigeonInternalDeepHash(an_int64_); + result = result * 31 + PigeonInternalDeepHash(a_double_); + result = result * 31 + PigeonInternalDeepHash(a_byte_array_); + result = result * 31 + PigeonInternalDeepHash(a4_byte_array_); + result = result * 31 + PigeonInternalDeepHash(a8_byte_array_); + result = result * 31 + PigeonInternalDeepHash(a_float_array_); + result = result * 31 + PigeonInternalDeepHash(an_enum_); + result = result * 31 + PigeonInternalDeepHash(another_enum_); + result = result * 31 + PigeonInternalDeepHash(a_string_); + result = result * 31 + PigeonInternalDeepHash(an_object_); + result = result * 31 + PigeonInternalDeepHash(list_); + result = result * 31 + PigeonInternalDeepHash(string_list_); + result = result * 31 + PigeonInternalDeepHash(int_list_); + result = result * 31 + PigeonInternalDeepHash(double_list_); + result = result * 31 + PigeonInternalDeepHash(bool_list_); + result = result * 31 + PigeonInternalDeepHash(enum_list_); + result = result * 31 + PigeonInternalDeepHash(object_list_); + result = result * 31 + PigeonInternalDeepHash(list_list_); + result = result * 31 + PigeonInternalDeepHash(map_list_); + result = result * 31 + PigeonInternalDeepHash(map_); + result = result * 31 + PigeonInternalDeepHash(string_map_); + result = result * 31 + PigeonInternalDeepHash(int_map_); + result = result * 31 + PigeonInternalDeepHash(enum_map_); + result = result * 31 + PigeonInternalDeepHash(object_map_); + result = result * 31 + PigeonInternalDeepHash(list_map_); + result = result * 31 + PigeonInternalDeepHash(map_map_); + return result; +} + +size_t PigeonInternalDeepHash(const AllTypes& v) { return v.Hash(); } + // AllNullableTypes AllNullableTypes::AllNullableTypes() {} @@ -1187,6 +1479,93 @@ AllNullableTypes AllNullableTypes::FromEncodableList( return decoded; } +bool AllNullableTypes::operator==(const AllNullableTypes& other) const { + return PigeonInternalDeepEquals(a_nullable_bool_, other.a_nullable_bool_) && + PigeonInternalDeepEquals(a_nullable_int_, other.a_nullable_int_) && + PigeonInternalDeepEquals(a_nullable_int64_, other.a_nullable_int64_) && + PigeonInternalDeepEquals(a_nullable_double_, + other.a_nullable_double_) && + PigeonInternalDeepEquals(a_nullable_byte_array_, + other.a_nullable_byte_array_) && + PigeonInternalDeepEquals(a_nullable4_byte_array_, + other.a_nullable4_byte_array_) && + PigeonInternalDeepEquals(a_nullable8_byte_array_, + other.a_nullable8_byte_array_) && + PigeonInternalDeepEquals(a_nullable_float_array_, + other.a_nullable_float_array_) && + PigeonInternalDeepEquals(a_nullable_enum_, other.a_nullable_enum_) && + PigeonInternalDeepEquals(another_nullable_enum_, + other.another_nullable_enum_) && + PigeonInternalDeepEquals(a_nullable_string_, + other.a_nullable_string_) && + PigeonInternalDeepEquals(a_nullable_object_, + other.a_nullable_object_) && + PigeonInternalDeepEquals(all_nullable_types_, + other.all_nullable_types_) && + PigeonInternalDeepEquals(list_, other.list_) && + PigeonInternalDeepEquals(string_list_, other.string_list_) && + PigeonInternalDeepEquals(int_list_, other.int_list_) && + PigeonInternalDeepEquals(double_list_, other.double_list_) && + PigeonInternalDeepEquals(bool_list_, other.bool_list_) && + PigeonInternalDeepEquals(enum_list_, other.enum_list_) && + PigeonInternalDeepEquals(object_list_, other.object_list_) && + PigeonInternalDeepEquals(list_list_, other.list_list_) && + PigeonInternalDeepEquals(map_list_, other.map_list_) && + PigeonInternalDeepEquals(recursive_class_list_, + other.recursive_class_list_) && + PigeonInternalDeepEquals(map_, other.map_) && + PigeonInternalDeepEquals(string_map_, other.string_map_) && + PigeonInternalDeepEquals(int_map_, other.int_map_) && + PigeonInternalDeepEquals(enum_map_, other.enum_map_) && + PigeonInternalDeepEquals(object_map_, other.object_map_) && + PigeonInternalDeepEquals(list_map_, other.list_map_) && + PigeonInternalDeepEquals(map_map_, other.map_map_) && + PigeonInternalDeepEquals(recursive_class_map_, + other.recursive_class_map_); +} + +bool AllNullableTypes::operator!=(const AllNullableTypes& other) const { + return !(*this == other); +} + +size_t AllNullableTypes::Hash() const { + size_t result = 0; + result = result * 31 + PigeonInternalDeepHash(a_nullable_bool_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_int_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_int64_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_double_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_byte_array_); + result = result * 31 + PigeonInternalDeepHash(a_nullable4_byte_array_); + result = result * 31 + PigeonInternalDeepHash(a_nullable8_byte_array_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_float_array_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_enum_); + result = result * 31 + PigeonInternalDeepHash(another_nullable_enum_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_string_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_object_); + result = result * 31 + PigeonInternalDeepHash(all_nullable_types_); + result = result * 31 + PigeonInternalDeepHash(list_); + result = result * 31 + PigeonInternalDeepHash(string_list_); + result = result * 31 + PigeonInternalDeepHash(int_list_); + result = result * 31 + PigeonInternalDeepHash(double_list_); + result = result * 31 + PigeonInternalDeepHash(bool_list_); + result = result * 31 + PigeonInternalDeepHash(enum_list_); + result = result * 31 + PigeonInternalDeepHash(object_list_); + result = result * 31 + PigeonInternalDeepHash(list_list_); + result = result * 31 + PigeonInternalDeepHash(map_list_); + result = result * 31 + PigeonInternalDeepHash(recursive_class_list_); + result = result * 31 + PigeonInternalDeepHash(map_); + result = result * 31 + PigeonInternalDeepHash(string_map_); + result = result * 31 + PigeonInternalDeepHash(int_map_); + result = result * 31 + PigeonInternalDeepHash(enum_map_); + result = result * 31 + PigeonInternalDeepHash(object_map_); + result = result * 31 + PigeonInternalDeepHash(list_map_); + result = result * 31 + PigeonInternalDeepHash(map_map_); + result = result * 31 + PigeonInternalDeepHash(recursive_class_map_); + return result; +} + +size_t PigeonInternalDeepHash(const AllNullableTypes& v) { return v.Hash(); } + // AllNullableTypesWithoutRecursion AllNullableTypesWithoutRecursion::AllNullableTypesWithoutRecursion() {} @@ -1873,6 +2252,88 @@ AllNullableTypesWithoutRecursion::FromEncodableList(const EncodableList& list) { return decoded; } +bool AllNullableTypesWithoutRecursion::operator==( + const AllNullableTypesWithoutRecursion& other) const { + return PigeonInternalDeepEquals(a_nullable_bool_, other.a_nullable_bool_) && + PigeonInternalDeepEquals(a_nullable_int_, other.a_nullable_int_) && + PigeonInternalDeepEquals(a_nullable_int64_, other.a_nullable_int64_) && + PigeonInternalDeepEquals(a_nullable_double_, + other.a_nullable_double_) && + PigeonInternalDeepEquals(a_nullable_byte_array_, + other.a_nullable_byte_array_) && + PigeonInternalDeepEquals(a_nullable4_byte_array_, + other.a_nullable4_byte_array_) && + PigeonInternalDeepEquals(a_nullable8_byte_array_, + other.a_nullable8_byte_array_) && + PigeonInternalDeepEquals(a_nullable_float_array_, + other.a_nullable_float_array_) && + PigeonInternalDeepEquals(a_nullable_enum_, other.a_nullable_enum_) && + PigeonInternalDeepEquals(another_nullable_enum_, + other.another_nullable_enum_) && + PigeonInternalDeepEquals(a_nullable_string_, + other.a_nullable_string_) && + PigeonInternalDeepEquals(a_nullable_object_, + other.a_nullable_object_) && + PigeonInternalDeepEquals(list_, other.list_) && + PigeonInternalDeepEquals(string_list_, other.string_list_) && + PigeonInternalDeepEquals(int_list_, other.int_list_) && + PigeonInternalDeepEquals(double_list_, other.double_list_) && + PigeonInternalDeepEquals(bool_list_, other.bool_list_) && + PigeonInternalDeepEquals(enum_list_, other.enum_list_) && + PigeonInternalDeepEquals(object_list_, other.object_list_) && + PigeonInternalDeepEquals(list_list_, other.list_list_) && + PigeonInternalDeepEquals(map_list_, other.map_list_) && + PigeonInternalDeepEquals(map_, other.map_) && + PigeonInternalDeepEquals(string_map_, other.string_map_) && + PigeonInternalDeepEquals(int_map_, other.int_map_) && + PigeonInternalDeepEquals(enum_map_, other.enum_map_) && + PigeonInternalDeepEquals(object_map_, other.object_map_) && + PigeonInternalDeepEquals(list_map_, other.list_map_) && + PigeonInternalDeepEquals(map_map_, other.map_map_); +} + +bool AllNullableTypesWithoutRecursion::operator!=( + const AllNullableTypesWithoutRecursion& other) const { + return !(*this == other); +} + +size_t AllNullableTypesWithoutRecursion::Hash() const { + size_t result = 0; + result = result * 31 + PigeonInternalDeepHash(a_nullable_bool_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_int_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_int64_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_double_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_byte_array_); + result = result * 31 + PigeonInternalDeepHash(a_nullable4_byte_array_); + result = result * 31 + PigeonInternalDeepHash(a_nullable8_byte_array_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_float_array_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_enum_); + result = result * 31 + PigeonInternalDeepHash(another_nullable_enum_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_string_); + result = result * 31 + PigeonInternalDeepHash(a_nullable_object_); + result = result * 31 + PigeonInternalDeepHash(list_); + result = result * 31 + PigeonInternalDeepHash(string_list_); + result = result * 31 + PigeonInternalDeepHash(int_list_); + result = result * 31 + PigeonInternalDeepHash(double_list_); + result = result * 31 + PigeonInternalDeepHash(bool_list_); + result = result * 31 + PigeonInternalDeepHash(enum_list_); + result = result * 31 + PigeonInternalDeepHash(object_list_); + result = result * 31 + PigeonInternalDeepHash(list_list_); + result = result * 31 + PigeonInternalDeepHash(map_list_); + result = result * 31 + PigeonInternalDeepHash(map_); + result = result * 31 + PigeonInternalDeepHash(string_map_); + result = result * 31 + PigeonInternalDeepHash(int_map_); + result = result * 31 + PigeonInternalDeepHash(enum_map_); + result = result * 31 + PigeonInternalDeepHash(object_map_); + result = result * 31 + PigeonInternalDeepHash(list_map_); + result = result * 31 + PigeonInternalDeepHash(map_map_); + return result; +} + +size_t PigeonInternalDeepHash(const AllNullableTypesWithoutRecursion& v) { + return v.Hash(); +} + // AllClassesWrapper AllClassesWrapper::AllClassesWrapper(const AllNullableTypes& all_nullable_types, @@ -2079,6 +2540,40 @@ AllClassesWrapper AllClassesWrapper::FromEncodableList( return decoded; } +bool AllClassesWrapper::operator==(const AllClassesWrapper& other) const { + return PigeonInternalDeepEquals(all_nullable_types_, + other.all_nullable_types_) && + PigeonInternalDeepEquals( + all_nullable_types_without_recursion_, + other.all_nullable_types_without_recursion_) && + PigeonInternalDeepEquals(all_types_, other.all_types_) && + PigeonInternalDeepEquals(class_list_, other.class_list_) && + PigeonInternalDeepEquals(nullable_class_list_, + other.nullable_class_list_) && + PigeonInternalDeepEquals(class_map_, other.class_map_) && + PigeonInternalDeepEquals(nullable_class_map_, + other.nullable_class_map_); +} + +bool AllClassesWrapper::operator!=(const AllClassesWrapper& other) const { + return !(*this == other); +} + +size_t AllClassesWrapper::Hash() const { + size_t result = 0; + result = result * 31 + PigeonInternalDeepHash(all_nullable_types_); + result = result * 31 + + PigeonInternalDeepHash(all_nullable_types_without_recursion_); + result = result * 31 + PigeonInternalDeepHash(all_types_); + result = result * 31 + PigeonInternalDeepHash(class_list_); + result = result * 31 + PigeonInternalDeepHash(nullable_class_list_); + result = result * 31 + PigeonInternalDeepHash(class_map_); + result = result * 31 + PigeonInternalDeepHash(nullable_class_map_); + return result; +} + +size_t PigeonInternalDeepHash(const AllClassesWrapper& v) { return v.Hash(); } + // TestMessage TestMessage::TestMessage() {} @@ -2116,10 +2611,26 @@ TestMessage TestMessage::FromEncodableList(const EncodableList& list) { return decoded; } +bool TestMessage::operator==(const TestMessage& other) const { + return PigeonInternalDeepEquals(test_list_, other.test_list_); +} + +bool TestMessage::operator!=(const TestMessage& other) const { + return !(*this == other); +} + +size_t TestMessage::Hash() const { + size_t result = 0; + result = result * 31 + PigeonInternalDeepHash(test_list_); + return result; +} + +size_t PigeonInternalDeepHash(const TestMessage& v) { return v.Hash(); } + PigeonInternalCodecSerializer::PigeonInternalCodecSerializer() {} EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( - uint8_t type, flutter::ByteStreamReader* stream) const { + uint8_t type, ::flutter::ByteStreamReader* stream) const { switch (type) { case 129: { const auto& encodable_enum_arg = ReadValue(stream); @@ -2164,12 +2675,12 @@ EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( std::get(ReadValue(stream)))); } default: - return flutter::StandardCodecSerializer::ReadValueOfType(type, stream); + return ::flutter::StandardCodecSerializer::ReadValueOfType(type, stream); } } void PigeonInternalCodecSerializer::WriteValue( - const EncodableValue& value, flutter::ByteStreamWriter* stream) const { + const EncodableValue& value, ::flutter::ByteStreamWriter* stream) const { if (const CustomEncodableValue* custom_value = std::get_if(&value)) { if (custom_value->type() == typeid(AnEnum)) { @@ -2233,23 +2744,23 @@ void PigeonInternalCodecSerializer::WriteValue( return; } } - flutter::StandardCodecSerializer::WriteValue(value, stream); + ::flutter::StandardCodecSerializer::WriteValue(value, stream); } /// The codec used by HostIntegrationCoreApi. -const flutter::StandardMessageCodec& HostIntegrationCoreApi::GetCodec() { - return flutter::StandardMessageCodec::GetInstance( +const ::flutter::StandardMessageCodec& HostIntegrationCoreApi::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance( &PigeonInternalCodecSerializer::GetInstance()); } // Sets up an instance of `HostIntegrationCoreApi` to handle messages through // the `binary_messenger`. -void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, +void HostIntegrationCoreApi::SetUp(::flutter::BinaryMessenger* binary_messenger, HostIntegrationCoreApi* api) { HostIntegrationCoreApi::SetUp(binary_messenger, api, ""); } -void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, +void HostIntegrationCoreApi::SetUp(::flutter::BinaryMessenger* binary_messenger, HostIntegrationCoreApi* api, const std::string& message_channel_suffix) { const std::string prepended_suffix = @@ -2265,7 +2776,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { std::optional output = api->Noop(); if (output.has_value()) { @@ -2292,7 +2803,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_everything_arg = args.at(0); @@ -2328,7 +2839,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { ErrorOr> output = api->ThrowError(); if (output.has_error()) { @@ -2361,7 +2872,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { std::optional output = api->ThrowErrorFromVoid(); if (output.has_value()) { @@ -2388,7 +2899,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { ErrorOr> output = api->ThrowFlutterError(); @@ -2422,7 +2933,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_int_arg = args.at(0); @@ -2456,7 +2967,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_double_arg = args.at(0); @@ -2491,7 +3002,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_bool_arg = args.at(0); @@ -2525,7 +3036,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_string_arg = args.at(0); @@ -2560,7 +3071,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_uint8_list_arg = args.at(0); @@ -2596,7 +3107,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_object_arg = args.at(0); @@ -2630,7 +3141,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_list_arg = args.at(0); @@ -2665,7 +3176,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_list_arg = args.at(0); @@ -2700,7 +3211,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_list_arg = args.at(0); @@ -2736,7 +3247,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_list_arg = args.at(0); @@ -2773,7 +3284,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_list_arg = args.at(0); @@ -2809,7 +3320,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_map_arg = args.at(0); @@ -2843,7 +3354,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_string_map_arg = args.at(0); @@ -2878,7 +3389,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_int_map_arg = args.at(0); @@ -2913,7 +3424,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_map_arg = args.at(0); @@ -2948,7 +3459,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_map_arg = args.at(0); @@ -2984,7 +3495,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_string_map_arg = args.at(0); @@ -3020,7 +3531,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_int_map_arg = args.at(0); @@ -3056,7 +3567,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_map_arg = args.at(0); @@ -3092,7 +3603,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_map_arg = args.at(0); @@ -3128,7 +3639,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_wrapper_arg = args.at(0); @@ -3165,7 +3676,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_enum_arg = args.at(0); @@ -3201,7 +3712,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_another_enum_arg = args.at(0); @@ -3239,7 +3750,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_string_arg = args.at(0); @@ -3276,7 +3787,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_double_arg = args.at(0); @@ -3312,7 +3823,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_int_arg = args.at(0); @@ -3337,6 +3848,124 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, channel.SetMessageHandler(nullptr); } } + { + BasicMessageChannel<> channel( + binary_messenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "areAllNullableTypesEqual" + + prepended_suffix, + &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler( + [api](const EncodableValue& message, + const ::flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_a_arg = args.at(0); + if (encodable_a_arg.IsNull()) { + reply(WrapError("a_arg unexpectedly null.")); + return; + } + const auto& a_arg = std::any_cast( + std::get(encodable_a_arg)); + const auto& encodable_b_arg = args.at(1); + if (encodable_b_arg.IsNull()) { + reply(WrapError("b_arg unexpectedly null.")); + return; + } + const auto& b_arg = std::any_cast( + std::get(encodable_b_arg)); + ErrorOr output = + api->AreAllNullableTypesEqual(a_arg, b_arg); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel( + binary_messenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "getAllNullableTypesHash" + + prepended_suffix, + &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler( + [api](const EncodableValue& message, + const ::flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_value_arg = args.at(0); + if (encodable_value_arg.IsNull()) { + reply(WrapError("value_arg unexpectedly null.")); + return; + } + const auto& value_arg = std::any_cast( + std::get(encodable_value_arg)); + ErrorOr output = api->GetAllNullableTypesHash(value_arg); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel( + binary_messenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "getAllNullableTypesWithoutRecursionHash" + + prepended_suffix, + &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler( + [api](const EncodableValue& message, + const ::flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_value_arg = args.at(0); + if (encodable_value_arg.IsNull()) { + reply(WrapError("value_arg unexpectedly null.")); + return; + } + const auto& value_arg = + std::any_cast( + std::get(encodable_value_arg)); + ErrorOr output = + api->GetAllNullableTypesWithoutRecursionHash(value_arg); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } { BasicMessageChannel<> channel( binary_messenger, @@ -3347,7 +3976,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_everything_arg = args.at(0); @@ -3388,10 +4017,9 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api]( - const EncodableValue& message, - const flutter::MessageReply& - reply) { + channel.SetMessageHandler([api](const EncodableValue& message, + const ::flutter::MessageReply< + EncodableValue>& reply) { try { const auto& args = std::get(message); const auto& encodable_everything_arg = args.at(0); @@ -3434,7 +4062,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_wrapper_arg = args.at(0); @@ -3477,7 +4105,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_nullable_string_arg = args.at(0); @@ -3511,7 +4139,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_bool_arg = args.at(0); @@ -3552,7 +4180,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_bool_arg = args.at(0); @@ -3593,7 +4221,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_int_arg = args.at(0); @@ -3631,7 +4259,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_double_arg = args.at(0); @@ -3669,7 +4297,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_bool_arg = args.at(0); @@ -3707,7 +4335,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_string_arg = args.at(0); @@ -3746,7 +4374,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_uint8_list_arg = args.at(0); @@ -3785,7 +4413,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_object_arg = args.at(0); @@ -3823,7 +4451,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_list_arg = args.at(0); @@ -3862,7 +4490,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_list_arg = args.at(0); @@ -3901,7 +4529,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_list_arg = args.at(0); @@ -3940,7 +4568,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_list_arg = args.at(0); @@ -3979,7 +4607,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_list_arg = args.at(0); @@ -4017,7 +4645,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_map_arg = args.at(0); @@ -4056,7 +4684,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_string_map_arg = args.at(0); @@ -4094,7 +4722,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_int_map_arg = args.at(0); @@ -4132,7 +4760,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_map_arg = args.at(0); @@ -4171,7 +4799,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_map_arg = args.at(0); @@ -4210,7 +4838,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_string_map_arg = args.at(0); @@ -4249,7 +4877,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_int_map_arg = args.at(0); @@ -4288,7 +4916,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_map_arg = args.at(0); @@ -4327,7 +4955,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_map_arg = args.at(0); @@ -4365,7 +4993,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_enum_arg = args.at(0); @@ -4409,7 +5037,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_another_enum_arg = args.at(0); @@ -4454,7 +5082,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_int_arg = args.at(0); @@ -4493,7 +5121,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_string_arg = args.at(0); @@ -4531,7 +5159,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { api->NoopAsync([reply](std::optional&& output) { if (output.has_value()) { @@ -4559,7 +5187,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_int_arg = args.at(0); @@ -4595,7 +5223,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_double_arg = args.at(0); @@ -4633,7 +5261,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_bool_arg = args.at(0); @@ -4669,7 +5297,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_string_arg = args.at(0); @@ -4707,7 +5335,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_uint8_list_arg = args.at(0); @@ -4746,7 +5374,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_object_arg = args.at(0); @@ -4783,7 +5411,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_list_arg = args.at(0); @@ -4821,7 +5449,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_list_arg = args.at(0); @@ -4859,7 +5487,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_list_arg = args.at(0); @@ -4897,7 +5525,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_map_arg = args.at(0); @@ -4934,7 +5562,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_string_map_arg = args.at(0); @@ -4972,7 +5600,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_int_map_arg = args.at(0); @@ -5010,7 +5638,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_map_arg = args.at(0); @@ -5048,7 +5676,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_map_arg = args.at(0); @@ -5086,7 +5714,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_enum_arg = args.at(0); @@ -5125,7 +5753,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_another_enum_arg = args.at(0); @@ -5163,7 +5791,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { api->ThrowAsyncError( [reply](ErrorOr>&& output) { @@ -5199,7 +5827,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { api->ThrowAsyncErrorFromVoid( [reply](std::optional&& output) { @@ -5229,7 +5857,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { api->ThrowAsyncFlutterError( [reply](ErrorOr>&& output) { @@ -5264,7 +5892,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_everything_arg = args.at(0); @@ -5303,7 +5931,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_everything_arg = args.at(0); @@ -5346,10 +5974,9 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api]( - const EncodableValue& message, - const flutter::MessageReply& - reply) { + channel.SetMessageHandler([api](const EncodableValue& message, + const ::flutter::MessageReply< + EncodableValue>& reply) { try { const auto& args = std::get(message); const auto& encodable_everything_arg = args.at(0); @@ -5395,7 +6022,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_int_arg = args.at(0); @@ -5436,7 +6063,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_double_arg = args.at(0); @@ -5477,7 +6104,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_bool_arg = args.at(0); @@ -5516,7 +6143,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_string_arg = args.at(0); @@ -5557,7 +6184,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_uint8_list_arg = args.at(0); @@ -5599,7 +6226,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_object_arg = args.at(0); @@ -5639,7 +6266,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_list_arg = args.at(0); @@ -5680,7 +6307,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_list_arg = args.at(0); @@ -5721,7 +6348,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_list_arg = args.at(0); @@ -5762,7 +6389,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_map_arg = args.at(0); @@ -5803,7 +6430,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_string_map_arg = args.at(0); @@ -5844,7 +6471,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_int_map_arg = args.at(0); @@ -5885,7 +6512,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_map_arg = args.at(0); @@ -5926,7 +6553,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_map_arg = args.at(0); @@ -5967,7 +6594,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_enum_arg = args.at(0); @@ -6013,7 +6640,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_another_enum_arg = args.at(0); @@ -6058,7 +6685,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { ErrorOr output = api->DefaultIsMainThread(); if (output.has_error()) { @@ -6086,7 +6713,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { ErrorOr output = api->TaskQueueIsBackgroundThread(); if (output.has_error()) { @@ -6113,7 +6740,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { api->CallFlutterNoop( [reply](std::optional&& output) { @@ -6143,7 +6770,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { api->CallFlutterThrowError( [reply](ErrorOr>&& output) { @@ -6179,7 +6806,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { api->CallFlutterThrowErrorFromVoid( [reply](std::optional&& output) { @@ -6209,7 +6836,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_everything_arg = args.at(0); @@ -6248,7 +6875,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_everything_arg = args.at(0); @@ -6293,7 +6920,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_bool_arg = args.at(0); @@ -6334,10 +6961,9 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api]( - const EncodableValue& message, - const flutter::MessageReply& - reply) { + channel.SetMessageHandler([api](const EncodableValue& message, + const ::flutter::MessageReply< + EncodableValue>& reply) { try { const auto& args = std::get(message); const auto& encodable_everything_arg = args.at(0); @@ -6383,7 +7009,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_nullable_bool_arg = args.at(0); @@ -6425,7 +7051,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_bool_arg = args.at(0); @@ -6462,7 +7088,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_int_arg = args.at(0); @@ -6500,7 +7126,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_double_arg = args.at(0); @@ -6539,7 +7165,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_string_arg = args.at(0); @@ -6578,7 +7204,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_list_arg = args.at(0); @@ -6616,7 +7242,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_list_arg = args.at(0); @@ -6655,7 +7281,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_list_arg = args.at(0); @@ -6694,7 +7320,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_list_arg = args.at(0); @@ -6733,7 +7359,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_list_arg = args.at(0); @@ -6772,7 +7398,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_list_arg = args.at(0); @@ -6810,7 +7436,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_map_arg = args.at(0); @@ -6848,7 +7474,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_string_map_arg = args.at(0); @@ -6887,7 +7513,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_int_map_arg = args.at(0); @@ -6926,7 +7552,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_map_arg = args.at(0); @@ -6965,7 +7591,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_map_arg = args.at(0); @@ -7004,7 +7630,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_string_map_arg = args.at(0); @@ -7043,7 +7669,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_int_map_arg = args.at(0); @@ -7082,7 +7708,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_map_arg = args.at(0); @@ -7121,7 +7747,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_map_arg = args.at(0); @@ -7159,7 +7785,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_enum_arg = args.at(0); @@ -7198,7 +7824,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_another_enum_arg = args.at(0); @@ -7237,7 +7863,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_bool_arg = args.at(0); @@ -7276,7 +7902,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_int_arg = args.at(0); @@ -7317,7 +7943,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_double_arg = args.at(0); @@ -7358,7 +7984,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_string_arg = args.at(0); @@ -7399,7 +8025,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_list_arg = args.at(0); @@ -7441,7 +8067,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_list_arg = args.at(0); @@ -7482,7 +8108,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_list_arg = args.at(0); @@ -7523,7 +8149,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_list_arg = args.at(0); @@ -7564,7 +8190,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_list_arg = args.at(0); @@ -7605,7 +8231,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_list_arg = args.at(0); @@ -7646,7 +8272,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_map_arg = args.at(0); @@ -7687,7 +8313,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_string_map_arg = args.at(0); @@ -7728,7 +8354,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_int_map_arg = args.at(0); @@ -7769,7 +8395,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_map_arg = args.at(0); @@ -7810,7 +8436,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_map_arg = args.at(0); @@ -7851,7 +8477,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_string_map_arg = args.at(0); @@ -7892,7 +8518,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_int_map_arg = args.at(0); @@ -7933,7 +8559,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_enum_map_arg = args.at(0); @@ -7974,7 +8600,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_class_map_arg = args.at(0); @@ -8015,7 +8641,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_an_enum_arg = args.at(0); @@ -8061,7 +8687,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_another_enum_arg = args.at(0); @@ -8107,7 +8733,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_string_arg = args.at(0); @@ -8154,19 +8780,19 @@ EncodableValue HostIntegrationCoreApi::WrapError(const FlutterError& error) { // Generated class from Pigeon that represents Flutter messages that can be // called from C++. FlutterIntegrationCoreApi::FlutterIntegrationCoreApi( - flutter::BinaryMessenger* binary_messenger) + ::flutter::BinaryMessenger* binary_messenger) : binary_messenger_(binary_messenger), message_channel_suffix_("") {} FlutterIntegrationCoreApi::FlutterIntegrationCoreApi( - flutter::BinaryMessenger* binary_messenger, + ::flutter::BinaryMessenger* binary_messenger, const std::string& message_channel_suffix) : binary_messenger_(binary_messenger), message_channel_suffix_(message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : "") {} -const flutter::StandardMessageCodec& FlutterIntegrationCoreApi::GetCodec() { - return flutter::StandardMessageCodec::GetInstance( +const ::flutter::StandardMessageCodec& FlutterIntegrationCoreApi::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance( &PigeonInternalCodecSerializer::GetInstance()); } @@ -10148,19 +10774,19 @@ void FlutterIntegrationCoreApi::EchoAsyncString( } /// The codec used by HostTrivialApi. -const flutter::StandardMessageCodec& HostTrivialApi::GetCodec() { - return flutter::StandardMessageCodec::GetInstance( +const ::flutter::StandardMessageCodec& HostTrivialApi::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance( &PigeonInternalCodecSerializer::GetInstance()); } // Sets up an instance of `HostTrivialApi` to handle messages through the // `binary_messenger`. -void HostTrivialApi::SetUp(flutter::BinaryMessenger* binary_messenger, +void HostTrivialApi::SetUp(::flutter::BinaryMessenger* binary_messenger, HostTrivialApi* api) { HostTrivialApi::SetUp(binary_messenger, api, ""); } -void HostTrivialApi::SetUp(flutter::BinaryMessenger* binary_messenger, +void HostTrivialApi::SetUp(::flutter::BinaryMessenger* binary_messenger, HostTrivialApi* api, const std::string& message_channel_suffix) { const std::string prepended_suffix = @@ -10176,7 +10802,7 @@ void HostTrivialApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { std::optional output = api->Noop(); if (output.has_value()) { @@ -10209,19 +10835,19 @@ EncodableValue HostTrivialApi::WrapError(const FlutterError& error) { } /// The codec used by HostSmallApi. -const flutter::StandardMessageCodec& HostSmallApi::GetCodec() { - return flutter::StandardMessageCodec::GetInstance( +const ::flutter::StandardMessageCodec& HostSmallApi::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance( &PigeonInternalCodecSerializer::GetInstance()); } // Sets up an instance of `HostSmallApi` to handle messages through the // `binary_messenger`. -void HostSmallApi::SetUp(flutter::BinaryMessenger* binary_messenger, +void HostSmallApi::SetUp(::flutter::BinaryMessenger* binary_messenger, HostSmallApi* api) { HostSmallApi::SetUp(binary_messenger, api, ""); } -void HostSmallApi::SetUp(flutter::BinaryMessenger* binary_messenger, +void HostSmallApi::SetUp(::flutter::BinaryMessenger* binary_messenger, HostSmallApi* api, const std::string& message_channel_suffix) { const std::string prepended_suffix = @@ -10237,7 +10863,7 @@ void HostSmallApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_a_string_arg = args.at(0); @@ -10274,7 +10900,7 @@ void HostSmallApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { api->VoidVoid([reply](std::optional&& output) { if (output.has_value()) { @@ -10309,18 +10935,18 @@ EncodableValue HostSmallApi::WrapError(const FlutterError& error) { // Generated class from Pigeon that represents Flutter messages that can be // called from C++. -FlutterSmallApi::FlutterSmallApi(flutter::BinaryMessenger* binary_messenger) +FlutterSmallApi::FlutterSmallApi(::flutter::BinaryMessenger* binary_messenger) : binary_messenger_(binary_messenger), message_channel_suffix_("") {} -FlutterSmallApi::FlutterSmallApi(flutter::BinaryMessenger* binary_messenger, +FlutterSmallApi::FlutterSmallApi(::flutter::BinaryMessenger* binary_messenger, const std::string& message_channel_suffix) : binary_messenger_(binary_messenger), message_channel_suffix_(message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : "") {} -const flutter::StandardMessageCodec& FlutterSmallApi::GetCodec() { - return flutter::StandardMessageCodec::GetInstance( +const ::flutter::StandardMessageCodec& FlutterSmallApi::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance( &PigeonInternalCodecSerializer::GetInstance()); } diff --git a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h index 450a1dfcf068..24ca4540d6a8 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h +++ b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h @@ -28,17 +28,17 @@ class FlutterError { explicit FlutterError(const std::string& code, const std::string& message) : code_(code), message_(message) {} explicit FlutterError(const std::string& code, const std::string& message, - const flutter::EncodableValue& details) + const ::flutter::EncodableValue& details) : code_(code), message_(message), details_(details) {} const std::string& code() const { return code_; } const std::string& message() const { return message_; } - const flutter::EncodableValue& details() const { return details_; } + const ::flutter::EncodableValue& details() const { return details_; } private: std::string code_; std::string message_; - flutter::EncodableValue details_; + ::flutter::EncodableValue details_; }; template @@ -82,15 +82,21 @@ class UnusedClass { UnusedClass(); // Constructs an object setting all fields. - explicit UnusedClass(const flutter::EncodableValue* a_field); + explicit UnusedClass(const ::flutter::EncodableValue* a_field); - const flutter::EncodableValue* a_field() const; - void set_a_field(const flutter::EncodableValue* value_arg); - void set_a_field(const flutter::EncodableValue& value_arg); + const ::flutter::EncodableValue* a_field() const; + void set_a_field(const ::flutter::EncodableValue* value_arg); + void set_a_field(const ::flutter::EncodableValue& value_arg); + + bool operator==(const UnusedClass& other) const; + bool operator!=(const UnusedClass& other) const; + /// Returns a hash code value for the object. This method is supported for the + /// benefit of hash tables. + size_t Hash() const; private: - static UnusedClass FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static UnusedClass FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class HostIntegrationCoreApi; friend class FlutterIntegrationCoreApi; friend class HostTrivialApi; @@ -98,7 +104,7 @@ class UnusedClass { friend class FlutterSmallApi; friend class PigeonInternalCodecSerializer; friend class CoreTestsTest; - std::optional a_field_; + std::optional<::flutter::EncodableValue> a_field_; }; // A class containing all supported types. @@ -114,23 +120,23 @@ class AllTypes { const std::vector& a_float_array, const AnEnum& an_enum, const AnotherEnum& another_enum, const std::string& a_string, - const flutter::EncodableValue& an_object, - const flutter::EncodableList& list, - const flutter::EncodableList& string_list, - const flutter::EncodableList& int_list, - const flutter::EncodableList& double_list, - const flutter::EncodableList& bool_list, - const flutter::EncodableList& enum_list, - const flutter::EncodableList& object_list, - const flutter::EncodableList& list_list, - const flutter::EncodableList& map_list, - const flutter::EncodableMap& map, - const flutter::EncodableMap& string_map, - const flutter::EncodableMap& int_map, - const flutter::EncodableMap& enum_map, - const flutter::EncodableMap& object_map, - const flutter::EncodableMap& list_map, - const flutter::EncodableMap& map_map); + const ::flutter::EncodableValue& an_object, + const ::flutter::EncodableList& list, + const ::flutter::EncodableList& string_list, + const ::flutter::EncodableList& int_list, + const ::flutter::EncodableList& double_list, + const ::flutter::EncodableList& bool_list, + const ::flutter::EncodableList& enum_list, + const ::flutter::EncodableList& object_list, + const ::flutter::EncodableList& list_list, + const ::flutter::EncodableList& map_list, + const ::flutter::EncodableMap& map, + const ::flutter::EncodableMap& string_map, + const ::flutter::EncodableMap& int_map, + const ::flutter::EncodableMap& enum_map, + const ::flutter::EncodableMap& object_map, + const ::flutter::EncodableMap& list_map, + const ::flutter::EncodableMap& map_map); bool a_bool() const; void set_a_bool(bool value_arg); @@ -165,60 +171,66 @@ class AllTypes { const std::string& a_string() const; void set_a_string(std::string_view value_arg); - const flutter::EncodableValue& an_object() const; - void set_an_object(const flutter::EncodableValue& value_arg); + const ::flutter::EncodableValue& an_object() const; + void set_an_object(const ::flutter::EncodableValue& value_arg); + + const ::flutter::EncodableList& list() const; + void set_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& list() const; - void set_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& string_list() const; + void set_string_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& string_list() const; - void set_string_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& int_list() const; + void set_int_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& int_list() const; - void set_int_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& double_list() const; + void set_double_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& double_list() const; - void set_double_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& bool_list() const; + void set_bool_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& bool_list() const; - void set_bool_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& enum_list() const; + void set_enum_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& enum_list() const; - void set_enum_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& object_list() const; + void set_object_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& object_list() const; - void set_object_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& list_list() const; + void set_list_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& list_list() const; - void set_list_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& map_list() const; + void set_map_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& map_list() const; - void set_map_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableMap& map() const; + void set_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap& map() const; - void set_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap& string_map() const; + void set_string_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap& string_map() const; - void set_string_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap& int_map() const; + void set_int_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap& int_map() const; - void set_int_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap& enum_map() const; + void set_enum_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap& enum_map() const; - void set_enum_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap& object_map() const; + void set_object_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap& object_map() const; - void set_object_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap& list_map() const; + void set_list_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap& list_map() const; - void set_list_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap& map_map() const; + void set_map_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap& map_map() const; - void set_map_map(const flutter::EncodableMap& value_arg); + bool operator==(const AllTypes& other) const; + bool operator!=(const AllTypes& other) const; + /// Returns a hash code value for the object. This method is supported for the + /// benefit of hash tables. + size_t Hash() const; private: - static AllTypes FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static AllTypes FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class AllClassesWrapper; friend class HostIntegrationCoreApi; friend class FlutterIntegrationCoreApi; @@ -238,23 +250,23 @@ class AllTypes { AnEnum an_enum_; AnotherEnum another_enum_; std::string a_string_; - flutter::EncodableValue an_object_; - flutter::EncodableList list_; - flutter::EncodableList string_list_; - flutter::EncodableList int_list_; - flutter::EncodableList double_list_; - flutter::EncodableList bool_list_; - flutter::EncodableList enum_list_; - flutter::EncodableList object_list_; - flutter::EncodableList list_list_; - flutter::EncodableList map_list_; - flutter::EncodableMap map_; - flutter::EncodableMap string_map_; - flutter::EncodableMap int_map_; - flutter::EncodableMap enum_map_; - flutter::EncodableMap object_map_; - flutter::EncodableMap list_map_; - flutter::EncodableMap map_map_; + ::flutter::EncodableValue an_object_; + ::flutter::EncodableList list_; + ::flutter::EncodableList string_list_; + ::flutter::EncodableList int_list_; + ::flutter::EncodableList double_list_; + ::flutter::EncodableList bool_list_; + ::flutter::EncodableList enum_list_; + ::flutter::EncodableList object_list_; + ::flutter::EncodableList list_list_; + ::flutter::EncodableList map_list_; + ::flutter::EncodableMap map_; + ::flutter::EncodableMap string_map_; + ::flutter::EncodableMap int_map_; + ::flutter::EncodableMap enum_map_; + ::flutter::EncodableMap object_map_; + ::flutter::EncodableMap list_map_; + ::flutter::EncodableMap map_map_; }; // A class containing all supported nullable types. @@ -275,25 +287,26 @@ class AllNullableTypes { const std::vector* a_nullable_float_array, const AnEnum* a_nullable_enum, const AnotherEnum* another_nullable_enum, const std::string* a_nullable_string, - const flutter::EncodableValue* a_nullable_object, + const ::flutter::EncodableValue* a_nullable_object, const AllNullableTypes* all_nullable_types, - const flutter::EncodableList* list, - const flutter::EncodableList* string_list, - const flutter::EncodableList* int_list, - const flutter::EncodableList* double_list, - const flutter::EncodableList* bool_list, - const flutter::EncodableList* enum_list, - const flutter::EncodableList* object_list, - const flutter::EncodableList* list_list, - const flutter::EncodableList* map_list, - const flutter::EncodableList* recursive_class_list, - const flutter::EncodableMap* map, const flutter::EncodableMap* string_map, - const flutter::EncodableMap* int_map, - const flutter::EncodableMap* enum_map, - const flutter::EncodableMap* object_map, - const flutter::EncodableMap* list_map, - const flutter::EncodableMap* map_map, - const flutter::EncodableMap* recursive_class_map); + const ::flutter::EncodableList* list, + const ::flutter::EncodableList* string_list, + const ::flutter::EncodableList* int_list, + const ::flutter::EncodableList* double_list, + const ::flutter::EncodableList* bool_list, + const ::flutter::EncodableList* enum_list, + const ::flutter::EncodableList* object_list, + const ::flutter::EncodableList* list_list, + const ::flutter::EncodableList* map_list, + const ::flutter::EncodableList* recursive_class_list, + const ::flutter::EncodableMap* map, + const ::flutter::EncodableMap* string_map, + const ::flutter::EncodableMap* int_map, + const ::flutter::EncodableMap* enum_map, + const ::flutter::EncodableMap* object_map, + const ::flutter::EncodableMap* list_map, + const ::flutter::EncodableMap* map_map, + const ::flutter::EncodableMap* recursive_class_map); ~AllNullableTypes() = default; AllNullableTypes(const AllNullableTypes& other); @@ -344,89 +357,96 @@ class AllNullableTypes { void set_a_nullable_string(const std::string_view* value_arg); void set_a_nullable_string(std::string_view value_arg); - const flutter::EncodableValue* a_nullable_object() const; - void set_a_nullable_object(const flutter::EncodableValue* value_arg); - void set_a_nullable_object(const flutter::EncodableValue& value_arg); + const ::flutter::EncodableValue* a_nullable_object() const; + void set_a_nullable_object(const ::flutter::EncodableValue* value_arg); + void set_a_nullable_object(const ::flutter::EncodableValue& value_arg); const AllNullableTypes* all_nullable_types() const; void set_all_nullable_types(const AllNullableTypes* value_arg); void set_all_nullable_types(const AllNullableTypes& value_arg); - const flutter::EncodableList* list() const; - void set_list(const flutter::EncodableList* value_arg); - void set_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* list() const; + void set_list(const ::flutter::EncodableList* value_arg); + void set_list(const ::flutter::EncodableList& value_arg); + + const ::flutter::EncodableList* string_list() const; + void set_string_list(const ::flutter::EncodableList* value_arg); + void set_string_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* string_list() const; - void set_string_list(const flutter::EncodableList* value_arg); - void set_string_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* int_list() const; + void set_int_list(const ::flutter::EncodableList* value_arg); + void set_int_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* int_list() const; - void set_int_list(const flutter::EncodableList* value_arg); - void set_int_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* double_list() const; + void set_double_list(const ::flutter::EncodableList* value_arg); + void set_double_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* double_list() const; - void set_double_list(const flutter::EncodableList* value_arg); - void set_double_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* bool_list() const; + void set_bool_list(const ::flutter::EncodableList* value_arg); + void set_bool_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* bool_list() const; - void set_bool_list(const flutter::EncodableList* value_arg); - void set_bool_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* enum_list() const; + void set_enum_list(const ::flutter::EncodableList* value_arg); + void set_enum_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* enum_list() const; - void set_enum_list(const flutter::EncodableList* value_arg); - void set_enum_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* object_list() const; + void set_object_list(const ::flutter::EncodableList* value_arg); + void set_object_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* object_list() const; - void set_object_list(const flutter::EncodableList* value_arg); - void set_object_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* list_list() const; + void set_list_list(const ::flutter::EncodableList* value_arg); + void set_list_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* list_list() const; - void set_list_list(const flutter::EncodableList* value_arg); - void set_list_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* map_list() const; + void set_map_list(const ::flutter::EncodableList* value_arg); + void set_map_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* map_list() const; - void set_map_list(const flutter::EncodableList* value_arg); - void set_map_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* recursive_class_list() const; + void set_recursive_class_list(const ::flutter::EncodableList* value_arg); + void set_recursive_class_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* recursive_class_list() const; - void set_recursive_class_list(const flutter::EncodableList* value_arg); - void set_recursive_class_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableMap* map() const; + void set_map(const ::flutter::EncodableMap* value_arg); + void set_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* map() const; - void set_map(const flutter::EncodableMap* value_arg); - void set_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* string_map() const; + void set_string_map(const ::flutter::EncodableMap* value_arg); + void set_string_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* string_map() const; - void set_string_map(const flutter::EncodableMap* value_arg); - void set_string_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* int_map() const; + void set_int_map(const ::flutter::EncodableMap* value_arg); + void set_int_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* int_map() const; - void set_int_map(const flutter::EncodableMap* value_arg); - void set_int_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* enum_map() const; + void set_enum_map(const ::flutter::EncodableMap* value_arg); + void set_enum_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* enum_map() const; - void set_enum_map(const flutter::EncodableMap* value_arg); - void set_enum_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* object_map() const; + void set_object_map(const ::flutter::EncodableMap* value_arg); + void set_object_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* object_map() const; - void set_object_map(const flutter::EncodableMap* value_arg); - void set_object_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* list_map() const; + void set_list_map(const ::flutter::EncodableMap* value_arg); + void set_list_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* list_map() const; - void set_list_map(const flutter::EncodableMap* value_arg); - void set_list_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* map_map() const; + void set_map_map(const ::flutter::EncodableMap* value_arg); + void set_map_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* map_map() const; - void set_map_map(const flutter::EncodableMap* value_arg); - void set_map_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* recursive_class_map() const; + void set_recursive_class_map(const ::flutter::EncodableMap* value_arg); + void set_recursive_class_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* recursive_class_map() const; - void set_recursive_class_map(const flutter::EncodableMap* value_arg); - void set_recursive_class_map(const flutter::EncodableMap& value_arg); + bool operator==(const AllNullableTypes& other) const; + bool operator!=(const AllNullableTypes& other) const; + /// Returns a hash code value for the object. This method is supported for the + /// benefit of hash tables. + size_t Hash() const; private: - static AllNullableTypes FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static AllNullableTypes FromEncodableList( + const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class AllClassesWrapper; friend class HostIntegrationCoreApi; friend class FlutterIntegrationCoreApi; @@ -446,26 +466,26 @@ class AllNullableTypes { std::optional a_nullable_enum_; std::optional another_nullable_enum_; std::optional a_nullable_string_; - std::optional a_nullable_object_; + std::optional<::flutter::EncodableValue> a_nullable_object_; std::unique_ptr all_nullable_types_; - std::optional list_; - std::optional string_list_; - std::optional int_list_; - std::optional double_list_; - std::optional bool_list_; - std::optional enum_list_; - std::optional object_list_; - std::optional list_list_; - std::optional map_list_; - std::optional recursive_class_list_; - std::optional map_; - std::optional string_map_; - std::optional int_map_; - std::optional enum_map_; - std::optional object_map_; - std::optional list_map_; - std::optional map_map_; - std::optional recursive_class_map_; + std::optional<::flutter::EncodableList> list_; + std::optional<::flutter::EncodableList> string_list_; + std::optional<::flutter::EncodableList> int_list_; + std::optional<::flutter::EncodableList> double_list_; + std::optional<::flutter::EncodableList> bool_list_; + std::optional<::flutter::EncodableList> enum_list_; + std::optional<::flutter::EncodableList> object_list_; + std::optional<::flutter::EncodableList> list_list_; + std::optional<::flutter::EncodableList> map_list_; + std::optional<::flutter::EncodableList> recursive_class_list_; + std::optional<::flutter::EncodableMap> map_; + std::optional<::flutter::EncodableMap> string_map_; + std::optional<::flutter::EncodableMap> int_map_; + std::optional<::flutter::EncodableMap> enum_map_; + std::optional<::flutter::EncodableMap> object_map_; + std::optional<::flutter::EncodableMap> list_map_; + std::optional<::flutter::EncodableMap> map_map_; + std::optional<::flutter::EncodableMap> recursive_class_map_; }; // The primary purpose for this class is to ensure coverage of Swift structs @@ -488,22 +508,23 @@ class AllNullableTypesWithoutRecursion { const std::vector* a_nullable_float_array, const AnEnum* a_nullable_enum, const AnotherEnum* another_nullable_enum, const std::string* a_nullable_string, - const flutter::EncodableValue* a_nullable_object, - const flutter::EncodableList* list, - const flutter::EncodableList* string_list, - const flutter::EncodableList* int_list, - const flutter::EncodableList* double_list, - const flutter::EncodableList* bool_list, - const flutter::EncodableList* enum_list, - const flutter::EncodableList* object_list, - const flutter::EncodableList* list_list, - const flutter::EncodableList* map_list, const flutter::EncodableMap* map, - const flutter::EncodableMap* string_map, - const flutter::EncodableMap* int_map, - const flutter::EncodableMap* enum_map, - const flutter::EncodableMap* object_map, - const flutter::EncodableMap* list_map, - const flutter::EncodableMap* map_map); + const ::flutter::EncodableValue* a_nullable_object, + const ::flutter::EncodableList* list, + const ::flutter::EncodableList* string_list, + const ::flutter::EncodableList* int_list, + const ::flutter::EncodableList* double_list, + const ::flutter::EncodableList* bool_list, + const ::flutter::EncodableList* enum_list, + const ::flutter::EncodableList* object_list, + const ::flutter::EncodableList* list_list, + const ::flutter::EncodableList* map_list, + const ::flutter::EncodableMap* map, + const ::flutter::EncodableMap* string_map, + const ::flutter::EncodableMap* int_map, + const ::flutter::EncodableMap* enum_map, + const ::flutter::EncodableMap* object_map, + const ::flutter::EncodableMap* list_map, + const ::flutter::EncodableMap* map_map); const bool* a_nullable_bool() const; void set_a_nullable_bool(const bool* value_arg); @@ -549,78 +570,84 @@ class AllNullableTypesWithoutRecursion { void set_a_nullable_string(const std::string_view* value_arg); void set_a_nullable_string(std::string_view value_arg); - const flutter::EncodableValue* a_nullable_object() const; - void set_a_nullable_object(const flutter::EncodableValue* value_arg); - void set_a_nullable_object(const flutter::EncodableValue& value_arg); + const ::flutter::EncodableValue* a_nullable_object() const; + void set_a_nullable_object(const ::flutter::EncodableValue* value_arg); + void set_a_nullable_object(const ::flutter::EncodableValue& value_arg); - const flutter::EncodableList* list() const; - void set_list(const flutter::EncodableList* value_arg); - void set_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* list() const; + void set_list(const ::flutter::EncodableList* value_arg); + void set_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* string_list() const; - void set_string_list(const flutter::EncodableList* value_arg); - void set_string_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* string_list() const; + void set_string_list(const ::flutter::EncodableList* value_arg); + void set_string_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* int_list() const; - void set_int_list(const flutter::EncodableList* value_arg); - void set_int_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* int_list() const; + void set_int_list(const ::flutter::EncodableList* value_arg); + void set_int_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* double_list() const; - void set_double_list(const flutter::EncodableList* value_arg); - void set_double_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* double_list() const; + void set_double_list(const ::flutter::EncodableList* value_arg); + void set_double_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* bool_list() const; - void set_bool_list(const flutter::EncodableList* value_arg); - void set_bool_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* bool_list() const; + void set_bool_list(const ::flutter::EncodableList* value_arg); + void set_bool_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* enum_list() const; - void set_enum_list(const flutter::EncodableList* value_arg); - void set_enum_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* enum_list() const; + void set_enum_list(const ::flutter::EncodableList* value_arg); + void set_enum_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* object_list() const; - void set_object_list(const flutter::EncodableList* value_arg); - void set_object_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* object_list() const; + void set_object_list(const ::flutter::EncodableList* value_arg); + void set_object_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* list_list() const; - void set_list_list(const flutter::EncodableList* value_arg); - void set_list_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* list_list() const; + void set_list_list(const ::flutter::EncodableList* value_arg); + void set_list_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* map_list() const; - void set_map_list(const flutter::EncodableList* value_arg); - void set_map_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* map_list() const; + void set_map_list(const ::flutter::EncodableList* value_arg); + void set_map_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableMap* map() const; - void set_map(const flutter::EncodableMap* value_arg); - void set_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* map() const; + void set_map(const ::flutter::EncodableMap* value_arg); + void set_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* string_map() const; - void set_string_map(const flutter::EncodableMap* value_arg); - void set_string_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* string_map() const; + void set_string_map(const ::flutter::EncodableMap* value_arg); + void set_string_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* int_map() const; - void set_int_map(const flutter::EncodableMap* value_arg); - void set_int_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* int_map() const; + void set_int_map(const ::flutter::EncodableMap* value_arg); + void set_int_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* enum_map() const; - void set_enum_map(const flutter::EncodableMap* value_arg); - void set_enum_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* enum_map() const; + void set_enum_map(const ::flutter::EncodableMap* value_arg); + void set_enum_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* object_map() const; - void set_object_map(const flutter::EncodableMap* value_arg); - void set_object_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* object_map() const; + void set_object_map(const ::flutter::EncodableMap* value_arg); + void set_object_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* list_map() const; - void set_list_map(const flutter::EncodableMap* value_arg); - void set_list_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* list_map() const; + void set_list_map(const ::flutter::EncodableMap* value_arg); + void set_list_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* map_map() const; - void set_map_map(const flutter::EncodableMap* value_arg); - void set_map_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* map_map() const; + void set_map_map(const ::flutter::EncodableMap* value_arg); + void set_map_map(const ::flutter::EncodableMap& value_arg); + + bool operator==(const AllNullableTypesWithoutRecursion& other) const; + bool operator!=(const AllNullableTypesWithoutRecursion& other) const; + /// Returns a hash code value for the object. This method is supported for the + /// benefit of hash tables. + size_t Hash() const; private: static AllNullableTypesWithoutRecursion FromEncodableList( - const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class AllClassesWrapper; friend class HostIntegrationCoreApi; friend class FlutterIntegrationCoreApi; @@ -640,23 +667,23 @@ class AllNullableTypesWithoutRecursion { std::optional a_nullable_enum_; std::optional another_nullable_enum_; std::optional a_nullable_string_; - std::optional a_nullable_object_; - std::optional list_; - std::optional string_list_; - std::optional int_list_; - std::optional double_list_; - std::optional bool_list_; - std::optional enum_list_; - std::optional object_list_; - std::optional list_list_; - std::optional map_list_; - std::optional map_; - std::optional string_map_; - std::optional int_map_; - std::optional enum_map_; - std::optional object_map_; - std::optional list_map_; - std::optional map_map_; + std::optional<::flutter::EncodableValue> a_nullable_object_; + std::optional<::flutter::EncodableList> list_; + std::optional<::flutter::EncodableList> string_list_; + std::optional<::flutter::EncodableList> int_list_; + std::optional<::flutter::EncodableList> double_list_; + std::optional<::flutter::EncodableList> bool_list_; + std::optional<::flutter::EncodableList> enum_list_; + std::optional<::flutter::EncodableList> object_list_; + std::optional<::flutter::EncodableList> list_list_; + std::optional<::flutter::EncodableList> map_list_; + std::optional<::flutter::EncodableMap> map_; + std::optional<::flutter::EncodableMap> string_map_; + std::optional<::flutter::EncodableMap> int_map_; + std::optional<::flutter::EncodableMap> enum_map_; + std::optional<::flutter::EncodableMap> object_map_; + std::optional<::flutter::EncodableMap> list_map_; + std::optional<::flutter::EncodableMap> map_map_; }; // A class for testing nested class handling. @@ -670,18 +697,18 @@ class AllClassesWrapper { public: // Constructs an object setting all non-nullable fields. explicit AllClassesWrapper(const AllNullableTypes& all_nullable_types, - const flutter::EncodableList& class_list, - const flutter::EncodableMap& class_map); + const ::flutter::EncodableList& class_list, + const ::flutter::EncodableMap& class_map); // Constructs an object setting all fields. - explicit AllClassesWrapper(const AllNullableTypes& all_nullable_types, - const AllNullableTypesWithoutRecursion* - all_nullable_types_without_recursion, - const AllTypes* all_types, - const flutter::EncodableList& class_list, - const flutter::EncodableList* nullable_class_list, - const flutter::EncodableMap& class_map, - const flutter::EncodableMap* nullable_class_map); + explicit AllClassesWrapper( + const AllNullableTypes& all_nullable_types, + const AllNullableTypesWithoutRecursion* + all_nullable_types_without_recursion, + const AllTypes* all_types, const ::flutter::EncodableList& class_list, + const ::flutter::EncodableList* nullable_class_list, + const ::flutter::EncodableMap& class_map, + const ::flutter::EncodableMap* nullable_class_map); ~AllClassesWrapper() = default; AllClassesWrapper(const AllClassesWrapper& other); @@ -702,24 +729,30 @@ class AllClassesWrapper { void set_all_types(const AllTypes* value_arg); void set_all_types(const AllTypes& value_arg); - const flutter::EncodableList& class_list() const; - void set_class_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& class_list() const; + void set_class_list(const ::flutter::EncodableList& value_arg); + + const ::flutter::EncodableList* nullable_class_list() const; + void set_nullable_class_list(const ::flutter::EncodableList* value_arg); + void set_nullable_class_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* nullable_class_list() const; - void set_nullable_class_list(const flutter::EncodableList* value_arg); - void set_nullable_class_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableMap& class_map() const; + void set_class_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap& class_map() const; - void set_class_map(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* nullable_class_map() const; + void set_nullable_class_map(const ::flutter::EncodableMap* value_arg); + void set_nullable_class_map(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableMap* nullable_class_map() const; - void set_nullable_class_map(const flutter::EncodableMap* value_arg); - void set_nullable_class_map(const flutter::EncodableMap& value_arg); + bool operator==(const AllClassesWrapper& other) const; + bool operator!=(const AllClassesWrapper& other) const; + /// Returns a hash code value for the object. This method is supported for the + /// benefit of hash tables. + size_t Hash() const; private: static AllClassesWrapper FromEncodableList( - const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class HostIntegrationCoreApi; friend class FlutterIntegrationCoreApi; friend class HostTrivialApi; @@ -731,10 +764,10 @@ class AllClassesWrapper { std::unique_ptr all_nullable_types_without_recursion_; std::unique_ptr all_types_; - flutter::EncodableList class_list_; - std::optional nullable_class_list_; - flutter::EncodableMap class_map_; - std::optional nullable_class_map_; + ::flutter::EncodableList class_list_; + std::optional<::flutter::EncodableList> nullable_class_list_; + ::flutter::EncodableMap class_map_; + std::optional<::flutter::EncodableMap> nullable_class_map_; }; // A data class containing a List, used in unit tests. @@ -746,15 +779,21 @@ class TestMessage { TestMessage(); // Constructs an object setting all fields. - explicit TestMessage(const flutter::EncodableList* test_list); + explicit TestMessage(const ::flutter::EncodableList* test_list); - const flutter::EncodableList* test_list() const; - void set_test_list(const flutter::EncodableList* value_arg); - void set_test_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* test_list() const; + void set_test_list(const ::flutter::EncodableList* value_arg); + void set_test_list(const ::flutter::EncodableList& value_arg); + + bool operator==(const TestMessage& other) const; + bool operator!=(const TestMessage& other) const; + /// Returns a hash code value for the object. This method is supported for the + /// benefit of hash tables. + size_t Hash() const; private: - static TestMessage FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static TestMessage FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class HostIntegrationCoreApi; friend class FlutterIntegrationCoreApi; friend class HostTrivialApi; @@ -762,10 +801,11 @@ class TestMessage { friend class FlutterSmallApi; friend class PigeonInternalCodecSerializer; friend class CoreTestsTest; - std::optional test_list_; + std::optional<::flutter::EncodableList> test_list_; }; -class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer { +class PigeonInternalCodecSerializer + : public ::flutter::StandardCodecSerializer { public: PigeonInternalCodecSerializer(); inline static PigeonInternalCodecSerializer& GetInstance() { @@ -773,12 +813,12 @@ class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer { return sInstance; } - void WriteValue(const flutter::EncodableValue& value, - flutter::ByteStreamWriter* stream) const override; + void WriteValue(const ::flutter::EncodableValue& value, + ::flutter::ByteStreamWriter* stream) const override; protected: - flutter::EncodableValue ReadValueOfType( - uint8_t type, flutter::ByteStreamReader* stream) const override; + ::flutter::EncodableValue ReadValueOfType( + uint8_t type, ::flutter::ByteStreamReader* stream) const override; }; // The core interface that each host language plugin must implement in @@ -797,11 +837,11 @@ class HostIntegrationCoreApi { // Returns the passed object, to test serialization and deserialization. virtual ErrorOr EchoAllTypes(const AllTypes& everything) = 0; // Returns an error, to test error handling. - virtual ErrorOr> ThrowError() = 0; + virtual ErrorOr> ThrowError() = 0; // Returns an error from a void function, to test error handling. virtual std::optional ThrowErrorFromVoid() = 0; // Returns a Flutter error, to test error handling. - virtual ErrorOr> + virtual ErrorOr> ThrowFlutterError() = 0; // Returns passed in int. virtual ErrorOr EchoInt(int64_t an_int) = 0; @@ -815,50 +855,50 @@ class HostIntegrationCoreApi { virtual ErrorOr> EchoUint8List( const std::vector& a_uint8_list) = 0; // Returns the passed in generic Object. - virtual ErrorOr EchoObject( - const flutter::EncodableValue& an_object) = 0; + virtual ErrorOr<::flutter::EncodableValue> EchoObject( + const ::flutter::EncodableValue& an_object) = 0; // Returns the passed list, to test serialization and deserialization. - virtual ErrorOr EchoList( - const flutter::EncodableList& list) = 0; + virtual ErrorOr<::flutter::EncodableList> EchoList( + const ::flutter::EncodableList& list) = 0; // Returns the passed list, to test serialization and deserialization. - virtual ErrorOr EchoEnumList( - const flutter::EncodableList& enum_list) = 0; + virtual ErrorOr<::flutter::EncodableList> EchoEnumList( + const ::flutter::EncodableList& enum_list) = 0; // Returns the passed list, to test serialization and deserialization. - virtual ErrorOr EchoClassList( - const flutter::EncodableList& class_list) = 0; + virtual ErrorOr<::flutter::EncodableList> EchoClassList( + const ::flutter::EncodableList& class_list) = 0; // Returns the passed list, to test serialization and deserialization. - virtual ErrorOr EchoNonNullEnumList( - const flutter::EncodableList& enum_list) = 0; + virtual ErrorOr<::flutter::EncodableList> EchoNonNullEnumList( + const ::flutter::EncodableList& enum_list) = 0; // Returns the passed list, to test serialization and deserialization. - virtual ErrorOr EchoNonNullClassList( - const flutter::EncodableList& class_list) = 0; + virtual ErrorOr<::flutter::EncodableList> EchoNonNullClassList( + const ::flutter::EncodableList& class_list) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr EchoMap( - const flutter::EncodableMap& map) = 0; + virtual ErrorOr<::flutter::EncodableMap> EchoMap( + const ::flutter::EncodableMap& map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr EchoStringMap( - const flutter::EncodableMap& string_map) = 0; + virtual ErrorOr<::flutter::EncodableMap> EchoStringMap( + const ::flutter::EncodableMap& string_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr EchoIntMap( - const flutter::EncodableMap& int_map) = 0; + virtual ErrorOr<::flutter::EncodableMap> EchoIntMap( + const ::flutter::EncodableMap& int_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr EchoEnumMap( - const flutter::EncodableMap& enum_map) = 0; + virtual ErrorOr<::flutter::EncodableMap> EchoEnumMap( + const ::flutter::EncodableMap& enum_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr EchoClassMap( - const flutter::EncodableMap& class_map) = 0; + virtual ErrorOr<::flutter::EncodableMap> EchoClassMap( + const ::flutter::EncodableMap& class_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr EchoNonNullStringMap( - const flutter::EncodableMap& string_map) = 0; + virtual ErrorOr<::flutter::EncodableMap> EchoNonNullStringMap( + const ::flutter::EncodableMap& string_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr EchoNonNullIntMap( - const flutter::EncodableMap& int_map) = 0; + virtual ErrorOr<::flutter::EncodableMap> EchoNonNullIntMap( + const ::flutter::EncodableMap& int_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr EchoNonNullEnumMap( - const flutter::EncodableMap& enum_map) = 0; + virtual ErrorOr<::flutter::EncodableMap> EchoNonNullEnumMap( + const ::flutter::EncodableMap& enum_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr EchoNonNullClassMap( - const flutter::EncodableMap& class_map) = 0; + virtual ErrorOr<::flutter::EncodableMap> EchoNonNullClassMap( + const ::flutter::EncodableMap& class_map) = 0; // Returns the passed class to test nested class serialization and // deserialization. virtual ErrorOr EchoClassWrapper( @@ -875,6 +915,15 @@ class HostIntegrationCoreApi { virtual ErrorOr EchoOptionalDefaultDouble(double a_double) = 0; // Returns passed in int. virtual ErrorOr EchoRequiredInt(int64_t an_int) = 0; + // Returns the result of platform-side equality check. + virtual ErrorOr AreAllNullableTypesEqual(const AllNullableTypes& a, + const AllNullableTypes& b) = 0; + // Returns the platform-side hash code for the given object. + virtual ErrorOr GetAllNullableTypesHash( + const AllNullableTypes& value) = 0; + // Returns the platform-side hash code for the given object. + virtual ErrorOr GetAllNullableTypesWithoutRecursionHash( + const AllNullableTypesWithoutRecursion& value) = 0; // Returns the passed object, to test serialization and deserialization. virtual ErrorOr> EchoAllNullableTypes( const AllNullableTypes* everything) = 0; @@ -915,50 +964,50 @@ class HostIntegrationCoreApi { virtual ErrorOr>> EchoNullableUint8List( const std::vector* a_nullable_uint8_list) = 0; // Returns the passed in generic Object. - virtual ErrorOr> EchoNullableObject( - const flutter::EncodableValue* a_nullable_object) = 0; + virtual ErrorOr> EchoNullableObject( + const ::flutter::EncodableValue* a_nullable_object) = 0; // Returns the passed list, to test serialization and deserialization. - virtual ErrorOr> EchoNullableList( - const flutter::EncodableList* a_nullable_list) = 0; + virtual ErrorOr> EchoNullableList( + const ::flutter::EncodableList* a_nullable_list) = 0; // Returns the passed list, to test serialization and deserialization. - virtual ErrorOr> EchoNullableEnumList( - const flutter::EncodableList* enum_list) = 0; + virtual ErrorOr> EchoNullableEnumList( + const ::flutter::EncodableList* enum_list) = 0; // Returns the passed list, to test serialization and deserialization. - virtual ErrorOr> EchoNullableClassList( - const flutter::EncodableList* class_list) = 0; + virtual ErrorOr> + EchoNullableClassList(const ::flutter::EncodableList* class_list) = 0; // Returns the passed list, to test serialization and deserialization. - virtual ErrorOr> - EchoNullableNonNullEnumList(const flutter::EncodableList* enum_list) = 0; + virtual ErrorOr> + EchoNullableNonNullEnumList(const ::flutter::EncodableList* enum_list) = 0; // Returns the passed list, to test serialization and deserialization. - virtual ErrorOr> - EchoNullableNonNullClassList(const flutter::EncodableList* class_list) = 0; + virtual ErrorOr> + EchoNullableNonNullClassList(const ::flutter::EncodableList* class_list) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr> EchoNullableMap( - const flutter::EncodableMap* map) = 0; + virtual ErrorOr> EchoNullableMap( + const ::flutter::EncodableMap* map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr> EchoNullableStringMap( - const flutter::EncodableMap* string_map) = 0; + virtual ErrorOr> EchoNullableStringMap( + const ::flutter::EncodableMap* string_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr> EchoNullableIntMap( - const flutter::EncodableMap* int_map) = 0; + virtual ErrorOr> EchoNullableIntMap( + const ::flutter::EncodableMap* int_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr> EchoNullableEnumMap( - const flutter::EncodableMap* enum_map) = 0; + virtual ErrorOr> EchoNullableEnumMap( + const ::flutter::EncodableMap* enum_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr> EchoNullableClassMap( - const flutter::EncodableMap* class_map) = 0; + virtual ErrorOr> EchoNullableClassMap( + const ::flutter::EncodableMap* class_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr> - EchoNullableNonNullStringMap(const flutter::EncodableMap* string_map) = 0; + virtual ErrorOr> + EchoNullableNonNullStringMap(const ::flutter::EncodableMap* string_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr> - EchoNullableNonNullIntMap(const flutter::EncodableMap* int_map) = 0; + virtual ErrorOr> + EchoNullableNonNullIntMap(const ::flutter::EncodableMap* int_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr> - EchoNullableNonNullEnumMap(const flutter::EncodableMap* enum_map) = 0; + virtual ErrorOr> + EchoNullableNonNullEnumMap(const ::flutter::EncodableMap* enum_map) = 0; // Returns the passed map, to test serialization and deserialization. - virtual ErrorOr> - EchoNullableNonNullClassMap(const flutter::EncodableMap* class_map) = 0; + virtual ErrorOr> + EchoNullableNonNullClassMap(const ::flutter::EncodableMap* class_map) = 0; virtual ErrorOr> EchoNullableEnum( const AnEnum* an_enum) = 0; virtual ErrorOr> EchoAnotherNullableEnum( @@ -992,48 +1041,48 @@ class HostIntegrationCoreApi { std::function> reply)> result) = 0; // Returns the passed in generic Object asynchronously. virtual void EchoAsyncObject( - const flutter::EncodableValue& an_object, - std::function reply)> result) = 0; + const ::flutter::EncodableValue& an_object, + std::function reply)> result) = 0; // Returns the passed list, to test asynchronous serialization and // deserialization. virtual void EchoAsyncList( - const flutter::EncodableList& list, - std::function reply)> result) = 0; + const ::flutter::EncodableList& list, + std::function reply)> result) = 0; // Returns the passed list, to test asynchronous serialization and // deserialization. virtual void EchoAsyncEnumList( - const flutter::EncodableList& enum_list, - std::function reply)> result) = 0; + const ::flutter::EncodableList& enum_list, + std::function reply)> result) = 0; // Returns the passed list, to test asynchronous serialization and // deserialization. virtual void EchoAsyncClassList( - const flutter::EncodableList& class_list, - std::function reply)> result) = 0; + const ::flutter::EncodableList& class_list, + std::function reply)> result) = 0; // Returns the passed map, to test asynchronous serialization and // deserialization. virtual void EchoAsyncMap( - const flutter::EncodableMap& map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& map, + std::function reply)> result) = 0; // Returns the passed map, to test asynchronous serialization and // deserialization. virtual void EchoAsyncStringMap( - const flutter::EncodableMap& string_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& string_map, + std::function reply)> result) = 0; // Returns the passed map, to test asynchronous serialization and // deserialization. virtual void EchoAsyncIntMap( - const flutter::EncodableMap& int_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& int_map, + std::function reply)> result) = 0; // Returns the passed map, to test asynchronous serialization and // deserialization. virtual void EchoAsyncEnumMap( - const flutter::EncodableMap& enum_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& enum_map, + std::function reply)> result) = 0; // Returns the passed map, to test asynchronous serialization and // deserialization. virtual void EchoAsyncClassMap( - const flutter::EncodableMap& class_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& class_map, + std::function reply)> result) = 0; // Returns the passed enum, to test asynchronous serialization and // deserialization. virtual void EchoAsyncEnum( @@ -1046,14 +1095,16 @@ class HostIntegrationCoreApi { std::function reply)> result) = 0; // Responds with an error from an async function returning a value. virtual void ThrowAsyncError( - std::function> reply)> + std::function< + void(ErrorOr> reply)> result) = 0; // Responds with an error from an async void function. virtual void ThrowAsyncErrorFromVoid( std::function reply)> result) = 0; // Responds with a Flutter error from an async function returning a value. virtual void ThrowAsyncFlutterError( - std::function> reply)> + std::function< + void(ErrorOr> reply)> result) = 0; // Returns the passed object, to test async serialization and deserialization. virtual void EchoAsyncAllTypes( @@ -1094,56 +1145,60 @@ class HostIntegrationCoreApi { result) = 0; // Returns the passed in generic Object asynchronously. virtual void EchoAsyncNullableObject( - const flutter::EncodableValue* an_object, - std::function> reply)> + const ::flutter::EncodableValue* an_object, + std::function< + void(ErrorOr> reply)> result) = 0; // Returns the passed list, to test asynchronous serialization and // deserialization. virtual void EchoAsyncNullableList( - const flutter::EncodableList* list, - std::function> reply)> + const ::flutter::EncodableList* list, + std::function< + void(ErrorOr> reply)> result) = 0; // Returns the passed list, to test asynchronous serialization and // deserialization. virtual void EchoAsyncNullableEnumList( - const flutter::EncodableList* enum_list, - std::function> reply)> + const ::flutter::EncodableList* enum_list, + std::function< + void(ErrorOr> reply)> result) = 0; // Returns the passed list, to test asynchronous serialization and // deserialization. virtual void EchoAsyncNullableClassList( - const flutter::EncodableList* class_list, - std::function> reply)> + const ::flutter::EncodableList* class_list, + std::function< + void(ErrorOr> reply)> result) = 0; // Returns the passed map, to test asynchronous serialization and // deserialization. virtual void EchoAsyncNullableMap( - const flutter::EncodableMap* map, - std::function> reply)> + const ::flutter::EncodableMap* map, + std::function> reply)> result) = 0; // Returns the passed map, to test asynchronous serialization and // deserialization. virtual void EchoAsyncNullableStringMap( - const flutter::EncodableMap* string_map, - std::function> reply)> + const ::flutter::EncodableMap* string_map, + std::function> reply)> result) = 0; // Returns the passed map, to test asynchronous serialization and // deserialization. virtual void EchoAsyncNullableIntMap( - const flutter::EncodableMap* int_map, - std::function> reply)> + const ::flutter::EncodableMap* int_map, + std::function> reply)> result) = 0; // Returns the passed map, to test asynchronous serialization and // deserialization. virtual void EchoAsyncNullableEnumMap( - const flutter::EncodableMap* enum_map, - std::function> reply)> + const ::flutter::EncodableMap* enum_map, + std::function> reply)> result) = 0; // Returns the passed map, to test asynchronous serialization and // deserialization. virtual void EchoAsyncNullableClassMap( - const flutter::EncodableMap* class_map, - std::function> reply)> + const ::flutter::EncodableMap* class_map, + std::function> reply)> result) = 0; // Returns the passed enum, to test asynchronous serialization and // deserialization. @@ -1165,7 +1220,8 @@ class HostIntegrationCoreApi { virtual void CallFlutterNoop( std::function reply)> result) = 0; virtual void CallFlutterThrowError( - std::function> reply)> + std::function< + void(ErrorOr> reply)> result) = 0; virtual void CallFlutterThrowErrorFromVoid( std::function reply)> result) = 0; @@ -1203,47 +1259,47 @@ class HostIntegrationCoreApi { const std::vector& list, std::function> reply)> result) = 0; virtual void CallFlutterEchoList( - const flutter::EncodableList& list, - std::function reply)> result) = 0; + const ::flutter::EncodableList& list, + std::function reply)> result) = 0; virtual void CallFlutterEchoEnumList( - const flutter::EncodableList& enum_list, - std::function reply)> result) = 0; + const ::flutter::EncodableList& enum_list, + std::function reply)> result) = 0; virtual void CallFlutterEchoClassList( - const flutter::EncodableList& class_list, - std::function reply)> result) = 0; + const ::flutter::EncodableList& class_list, + std::function reply)> result) = 0; virtual void CallFlutterEchoNonNullEnumList( - const flutter::EncodableList& enum_list, - std::function reply)> result) = 0; + const ::flutter::EncodableList& enum_list, + std::function reply)> result) = 0; virtual void CallFlutterEchoNonNullClassList( - const flutter::EncodableList& class_list, - std::function reply)> result) = 0; + const ::flutter::EncodableList& class_list, + std::function reply)> result) = 0; virtual void CallFlutterEchoMap( - const flutter::EncodableMap& map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& map, + std::function reply)> result) = 0; virtual void CallFlutterEchoStringMap( - const flutter::EncodableMap& string_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& string_map, + std::function reply)> result) = 0; virtual void CallFlutterEchoIntMap( - const flutter::EncodableMap& int_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& int_map, + std::function reply)> result) = 0; virtual void CallFlutterEchoEnumMap( - const flutter::EncodableMap& enum_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& enum_map, + std::function reply)> result) = 0; virtual void CallFlutterEchoClassMap( - const flutter::EncodableMap& class_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& class_map, + std::function reply)> result) = 0; virtual void CallFlutterEchoNonNullStringMap( - const flutter::EncodableMap& string_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& string_map, + std::function reply)> result) = 0; virtual void CallFlutterEchoNonNullIntMap( - const flutter::EncodableMap& int_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& int_map, + std::function reply)> result) = 0; virtual void CallFlutterEchoNonNullEnumMap( - const flutter::EncodableMap& enum_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& enum_map, + std::function reply)> result) = 0; virtual void CallFlutterEchoNonNullClassMap( - const flutter::EncodableMap& class_map, - std::function reply)> result) = 0; + const ::flutter::EncodableMap& class_map, + std::function reply)> result) = 0; virtual void CallFlutterEchoEnum( const AnEnum& an_enum, std::function reply)> result) = 0; @@ -1268,60 +1324,65 @@ class HostIntegrationCoreApi { std::function>> reply)> result) = 0; virtual void CallFlutterEchoNullableList( - const flutter::EncodableList* list, - std::function> reply)> + const ::flutter::EncodableList* list, + std::function< + void(ErrorOr> reply)> result) = 0; virtual void CallFlutterEchoNullableEnumList( - const flutter::EncodableList* enum_list, - std::function> reply)> + const ::flutter::EncodableList* enum_list, + std::function< + void(ErrorOr> reply)> result) = 0; virtual void CallFlutterEchoNullableClassList( - const flutter::EncodableList* class_list, - std::function> reply)> + const ::flutter::EncodableList* class_list, + std::function< + void(ErrorOr> reply)> result) = 0; virtual void CallFlutterEchoNullableNonNullEnumList( - const flutter::EncodableList* enum_list, - std::function> reply)> + const ::flutter::EncodableList* enum_list, + std::function< + void(ErrorOr> reply)> result) = 0; virtual void CallFlutterEchoNullableNonNullClassList( - const flutter::EncodableList* class_list, - std::function> reply)> + const ::flutter::EncodableList* class_list, + std::function< + void(ErrorOr> reply)> result) = 0; virtual void CallFlutterEchoNullableMap( - const flutter::EncodableMap* map, - std::function> reply)> + const ::flutter::EncodableMap* map, + std::function> reply)> result) = 0; virtual void CallFlutterEchoNullableStringMap( - const flutter::EncodableMap* string_map, - std::function> reply)> + const ::flutter::EncodableMap* string_map, + std::function> reply)> result) = 0; virtual void CallFlutterEchoNullableIntMap( - const flutter::EncodableMap* int_map, - std::function> reply)> + const ::flutter::EncodableMap* int_map, + std::function> reply)> result) = 0; virtual void CallFlutterEchoNullableEnumMap( - const flutter::EncodableMap* enum_map, - std::function> reply)> + const ::flutter::EncodableMap* enum_map, + std::function> reply)> result) = 0; virtual void CallFlutterEchoNullableClassMap( - const flutter::EncodableMap* class_map, - std::function> reply)> + const ::flutter::EncodableMap* class_map, + std::function> reply)> result) = 0; virtual void CallFlutterEchoNullableNonNullStringMap( - const flutter::EncodableMap* string_map, - std::function> reply)> + const ::flutter::EncodableMap* string_map, + std::function> reply)> result) = 0; virtual void CallFlutterEchoNullableNonNullIntMap( - const flutter::EncodableMap* int_map, - std::function> reply)> + const ::flutter::EncodableMap* int_map, + std::function> reply)> result) = 0; virtual void CallFlutterEchoNullableNonNullEnumMap( - const flutter::EncodableMap* enum_map, - std::function> reply)> + const ::flutter::EncodableMap* enum_map, + std::function> reply)> result) = 0; virtual void CallFlutterEchoNullableNonNullClassMap( - const flutter::EncodableMap* class_map, - std::function> reply)> + const ::flutter::EncodableMap* class_map, + std::function> reply)> result) = 0; virtual void CallFlutterEchoNullableEnum( const AnEnum* an_enum, @@ -1335,16 +1396,16 @@ class HostIntegrationCoreApi { std::function reply)> result) = 0; // The codec used by HostIntegrationCoreApi. - static const flutter::StandardMessageCodec& GetCodec(); + static const ::flutter::StandardMessageCodec& GetCodec(); // Sets up an instance of `HostIntegrationCoreApi` to handle messages through // the `binary_messenger`. - static void SetUp(flutter::BinaryMessenger* binary_messenger, + static void SetUp(::flutter::BinaryMessenger* binary_messenger, HostIntegrationCoreApi* api); - static void SetUp(flutter::BinaryMessenger* binary_messenger, + static void SetUp(::flutter::BinaryMessenger* binary_messenger, HostIntegrationCoreApi* api, const std::string& message_channel_suffix); - static flutter::EncodableValue WrapError(std::string_view error_message); - static flutter::EncodableValue WrapError(const FlutterError& error); + static ::flutter::EncodableValue WrapError(std::string_view error_message); + static ::flutter::EncodableValue WrapError(const FlutterError& error); protected: HostIntegrationCoreApi() = default; @@ -1356,17 +1417,17 @@ class HostIntegrationCoreApi { // called from C++. class FlutterIntegrationCoreApi { public: - FlutterIntegrationCoreApi(flutter::BinaryMessenger* binary_messenger); - FlutterIntegrationCoreApi(flutter::BinaryMessenger* binary_messenger, + FlutterIntegrationCoreApi(::flutter::BinaryMessenger* binary_messenger); + FlutterIntegrationCoreApi(::flutter::BinaryMessenger* binary_messenger, const std::string& message_channel_suffix); - static const flutter::StandardMessageCodec& GetCodec(); + static const ::flutter::StandardMessageCodec& GetCodec(); // A no-op function taking no arguments and returning no value, to sanity // test basic calling. void Noop(std::function&& on_success, std::function&& on_error); // Responds with an error from an async function returning a value. void ThrowError( - std::function&& on_success, + std::function&& on_success, std::function&& on_error); // Responds with an error from an async void function. void ThrowErrorFromVoid(std::function&& on_success, @@ -1420,72 +1481,73 @@ class FlutterIntegrationCoreApi { std::function&)>&& on_success, std::function&& on_error); // Returns the passed list, to test serialization and deserialization. - void EchoList(const flutter::EncodableList& list, - std::function&& on_success, - std::function&& on_error); + void EchoList( + const ::flutter::EncodableList& list, + std::function&& on_success, + std::function&& on_error); // Returns the passed list, to test serialization and deserialization. void EchoEnumList( - const flutter::EncodableList& enum_list, - std::function&& on_success, + const ::flutter::EncodableList& enum_list, + std::function&& on_success, std::function&& on_error); // Returns the passed list, to test serialization and deserialization. void EchoClassList( - const flutter::EncodableList& class_list, - std::function&& on_success, + const ::flutter::EncodableList& class_list, + std::function&& on_success, std::function&& on_error); // Returns the passed list, to test serialization and deserialization. void EchoNonNullEnumList( - const flutter::EncodableList& enum_list, - std::function&& on_success, + const ::flutter::EncodableList& enum_list, + std::function&& on_success, std::function&& on_error); // Returns the passed list, to test serialization and deserialization. void EchoNonNullClassList( - const flutter::EncodableList& class_list, - std::function&& on_success, + const ::flutter::EncodableList& class_list, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. - void EchoMap(const flutter::EncodableMap& map, - std::function&& on_success, + void EchoMap(const ::flutter::EncodableMap& map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoStringMap( - const flutter::EncodableMap& string_map, - std::function&& on_success, + const ::flutter::EncodableMap& string_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoIntMap( - const flutter::EncodableMap& int_map, - std::function&& on_success, + const ::flutter::EncodableMap& int_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoEnumMap( - const flutter::EncodableMap& enum_map, - std::function&& on_success, + const ::flutter::EncodableMap& enum_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoClassMap( - const flutter::EncodableMap& class_map, - std::function&& on_success, + const ::flutter::EncodableMap& class_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNonNullStringMap( - const flutter::EncodableMap& string_map, - std::function&& on_success, + const ::flutter::EncodableMap& string_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNonNullIntMap( - const flutter::EncodableMap& int_map, - std::function&& on_success, + const ::flutter::EncodableMap& int_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNonNullEnumMap( - const flutter::EncodableMap& enum_map, - std::function&& on_success, + const ::flutter::EncodableMap& enum_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNonNullClassMap( - const flutter::EncodableMap& class_map, - std::function&& on_success, + const ::flutter::EncodableMap& class_map, + std::function&& on_success, std::function&& on_error); // Returns the passed enum to test serialization and deserialization. void EchoEnum(const AnEnum& an_enum, @@ -1518,73 +1580,73 @@ class FlutterIntegrationCoreApi { std::function&& on_error); // Returns the passed list, to test serialization and deserialization. void EchoNullableList( - const flutter::EncodableList* list, - std::function&& on_success, + const ::flutter::EncodableList* list, + std::function&& on_success, std::function&& on_error); // Returns the passed list, to test serialization and deserialization. void EchoNullableEnumList( - const flutter::EncodableList* enum_list, - std::function&& on_success, + const ::flutter::EncodableList* enum_list, + std::function&& on_success, std::function&& on_error); // Returns the passed list, to test serialization and deserialization. void EchoNullableClassList( - const flutter::EncodableList* class_list, - std::function&& on_success, + const ::flutter::EncodableList* class_list, + std::function&& on_success, std::function&& on_error); // Returns the passed list, to test serialization and deserialization. void EchoNullableNonNullEnumList( - const flutter::EncodableList* enum_list, - std::function&& on_success, + const ::flutter::EncodableList* enum_list, + std::function&& on_success, std::function&& on_error); // Returns the passed list, to test serialization and deserialization. void EchoNullableNonNullClassList( - const flutter::EncodableList* class_list, - std::function&& on_success, + const ::flutter::EncodableList* class_list, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNullableMap( - const flutter::EncodableMap* map, - std::function&& on_success, + const ::flutter::EncodableMap* map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNullableStringMap( - const flutter::EncodableMap* string_map, - std::function&& on_success, + const ::flutter::EncodableMap* string_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNullableIntMap( - const flutter::EncodableMap* int_map, - std::function&& on_success, + const ::flutter::EncodableMap* int_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNullableEnumMap( - const flutter::EncodableMap* enum_map, - std::function&& on_success, + const ::flutter::EncodableMap* enum_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNullableClassMap( - const flutter::EncodableMap* class_map, - std::function&& on_success, + const ::flutter::EncodableMap* class_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNullableNonNullStringMap( - const flutter::EncodableMap* string_map, - std::function&& on_success, + const ::flutter::EncodableMap* string_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNullableNonNullIntMap( - const flutter::EncodableMap* int_map, - std::function&& on_success, + const ::flutter::EncodableMap* int_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNullableNonNullEnumMap( - const flutter::EncodableMap* enum_map, - std::function&& on_success, + const ::flutter::EncodableMap* enum_map, + std::function&& on_success, std::function&& on_error); // Returns the passed map, to test serialization and deserialization. void EchoNullableNonNullClassMap( - const flutter::EncodableMap* class_map, - std::function&& on_success, + const ::flutter::EncodableMap* class_map, + std::function&& on_success, std::function&& on_error); // Returns the passed enum to test serialization and deserialization. void EchoNullableEnum(const AnEnum* an_enum, @@ -1605,7 +1667,7 @@ class FlutterIntegrationCoreApi { std::function&& on_error); private: - flutter::BinaryMessenger* binary_messenger_; + ::flutter::BinaryMessenger* binary_messenger_; std::string message_channel_suffix_; }; @@ -1621,16 +1683,16 @@ class HostTrivialApi { virtual std::optional Noop() = 0; // The codec used by HostTrivialApi. - static const flutter::StandardMessageCodec& GetCodec(); + static const ::flutter::StandardMessageCodec& GetCodec(); // Sets up an instance of `HostTrivialApi` to handle messages through the // `binary_messenger`. - static void SetUp(flutter::BinaryMessenger* binary_messenger, + static void SetUp(::flutter::BinaryMessenger* binary_messenger, HostTrivialApi* api); - static void SetUp(flutter::BinaryMessenger* binary_messenger, + static void SetUp(::flutter::BinaryMessenger* binary_messenger, HostTrivialApi* api, const std::string& message_channel_suffix); - static flutter::EncodableValue WrapError(std::string_view error_message); - static flutter::EncodableValue WrapError(const FlutterError& error); + static ::flutter::EncodableValue WrapError(std::string_view error_message); + static ::flutter::EncodableValue WrapError(const FlutterError& error); protected: HostTrivialApi() = default; @@ -1650,16 +1712,16 @@ class HostSmallApi { std::function reply)> result) = 0; // The codec used by HostSmallApi. - static const flutter::StandardMessageCodec& GetCodec(); + static const ::flutter::StandardMessageCodec& GetCodec(); // Sets up an instance of `HostSmallApi` to handle messages through the // `binary_messenger`. - static void SetUp(flutter::BinaryMessenger* binary_messenger, + static void SetUp(::flutter::BinaryMessenger* binary_messenger, HostSmallApi* api); - static void SetUp(flutter::BinaryMessenger* binary_messenger, + static void SetUp(::flutter::BinaryMessenger* binary_messenger, HostSmallApi* api, const std::string& message_channel_suffix); - static flutter::EncodableValue WrapError(std::string_view error_message); - static flutter::EncodableValue WrapError(const FlutterError& error); + static ::flutter::EncodableValue WrapError(std::string_view error_message); + static ::flutter::EncodableValue WrapError(const FlutterError& error); protected: HostSmallApi() = default; @@ -1670,10 +1732,10 @@ class HostSmallApi { // called from C++. class FlutterSmallApi { public: - FlutterSmallApi(flutter::BinaryMessenger* binary_messenger); - FlutterSmallApi(flutter::BinaryMessenger* binary_messenger, + FlutterSmallApi(::flutter::BinaryMessenger* binary_messenger); + FlutterSmallApi(::flutter::BinaryMessenger* binary_messenger, const std::string& message_channel_suffix); - static const flutter::StandardMessageCodec& GetCodec(); + static const ::flutter::StandardMessageCodec& GetCodec(); void EchoWrappedList(const TestMessage& msg, std::function&& on_success, std::function&& on_error); @@ -1682,7 +1744,7 @@ class FlutterSmallApi { std::function&& on_error); private: - flutter::BinaryMessenger* binary_messenger_; + ::flutter::BinaryMessenger* binary_messenger_; std::string message_channel_suffix_; }; diff --git a/packages/pigeon/platform_tests/test_plugin/windows/test/equality_test.cpp b/packages/pigeon/platform_tests/test_plugin/windows/test/equality_test.cpp new file mode 100644 index 000000000000..bcadcc5f6a5c --- /dev/null +++ b/packages/pigeon/platform_tests/test_plugin/windows/test/equality_test.cpp @@ -0,0 +1,64 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include + +#include "pigeon/core_tests.gen.h" + +namespace test_plugin { +namespace test { + +using namespace core_tests_pigeontest; + +TEST(EqualityTests, NaNEquality) { + AllNullableTypes all1; + all1.set_a_nullable_double(NAN); + + AllNullableTypes all2; + all2.set_a_nullable_double(NAN); + + EXPECT_EQ(all1, all2); + + AllNullableTypes all3; + all3.set_a_nullable_double(1.0); + + EXPECT_NE(all1, all3); +} + +TEST(EqualityTests, OptionalNaNEquality) { + AllNullableTypes all1; + // std::optional handled via set_a_nullable_double + all1.set_a_nullable_double(NAN); + + AllNullableTypes all2; + all2.set_a_nullable_double(NAN); + + EXPECT_EQ(all1, all2); +} + +TEST(EqualityTests, NestedNaNEquality) { + std::vector list = {NAN}; + AllNullableTypes all1; + all1.set_double_list(list); + + AllNullableTypes all2; + all2.set_double_list(list); + + EXPECT_EQ(all1, all2); +} + +TEST(EqualityTests, SignedZeroEquality) { + AllNullableTypes all1; + all1.set_a_nullable_double(0.0); + + AllNullableTypes all2; + all2.set_a_nullable_double(-0.0); + + EXPECT_EQ(all1, all2); +} + +} // namespace test +} // namespace test_plugin diff --git a/packages/pigeon/platform_tests/test_plugin/windows/test/non_null_fields_test.cpp b/packages/pigeon/platform_tests/test_plugin/windows/test/non_null_fields_test.cpp index 07412dc84378..d7ea926f62b3 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/test/non_null_fields_test.cpp +++ b/packages/pigeon/platform_tests/test_plugin/windows/test/non_null_fields_test.cpp @@ -14,4 +14,13 @@ TEST(NonNullFields, Build) { EXPECT_EQ(request.query(), "hello"); } +TEST(NonNullFields, Equality) { + NonNullFieldSearchRequest request1("hello"); + NonNullFieldSearchRequest request2("hello"); + NonNullFieldSearchRequest request3("world"); + + EXPECT_EQ(request1, request2); + EXPECT_NE(request1, request3); +} + } // namespace non_null_fields_pigeontest diff --git a/packages/pigeon/platform_tests/test_plugin/windows/test/null_fields_test.cpp b/packages/pigeon/platform_tests/test_plugin/windows/test/null_fields_test.cpp index 9a0cf75e8259..46f16079cc45 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/test/null_fields_test.cpp +++ b/packages/pigeon/platform_tests/test_plugin/windows/test/null_fields_test.cpp @@ -211,4 +211,34 @@ TEST_F(NullFieldsTest, ReplyToListWithNulls) { } } +TEST(NullFields, Equality) { + NullFieldsSearchRequest request1(1); + request1.set_query("hello"); + NullFieldsSearchRequest request2(1); + request2.set_query("hello"); + NullFieldsSearchRequest request3(2); + request3.set_query("hello"); + NullFieldsSearchRequest request4(1); + request4.set_query("world"); + + EXPECT_EQ(request1, request2); + EXPECT_FALSE(request1 == request3); + EXPECT_FALSE(request1 == request4); + + NullFieldsSearchReply reply1; + reply1.set_result("result"); + reply1.set_request(request1); + + NullFieldsSearchReply reply2; + reply2.set_result("result"); + reply2.set_request(request2); + + NullFieldsSearchReply reply3; + reply3.set_result("result"); + reply3.set_request(request3); + + EXPECT_EQ(reply1, reply2); + EXPECT_FALSE(reply1 == reply3); +} + } // namespace null_fields_pigeontest diff --git a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.cpp b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.cpp index bb77ea902dfc..3e6056f3a810 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.cpp +++ b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.cpp @@ -97,6 +97,21 @@ ErrorOr> TestPlugin::EchoAllNullableTypes( return std::optional(*everything); } +ErrorOr TestPlugin::AreAllNullableTypesEqual(const AllNullableTypes& a, + const AllNullableTypes& b) { + return a == b; +} + +ErrorOr TestPlugin::GetAllNullableTypesHash( + const AllNullableTypes& value) { + return (int64_t)value.Hash(); +} + +ErrorOr TestPlugin::GetAllNullableTypesWithoutRecursionHash( + const AllNullableTypesWithoutRecursion& value) { + return (int64_t)value.Hash(); +} + ErrorOr> TestPlugin::EchoAllNullableTypesWithoutRecursion( const AllNullableTypesWithoutRecursion* everything) { diff --git a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h index 002a73291335..a52bd83f03a2 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h +++ b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h @@ -60,6 +60,15 @@ class TestPlugin : public flutter::Plugin, std::optional> EchoAllNullableTypes( const core_tests_pigeontest::AllNullableTypes* everything) override; + core_tests_pigeontest::ErrorOr AreAllNullableTypesEqual( + const core_tests_pigeontest::AllNullableTypes& a, + const core_tests_pigeontest::AllNullableTypes& b) override; + core_tests_pigeontest::ErrorOr GetAllNullableTypesHash( + const core_tests_pigeontest::AllNullableTypes& value) override; + core_tests_pigeontest::ErrorOr + GetAllNullableTypesWithoutRecursionHash( + const core_tests_pigeontest::AllNullableTypesWithoutRecursion& value) + override; core_tests_pigeontest::ErrorOr< std::optional> EchoAllNullableTypesWithoutRecursion( diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml index e0e25734e32e..fc6b93ef2807 100644 --- a/packages/pigeon/pubspec.yaml +++ b/packages/pigeon/pubspec.yaml @@ -2,7 +2,7 @@ name: pigeon description: Code generator tool to make communication between Flutter and the host platform type-safe and easier. repository: https://github.com/flutter/packages/tree/main/packages/pigeon issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+pigeon%22 -version: 26.1.10 # This must match the version in lib/src/generator_tools.dart +version: 26.2.0 # This must match the version in lib/src/generator_tools.dart environment: sdk: ^3.9.0 diff --git a/packages/pigeon/test/cpp_generator_test.dart b/packages/pigeon/test/cpp_generator_test.dart index d9a22ec657bb..0c77bed2b1de 100644 --- a/packages/pigeon/test/cpp_generator_test.dart +++ b/packages/pigeon/test/cpp_generator_test.dart @@ -124,7 +124,7 @@ void main() { contains( RegExp( r'void Api::SetUp\(\s*' - r'flutter::BinaryMessenger\* binary_messenger,\s*' + r'::flutter::BinaryMessenger\* binary_messenger,\s*' r'Api\* api\s*\)', ), ), @@ -309,12 +309,12 @@ void main() { contains(' const std::string& code() const { return code_; }'), contains(' const std::string& message() const { return message_; }'), contains( - ' const flutter::EncodableValue& details() const { return details_; }', + ' const ::flutter::EncodableValue& details() const { return details_; }', ), contains(' private:'), contains(' std::string code_;'), contains(' std::string message_;'), - contains(' flutter::EncodableValue details_;'), + contains(' ::flutter::EncodableValue details_;'), ]), ); } @@ -567,6 +567,8 @@ void main() { #include #include +#include +#include #include #include #include @@ -1174,13 +1176,13 @@ void main() { expect( code, contains( - 'ErrorOr> ReturnNullableList()', + 'ErrorOr> ReturnNullableList()', ), ); expect( code, contains( - 'ErrorOr> ReturnNullableMap()', + 'ErrorOr> ReturnNullableMap()', ), ); expect( @@ -1297,8 +1299,8 @@ void main() { expect(code, contains('ErrorOr ReturnBool()')); expect(code, contains('ErrorOr ReturnInt()')); expect(code, contains('ErrorOr ReturnString()')); - expect(code, contains('ErrorOr ReturnList()')); - expect(code, contains('ErrorOr ReturnMap()')); + expect(code, contains('ErrorOr<::flutter::EncodableList> ReturnList()')); + expect(code, contains('ErrorOr<::flutter::EncodableMap> ReturnMap()')); expect(code, contains('ErrorOr ReturnDataClass()')); } }); @@ -1415,10 +1417,10 @@ void main() { r'const bool\* a_bool,\s*' r'const int64_t\* an_int,\s*' r'const std::string\* a_string,\s*' - r'const flutter::EncodableList\* a_list,\s*' - r'const flutter::EncodableMap\* a_map,\s*' + r'const ::flutter::EncodableList\* a_list,\s*' + r'const ::flutter::EncodableMap\* a_map,\s*' r'const ParameterObject\* an_object,\s*' - r'const flutter::EncodableValue\* a_generic_object\s*\)', + r'const ::flutter::EncodableValue\* a_generic_object\s*\)', ), ), ); @@ -1611,10 +1613,10 @@ void main() { r'bool a_bool,\s*' r'int64_t an_int,\s*' r'const std::string& a_string,\s*' - r'const flutter::EncodableList& a_list,\s*' - r'const flutter::EncodableMap& a_map,\s*' + r'const ::flutter::EncodableList& a_list,\s*' + r'const ::flutter::EncodableMap& a_map,\s*' r'const ParameterObject& an_object,\s*' - r'const flutter::EncodableValue& a_generic_object\s*\)', + r'const ::flutter::EncodableValue& a_generic_object\s*\)', ), ), ); @@ -1813,10 +1815,10 @@ void main() { // Nullable strings use std::string* rather than std::string_view* // since there's no implicit conversion for pointer types. r'const std::string\* a_string,\s*' - r'const flutter::EncodableList\* a_list,\s*' - r'const flutter::EncodableMap\* a_map,\s*' + r'const ::flutter::EncodableList\* a_list,\s*' + r'const ::flutter::EncodableMap\* a_map,\s*' r'const ParameterObject\* an_object,\s*' - r'const flutter::EncodableValue\* a_generic_object,', + r'const ::flutter::EncodableValue\* a_generic_object,', ), ), ); @@ -2001,10 +2003,10 @@ void main() { // nullable strings. r'const std::string& a_string,\s*' // Non-POD types use const references. - r'const flutter::EncodableList& a_list,\s*' - r'const flutter::EncodableMap& a_map,\s*' + r'const ::flutter::EncodableList& a_list,\s*' + r'const ::flutter::EncodableMap& a_map,\s*' r'const ParameterObject& an_object,\s*' - r'const flutter::EncodableValue& a_generic_object,\s*', + r'const ::flutter::EncodableValue& a_generic_object,\s*', ), ), ); @@ -2313,7 +2315,7 @@ void main() { dartPackageName: DEFAULT_PACKAGE_NAME, ); final code = sink.toString(); - expect(code, contains(' : public flutter::StandardCodecSerializer')); + expect(code, contains(' : public ::flutter::StandardCodecSerializer')); }); test('Does not send unwrapped EncodableLists', () { @@ -2614,4 +2616,170 @@ void main() { ); expect(code, contains('channel.Send')); }); + + test('data class equality', () { + final root = Root( + apis: [], + classes: [ + Class( + name: 'Foo', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: false), + name: 'bar', + ), + ], + ), + ], + enums: [], + ); + { + final sink = StringBuffer(); + const generator = CppGenerator(); + final generatorOptions = OutputFileOptions( + fileType: FileType.header, + languageOptions: const InternalCppOptions( + cppHeaderOut: '', + cppSourceOut: '', + headerIncludePath: '', + ), + ); + generator.generate( + generatorOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('bool operator==(const Foo& other) const;')); + } + { + final sink = StringBuffer(); + const generator = CppGenerator(); + final generatorOptions = OutputFileOptions( + fileType: FileType.source, + languageOptions: const InternalCppOptions( + cppHeaderOut: '', + cppSourceOut: '', + headerIncludePath: '', + ), + ); + generator.generate( + generatorOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('bool Foo::operator==(const Foo& other) const {')); + } + }); + + test('data class equality with pointers', () { + final nested = Class( + name: 'Nested', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: false), + name: 'data', + ), + ], + ); + final root = Root( + apis: [], + classes: [ + Class( + name: 'Foo', + fields: [ + NamedType( + type: TypeDeclaration( + baseName: 'Nested', + isNullable: true, + associatedClass: nested, + ), + name: 'nested', + ), + ], + ), + nested, + ], + enums: [], + ); + final sink = StringBuffer(); + const generator = CppGenerator(); + final generatorOptions = OutputFileOptions( + fileType: FileType.source, + languageOptions: const InternalCppOptions( + cppHeaderOut: '', + cppSourceOut: '', + headerIncludePath: '', + ), + ); + generator.generate( + generatorOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('bool Foo::operator==(const Foo& other) const {')); + }); + + test('data classes implement Hash', () { + final root = Root( + apis: [], + classes: [ + Class( + name: 'Input', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: false), + name: 'field1', + ), + ], + ), + ], + enums: [], + ); + { + final sink = StringBuffer(); + const generator = CppGenerator(); + final generatorOptions = OutputFileOptions( + fileType: FileType.header, + languageOptions: const InternalCppOptions( + headerIncludePath: 'foo.h', + cppHeaderOut: '', + cppSourceOut: '', + ), + ); + generator.generate( + generatorOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('size_t Hash() const;')); + } + { + final sink = StringBuffer(); + const generator = CppGenerator(); + final generatorOptions = OutputFileOptions( + fileType: FileType.source, + languageOptions: const InternalCppOptions( + headerIncludePath: 'foo.h', + cppHeaderOut: '', + cppSourceOut: '', + ), + ); + generator.generate( + generatorOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('size_t Input::Hash() const {')); + } + }); } diff --git a/packages/pigeon/test/dart_generator_test.dart b/packages/pigeon/test/dart_generator_test.dart index 707673a9857e..88ec7f5f9ecc 100644 --- a/packages/pigeon/test/dart_generator_test.dart +++ b/packages/pigeon/test/dart_generator_test.dart @@ -2079,4 +2079,64 @@ name: foobar expect(code, contains('buffer.putUint8(4);')); expect(code, contains('buffer.putInt64(value);')); }); + + test('data class equality', () { + final classDefinition = Class( + name: 'Foobar', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: true), + name: 'field1', + ), + ], + ); + final root = Root( + apis: [], + classes: [classDefinition], + enums: [], + ); + final sink = StringBuffer(); + const generator = DartGenerator(); + generator.generate( + const InternalDartOptions(), + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('bool operator ==(Object other) {')); + expect(code, contains('int get hashCode =>')); + }); + + test('data class equality multi-field', () { + final classDefinition = Class( + name: 'Foobar', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: true), + name: 'field1', + ), + NamedType( + type: const TypeDeclaration(baseName: 'String', isNullable: true), + name: 'field2', + ), + ], + ); + final root = Root( + apis: [], + classes: [classDefinition], + enums: [], + ); + final sink = StringBuffer(); + const generator = DartGenerator(); + generator.generate( + const InternalDartOptions(), + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('bool operator ==(Object other) {')); + expect(code, contains('int get hashCode =>')); + }); } diff --git a/packages/pigeon/test/gobject_generator_test.dart b/packages/pigeon/test/gobject_generator_test.dart index c9ef46a3aa43..8f44885a4617 100644 --- a/packages/pigeon/test/gobject_generator_test.dart +++ b/packages/pigeon/test/gobject_generator_test.dart @@ -1035,4 +1035,50 @@ void main() { expect(code, contains('const int test_package_object_type_id = 131;')); } }); + + test('data classes handle equality and hashing', () { + final inputClass = Class( + name: 'Input', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'String', isNullable: true), + name: 'input', + ), + NamedType( + type: const TypeDeclaration(baseName: 'double', isNullable: false), + name: 'someDouble', + ), + NamedType( + type: const TypeDeclaration(baseName: 'Uint8List', isNullable: false), + name: 'someBytes', + ), + ], + ); + final root = Root( + apis: [], + classes: [inputClass], + enums: [], + ); + { + final sink = StringBuffer(); + const generator = GObjectGenerator(); + final generatorOptions = OutputFileOptions( + fileType: FileType.source, + languageOptions: const InternalGObjectOptions( + headerIncludePath: '', + gobjectHeaderOut: '', + gobjectSourceOut: '', + ), + ); + generator.generate( + generatorOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('gboolean test_package_input_equals(')); + expect(code, contains('guint test_package_input_hash(')); + } + }); } diff --git a/packages/pigeon/test/java_generator_test.dart b/packages/pigeon/test/java_generator_test.dart index a7dd1bbfbcbc..07c00a25d430 100644 --- a/packages/pigeon/test/java_generator_test.dart +++ b/packages/pigeon/test/java_generator_test.dart @@ -1886,4 +1886,33 @@ void main() { ), ); }); + + test('data class equality', () { + final classDefinition = Class( + name: 'Foobar', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: true), + name: 'field1', + ), + ], + ); + final root = Root( + apis: [], + classes: [classDefinition], + enums: [], + ); + final sink = StringBuffer(); + const javaOptions = InternalJavaOptions(className: 'Messages', javaOut: ''); + const generator = JavaGenerator(); + generator.generate( + javaOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('public boolean equals(Object o) {')); + expect(code, contains('public int hashCode() {')); + }); } diff --git a/packages/pigeon/test/kotlin_generator_test.dart b/packages/pigeon/test/kotlin_generator_test.dart index 10e5193dae96..236a28c4b983 100644 --- a/packages/pigeon/test/kotlin_generator_test.dart +++ b/packages/pigeon/test/kotlin_generator_test.dart @@ -2027,4 +2027,66 @@ void main() { // There should be only one occurrence of 'is Foo' in the block expect(count, 1); }); + + test('data class equality', () { + final classDefinition = Class( + name: 'Foobar', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: true), + name: 'field1', + ), + ], + ); + final root = Root( + apis: [], + classes: [classDefinition], + enums: [], + ); + final sink = StringBuffer(); + const kotlinOptions = InternalKotlinOptions(kotlinOut: ''); + const generator = KotlinGenerator(); + generator.generate( + kotlinOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('override fun equals(other: Any?): Boolean {')); + expect(code, contains('override fun hashCode(): Int {')); + }); + + test('data class equality multi-field', () { + final classDefinition = Class( + name: 'Foobar', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: true), + name: 'field1', + ), + NamedType( + type: const TypeDeclaration(baseName: 'String', isNullable: true), + name: 'field2', + ), + ], + ); + final root = Root( + apis: [], + classes: [classDefinition], + enums: [], + ); + final sink = StringBuffer(); + const kotlinOptions = InternalKotlinOptions(kotlinOut: ''); + const generator = KotlinGenerator(); + generator.generate( + kotlinOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('override fun equals(other: Any?): Boolean {')); + expect(code, contains('override fun hashCode(): Int {')); + }); } diff --git a/packages/pigeon/test/objc_generator_test.dart b/packages/pigeon/test/objc_generator_test.dart index b44f84f571d3..fb18833f77bc 100644 --- a/packages/pigeon/test/objc_generator_test.dart +++ b/packages/pigeon/test/objc_generator_test.dart @@ -4040,4 +4040,63 @@ void main() { expect(code, isNot(contains('FLTFLT'))); expect(code, contains('FLTEnum1Box')); }); + + test('data class equality', () { + final root = Root( + apis: [], + classes: [ + Class( + name: 'Foo', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: false), + name: 'bar', + ), + ], + ), + ], + enums: [], + ); + { + final sink = StringBuffer(); + const generator = ObjcGenerator(); + final generatorOptions = OutputFileOptions( + fileType: FileType.header, + languageOptions: const InternalObjcOptions( + prefix: 'ABC', + objcHeaderOut: '', + objcSourceOut: '', + headerIncludePath: '', + ), + ); + generator.generate( + generatorOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + } + { + final sink = StringBuffer(); + const generator = ObjcGenerator(); + final generatorOptions = OutputFileOptions( + fileType: FileType.source, + languageOptions: const InternalObjcOptions( + prefix: 'ABC', + objcHeaderOut: '', + objcSourceOut: '', + headerIncludePath: '', + ), + ); + generator.generate( + generatorOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect(code, contains('- (BOOL)isEqual:(id)object {')); + expect(code, contains('- (NSUInteger)hash {')); + } + }); } diff --git a/packages/pigeon/test/swift_generator_test.dart b/packages/pigeon/test/swift_generator_test.dart index c91f09e9976b..fa567e2b02c8 100644 --- a/packages/pigeon/test/swift_generator_test.dart +++ b/packages/pigeon/test/swift_generator_test.dart @@ -1785,4 +1785,72 @@ void main() { ), ); }); + + test('data class equality', () { + final classDefinition = Class( + name: 'Foobar', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: true), + name: 'field1', + ), + ], + ); + final root = Root( + apis: [], + classes: [classDefinition], + enums: [], + ); + final sink = StringBuffer(); + const swiftOptions = InternalSwiftOptions(swiftOut: ''); + const generator = SwiftGenerator(); + generator.generate( + swiftOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect( + code, + contains('static func == (lhs: Foobar, rhs: Foobar) -> Bool {'), + ); + expect(code, contains('func hash(into hasher: inout Hasher) {')); + }); + + test('data class equality multi-field', () { + final classDefinition = Class( + name: 'Foobar', + fields: [ + NamedType( + type: const TypeDeclaration(baseName: 'int', isNullable: true), + name: 'field1', + ), + NamedType( + type: const TypeDeclaration(baseName: 'String', isNullable: true), + name: 'field2', + ), + ], + ); + final root = Root( + apis: [], + classes: [classDefinition], + enums: [], + ); + final sink = StringBuffer(); + const swiftOptions = InternalSwiftOptions(swiftOut: ''); + const generator = SwiftGenerator(); + generator.generate( + swiftOptions, + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final code = sink.toString(); + expect( + code, + contains('static func == (lhs: Foobar, rhs: Foobar) -> Bool {'), + ); + expect(code, contains('func hash(into hasher: inout Hasher) {')); + }); }