aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/src/main/kotlin/model/properties/PropertyContainer.kt39
1 files changed, 37 insertions, 2 deletions
diff --git a/core/src/main/kotlin/model/properties/PropertyContainer.kt b/core/src/main/kotlin/model/properties/PropertyContainer.kt
index da351569..ed4b99de 100644
--- a/core/src/main/kotlin/model/properties/PropertyContainer.kt
+++ b/core/src/main/kotlin/model/properties/PropertyContainer.kt
@@ -1,13 +1,16 @@
package org.jetbrains.dokka.model.properties
-class PropertyContainer<C : Any> private constructor(
+import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
+import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
+
+class PropertyContainer<C : Any> internal constructor(
@PublishedApi internal val map: Map<Property.Key<C, *>, Property<C>>
) {
operator fun <D : C> plus(prop: Property<D>): PropertyContainer<D> =
PropertyContainer(map + (prop.key to prop))
// TODO: Add logic for caching calculated properties
- inline operator fun <reified T: Any> get(key: Property.Key<C, T>): T? = when (val prop = map[key]) {
+ inline operator fun <reified T : Any> get(key: Property.Key<C, T>): T? = when (val prop = map[key]) {
is T? -> prop
else -> throw ClassCastException("Property for $key stored under not matching key type.")
}
@@ -15,4 +18,36 @@ class PropertyContainer<C : Any> private constructor(
companion object {
val empty: PropertyContainer<Any> = PropertyContainer(emptyMap())
}
+}
+
+interface WithExtraProperties<C : Any> {
+ val extra: PropertyContainer<C>
+
+ fun withNewExtras(newExtras: PropertyContainer<C>): C
+}
+
+fun <C> C.mergeExtras(left: C, right: C): C where C : Any, C : WithExtraProperties<C> {
+ val aggregatedExtras: List<List<Property<C>>> =
+ (left.extra.map.values + right.extra.map.values)
+ .groupBy { it.key }
+ .values
+ .map { it.distinct() }
+
+ val (unambiguous, toMerge) = aggregatedExtras.partition { it.size == 1 }
+
+ @Suppress("UNCHECKED_CAST")
+ val strategies: List<MergeStrategy<C>> = toMerge.map { (l, r) ->
+ (l.key as Property.Key<C, Property<C>>).mergeStrategyFor(l, r)
+ }
+
+ strategies.firstIsInstanceOrNull<MergeStrategy.Fail>()?.error?.invoke()
+
+ val replaces: List<Property<C>> = strategies.filterIsInstance<MergeStrategy.Replace<C>>().map { it.newProperty }
+
+ val needingFullMerge: List<(preMerged: C, left: C, right: C) -> C> =
+ strategies.filterIsInstance<MergeStrategy.Full<C>>().map { it.merger }
+
+ val newExtras = PropertyContainer((unambiguous.flatten() + replaces).associateBy { it.key })
+
+ return needingFullMerge.fold(withNewExtras(newExtras)) { acc, merger -> merger(acc, left, right) }
} \ No newline at end of file