All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gw2tb.apigen.internal.impl.SchemaVersionedDataImpl.kt Maven / Gradle / Ivy

/*
 * Copyright (c) 2019-2024 Leon Linhart
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.gw2tb.apigen.internal.impl

import com.gw2tb.apigen.internal.model.v2.compareTo
import com.gw2tb.apigen.model.v2.*
import java.util.*

internal fun  buildVersionedSchemaData(block: Builder.() -> Unit): SchemaVersionedDataImpl =
    SchemaVersionedDataImpl(TreeSet> { a, b -> a.compareTo(b) }.apply {
        Builder().apply(block).data.forEach { (constraint, data) ->
            add(SchemaVersionConstrainedData(data, constraint.since, constraint.until))
        }
    })

internal fun  wrapVersionedSchemaData(value: T): SchemaVersionedDataImpl =
    buildVersionedSchemaData { add(value, since = SchemaVersion.V2_SCHEMA_CLASSIC, until = null) }

internal class Builder {

    internal val data = mutableMapOf()
    private var unboundSince: SchemaVersion? = null

    fun add(datum: T, since: SchemaVersion = SchemaVersion.V2_SCHEMA_CLASSIC, until: SchemaVersion? = null) {
        require(until == null || since < until)
//        require(data.none { (other, _) -> (other.until == null || since < other.until) && (until == null || other.since < until) })

        if (unboundSince != null && unboundSince!! < since) {
            val d = data.remove(VersionConstraint(unboundSince!!, null)) ?: error("")
            data[VersionConstraint(unboundSince!!, since)] = d
        }

        if (until == null)
            unboundSince = since

        data[VersionConstraint(since, until)] = datum
    }

}

internal data class VersionConstraint(
    val since: SchemaVersion,
    val until: SchemaVersion?
)

internal class SchemaVersionedDataImpl(
    internal val entries: TreeSet>
) : SchemaVersionedData, Iterable> by entries {

    init {
        require(entries.isNotEmpty()) { "SchemaVersionedData requires at least one entry" }
    }

    val isConsistent get() =
        (entries.size == 1) && (entries.first().since == SchemaVersion.V2_SCHEMA_CLASSIC) && (entries.first().until == null)

    override val versions: List get() =
        SchemaVersion.values().filter { get(it) != null }

    override val significantVersions get() =
        SchemaVersion.values().filter { hasChangedInVersion(it) && isSupported(it) }

    fun first(): SchemaVersionConstrainedData =
        entries.first()

    override fun getOrThrow(version: SchemaVersion): SchemaVersionConstrainedData =
        get(version) ?: error("No data for version $version")

    override fun get(version: SchemaVersion): SchemaVersionConstrainedData? =
        entries.firstOrNull { (_, since, until) -> since <= version && (until == null || version < until) }

    fun hasChangedInVersion(version: SchemaVersion): Boolean =
        entries.any { constraint -> constraint.since == version || constraint.until == version }

    override fun isSupported(version: SchemaVersion): Boolean =
        get(version) != null

    fun readjustConstraints(since: SchemaVersion, until: SchemaVersion?): SchemaVersionedDataImpl {
        if (entries.first().since == since && entries.last().until == until) return this

        return buildVersionedSchemaData {
            val first = entries.first()
            val last = entries.last()

            if (first == last) {
                add(first.data, since, until)
            } else {
                add(first.data, since, first.until)
                entries.forEach { entry ->
                    if (entry == first || entry == last) return@forEach

                    add(entry.data, entry.since, entry.until)
                }
                add(last.data, last.since, until)
            }
        }
    }

    fun forEach(block: (T, SchemaVersion, SchemaVersion?) -> Unit) {
        entries.forEach { block(it.data, it.since, it.until) }
    }

    override fun  flatten(transform: (T) -> R): R {
        val itr = entries.iterator()
        val data = transform(itr.next().data)

        while (itr.hasNext()) {
            val nextData = transform(itr.next().data)
            if (data != nextData) error("Cannot flatMap data")
        }

        return data
    }

    fun  mapData(transform: (T) -> R): SchemaVersionedDataImpl =
        SchemaVersionedDataImpl(entries.asSequence().map { it.map(transform) }.toCollection(TreeSet { a, b -> a.compareTo(b) }))

    fun  mapVersionedData(transform: (SchemaVersion, T) -> R): SchemaVersionedDataImpl =
        SchemaVersionedDataImpl(entries.asSequence().map { it.mapVersioned(transform) }.toCollection(TreeSet { a, b -> a.compareTo(b) }))

    private fun  SchemaVersionConstrainedData.map(transform: (T) -> R) =
        SchemaVersionConstrainedData(transform(data), since, until)

    private fun  SchemaVersionConstrainedData.mapVersioned(transform: (SchemaVersion, T) -> R) =
        SchemaVersionConstrainedData(transform(since, data), since, until)

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy