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

commonMain.at.asitplus.signum.supreme.dsl.ConfigurationDSL.kt Maven / Gradle / Ivy

There is a newer version: 0.3.2
Show newest version
package at.asitplus.signum.supreme.dsl

/**
 * The meta functionality that enables us to easily create DSLs.
 * @see at.asitplus.signum.supreme.dsl.DSLInheritanceDemonstration
 * @see at.asitplus.signum.supreme.dsl.DSLVarianceDemonstration
 */
object DSL {
    /** Resolve a DSL lambda to a concrete configuration */
    fun  resolve(factory: ()->T, config: DSLConfigureFn): T =
        (if (config == null) factory() else factory().apply(config)).also(Data::validate)

    sealed interface Holder {
        val v: T
    }

    sealed interface Invokable: Holder {
        operator fun invoke(configure: Target.()->Unit)
    }

    /** Constructed by: [DSL.Data.child]. */
    class DirectHolder internal constructor(default: T, private val factory: ()->(T & Any))
        : Invokable {
        private var _v: T = default
        override val v: T get() = _v

        override operator fun invoke(configure: (T & Any).()->Unit) { _v = resolve(factory, configure) }
    }

    /** Constructed by: [DSL.Data.subclassOf]. */
    class Generalized internal constructor(default: T): Holder {
        private var _v: T = default
        override val v: T get() = _v

        inner class option
        /**
         * Adds a specialized invokable accessor for the underlying generalized storage.
         * Use as `val specialized = _holder.option(::SpecializedClass).`
         *
         * User code can invoke this specialized accessor as `specialized { }`.
         * This constructs a new specialized child, configures it using the specified block,
         * and stores it in the underlying generalized storage.
         */
        internal constructor(private val factory: ()->S) : Invokable {
            override val v: T get() = [email protected]
            override operator fun invoke(configure: S.()->Unit) { _v = resolve(factory, configure) }
        }
    }

    /** Constructed by: [DSL.Data.integratedReceiver]. */
    class Integrated internal constructor(): Invokable<(T.() -> Unit)?, T> {
        private var _v: (T.()->Unit)? = null
        override val v: (T.()->Unit)? get() = _v
        override operator fun invoke(configure: T.()->Unit) { _v = configure }
    }

    @DslMarker
    annotation class Marker

    /** The superclass of all DSL configuration objects. Exposes helper functions for definition. */
    @Marker
    open class Data {
        /**
         * Embeds a child; use as `val sub = child(::TypeOfSub)`.
         * Defaults to a default-constructed child.
         *
         * User code will invoke as `child { }`.
         * This constructs a new child and configures it using the specified block.
         */
        protected fun  child(factory: ()->T): Invokable =
            DirectHolder(factory(), factory)

        /**
         * Embeds an optional child. Use as `val sub = childOrNull(::TypeOfSub)`.
         * Defaults to `null`.
         *
         * User code will invoke as `child { }`
         * This constructs a new child and configures it using the specified block.
         */
        protected fun  childOrNull(factory: ()->T): Invokable =
            DirectHolder(null, factory)

        /**
         * Specifies a generalized holder of type T.
         * Use as `internal val _subHolder = subclassOf()`.
         *
         * The generalized holder itself cannot be invoked, and should be marked `internal`.
         * Defaults to `null`.
         *
         * Specialized invokable accessors can be spun off via `.option(::SpecializedClass)`.
         * @see DSL.Generalized.option
         */
        protected fun  subclassOf(): Generalized =
            Generalized(null)
        /**
         * Specifies a generalized holder of type T.
         * Use as `internal val _subHolder = subclassOf(SpecializedClass())`.
         *
         * The generalized holder itself cannot be invoked, and should be marked `internal`.
         * Defaults to the specified `default`.
         *
         * Specialized invokable accessors can be spun off via `.option(::SpecializedClass)`.
         * @see DSL.Generalized.option
         */
        protected fun  subclassOf(default: T): Generalized =
            Generalized(default)

        /**
         * Integrates an external configuration lambda into the DSL.
         * Use as `val other = integratedReceiver()`.
         *
         * This receiver can be invoked, but simply stores the received lambda instead of running it.
         * Defaults to `null`.
         */
        protected fun  integratedReceiver(): Integrated =
            Integrated()

        /**
         * Invoked by `DSL.resolve()` after the configuration block runs.
         * Can be used for sanity checks.
         */
        internal open fun validate() {}
    }
}

typealias DSLConfigureFn = (T.()->Unit)?




© 2015 - 2024 Weber Informatics LLC | Privacy Policy