diff options
-rw-r--r-- | core/src/main/kotlin/model/properties/PropertyContainer.kt | 39 |
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 |