udalov
open class StructuredEquality<T>(vararg val properties: KProperty1<T, *>)
inline fun <reified T> T.equalsBy(other: Any?, eq: StructuredEquality<T>): Boolean {
return this === other || other is T && eq.properties.all { p -> p.get(this) == p.get(other) }
}
fun <T> T.hashCodeBy(eq: StructuredEquality<T>): Int {
return eq.properties.fold(0) { acc, p -> acc * 31 + (p.get(this)?.hashCode() ?: 0) }
}