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

commonMain.com.bkahlert.kommons.factories.kt Maven / Gradle / Ivy

Go to download

Kommons Core is a Kotlin Multiplatform Library that offers shared features for all Kommons modules.

There is a newer version: 2.8.0
Show newest version
package com.bkahlert.kommons

import com.bkahlert.kommons.Converter.Converter1
import com.bkahlert.kommons.Converter.Converter2
import com.bkahlert.kommons.Converter.Converter3
import com.bkahlert.kommons.Creator.Creator1
import com.bkahlert.kommons.Creator.Creator2
import com.bkahlert.kommons.Creator.Creator3
import com.bkahlert.kommons.Parser.Companion.parser
import kotlin.reflect.KClass

/**
 * Factory that can create a [T] object.
 * @see Creator1
 * @see Creator2
 * @see Creator3
 */
public sealed interface Creator {

    /**
     * Factory that can create a [T] object of a [P1] object.
     *
     * *Intended to be implemented by delegation by a companion object
     * using [creator] to offer
     * a [of] factory method and
     * a [ofOrNull] factory method.*
     *
     * @see Method Naming Convention
     */
    public interface Creator1 : Creator {
        /** Returns an object of type [T] created of the [P1] object, or `null` otherwise. */
        public fun ofOrNull(obj: P1): T? = kotlin.runCatching { of(obj) }.getOrNull()

        /** Returns an object of type [T] created of the [P1] object, or throws a [CreationException] otherwise. */
        public fun of(obj: P1): T
    }

    /**
     * Factory that can create a [T] object of a [P1] and a [P2] object.
     *
     * *Intended to be implemented by delegation by a companion object
     * using [creator] to offer
     * a [of] factory method and
     * a [ofOrNull] factory method.*
     *
     * @see Method Naming Convention
     */
    public interface Creator2 : Creator {
        /** Returns an object of type [T] created of the [P1] and [P2] object, or `null` otherwise. */
        public fun ofOrNull(obj1: P1, obj2: P2): T? = kotlin.runCatching { of(obj1, obj2) }.getOrNull()

        /** Returns an object of type [T] created of the [P1] and [P2] object, or throws a [CreationException] otherwise. */
        public fun of(obj1: P1, obj2: P2): T
    }

    /**
     * Factory that can create a [T] object of a [P1], a [P2] and a [P3] object.
     *
     * *Intended to be implemented by delegation by a companion object
     * using [creator] to offer
     * a [of] factory method and
     * a [ofOrNull] factory method.*
     *
     * @see Method Naming Convention
     */
    public interface Creator3 : Creator {
        /** Returns an object of type [T] created of the [P1], [P2], and [P3] object, or `null` otherwise. */
        public fun ofOrNull(obj1: P1, obj2: P2, obj3: P3): T? = kotlin.runCatching { of(obj1, obj2, obj3) }.getOrNull()

        /** Returns an object of type [T] created of the [P1], [P2], and [P3] object, or throws a [CreationException] otherwise. */
        public fun of(obj1: P1, obj2: P2, obj3: P3): T
    }

    public companion object {
        /** Returns a [Creator1] that can create a [T] object of a [P1] object using the specified [createOrNull]. */
        public inline fun  creator(crossinline createOrNull: (P1) -> T?): Creator1 = object : Creator1 {
            override fun of(obj: P1): T = kotlin.runCatching {
                createOrNull(obj) ?: throw CreationException(T::class, obj)
            }.getOrElse {
                if (it is CreationException) throw it
                throw throw CreationException(T::class, it, obj)
            }
        }

        /** Returns a [Creator2] that can create a [T] object of a [P1] and a [P2] object using the specified [createOrNull]. */
        public inline fun  creator(crossinline createOrNull: (P1, P2) -> T?): Creator2 = object : Creator2 {
            override fun of(obj1: P1, obj2: P2): T = kotlin.runCatching {
                createOrNull(obj1, obj2) ?: throw CreationException(T::class, obj1, obj2)
            }.getOrElse {
                if (it is CreationException) throw it
                throw throw CreationException(T::class, it, obj1, obj2)
            }
        }

        /** Returns a [Creator3] that can create a [T] object of a [P1], a [P2], and a [P3] object using the specified [createOrNull]. */
        public inline fun  creator(crossinline createOrNull: (P1, P2, P3) -> T?): Creator3 =
            object : Creator3 {
                override fun of(obj1: P1, obj2: P2, obj3: P3): T = kotlin.runCatching {
                    createOrNull(obj1, obj2, obj3) ?: throw CreationException(T::class, obj1, obj2, obj3)
                }.getOrElse {
                    if (it is CreationException) throw it
                    throw throw CreationException(T::class, it, obj1, obj2, obj3)
                }
            }
    }

    /** Exception thrown by a [Creator] when creation fails. */
    public class CreationException(
        message: String,
        /** Optional cause of this exception. */
        cause: Throwable? = null,
    ) : IllegalArgumentException(message, cause) {
        /** Creates a new creator exception for the specified [objects], the specified [type], and the optional [cause]. */
        public constructor(
            type: KClass<*>,
            cause: Throwable? = null,
            vararg objects: Any?,
        ) : this("Failed to create an instance of ${type.simpleName ?: type.toString()} of ${objects.joinToString { it.quoted }}", cause)

        /** Creates a new creator exception for the specified [objects] and the specified [type]. */
        public constructor(
            type: KClass<*>,
            vararg objects: Any?,
        ) : this(type, null, *objects)
    }
}

/**
 * Factory that can convert objects to a [T] object.
 * @see Converter1
 * @see Converter2
 * @see Converter3
 */
public sealed interface Converter {
    /**
     * Factory that can convert a [P1] object to a [T] object.
     *
     * *Intended to be implemented by delegation by a companion object
     * using [converter] to offer
     * a [from] factory method and
     * a [fromOrNull] factory method.*
     *
     * @see Method Naming Convention
     */
    public interface Converter1 : Converter {
        /** Returns an object of type [T] representing the converted [P1] object, or `null` otherwise. */
        public fun fromOrNull(obj: P1): T? = kotlin.runCatching { from(obj) }.getOrNull()

        /** Returns an object of type [T] representing the converted [P1] object, or throws a [ConversionException] otherwise. */
        public fun from(obj: P1): T
    }

    /**
     * Factory that can convert a [P1] and a [P2] object to a [T] object.
     *
     * *Intended to be implemented by delegation by a companion object
     * using [converter] to offer
     * a [from] factory method and
     * a [fromOrNull] factory method.*
     *
     * @see Method Naming Convention
     */
    public interface Converter2 : Converter {
        /** Returns an object of type [T] representing the converted [P1] and [P2] object, or `null` otherwise. */
        public fun fromOrNull(obj1: P1, obj2: P2): T? = kotlin.runCatching { from(obj1, obj2) }.getOrNull()

        /** Returns an object of type [T] representing the converted [P1] and [P2] object, or throws a [ConversionException] otherwise. */
        public fun from(obj1: P1, obj2: P2): T
    }

    /**
     * Factory that can convert a [P1], a [P2], and a [P3] object to a [T] object.
     *
     * *Intended to be implemented by delegation by a companion object
     * using [converter] to offer
     * a [from] factory method and
     * a [fromOrNull] factory method.*
     *
     * @see Method Naming Convention
     */
    public interface Converter3 : Converter {
        /** Returns an object of type [T] representing the converted [P1], [P2], and [P3] object, or `null` otherwise. */
        public fun fromOrNull(obj1: P1, obj2: P2, obj3: P3): T? = kotlin.runCatching { from(obj1, obj2, obj3) }.getOrNull()

        /** Returns an object of type [T] representing the converted [P1], [P2], and [P3] object, or throws a [ConversionException] otherwise. */
        public fun from(obj1: P1, obj2: P2, obj3: P3): T
    }

    public companion object {
        /** Returns a [Converter1] that can convert a [P1] object to a [T] object using the specified [convertOrNull]. */
        public inline fun  converter(crossinline convertOrNull: (P1) -> T?): Converter1 = object : Converter1 {
            override fun from(obj: P1): T = kotlin.runCatching {
                convertOrNull(obj) ?: throw ConversionException(T::class, obj)
            }.getOrElse {
                if (it is ConversionException) throw it
                throw throw ConversionException(T::class, it, obj)
            }
        }

        /** Returns a [Converter2] that can convert a [P1] and [P2] object to a [T] object using the specified [convertOrNull]. */
        public inline fun  converter(crossinline convertOrNull: (P1, P2) -> T?): Converter2 =
            object : Converter2 {
                override fun from(obj1: P1, obj2: P2): T = kotlin.runCatching {
                    convertOrNull(obj1, obj2) ?: throw ConversionException(T::class, obj1, obj2)
                }.getOrElse {
                    if (it is ConversionException) throw it
                    throw throw ConversionException(T::class, it, obj1, obj2)
                }
            }

        /** Returns a [Converter3] that can convert a [P1], a [P2], and a [P3] object to a [T] object using the specified [convertOrNull]. */
        public inline fun  converter(crossinline convertOrNull: (P1, P2, P3) -> T?): Converter3 =
            object : Converter3 {
                override fun from(obj1: P1, obj2: P2, obj3: P3): T = kotlin.runCatching {
                    convertOrNull(obj1, obj2, obj3) ?: throw ConversionException(T::class, obj1, obj2, obj3)
                }.getOrElse {
                    if (it is ConversionException) throw it
                    throw throw ConversionException(T::class, it, obj1, obj2, obj3)
                }
            }
    }

    /** Exception thrown by a [Converter] when conversion fails. */
    public class ConversionException(
        message: String,
        /** Optional cause of this exception. */
        cause: Throwable? = null,
    ) : IllegalArgumentException(message, cause) {
        /** Creates a new converter exception for the specified [objects], the specified [type], and the optional [cause]. */
        public constructor(
            type: KClass<*>,
            cause: Throwable? = null,
            vararg objects: Any?,
        ) : this("Failed to convert ${objects.joinToString { it.quoted }} to an instance of ${type.simpleName ?: type.toString()}", cause)

        /** Creates a new converter exception for the specified [objects] and the specified [type]. */
        public constructor(
            type: KClass<*>,
            vararg objects: Any?,
        ) : this(type, null, *objects)
    }
}


/**
 * Parser than can parse a string into a [T] object.
 *
 * *Intended to be implemented by delegation by a companion object
 * using [parser] to offer
 * a [parse] factory method and
 * a [parseOrNull] factory method.*
 *
 * @see Method Naming Convention
 */
public interface Parser {
    /** Returns an object of type [T] representing the parsed [text], or `null` otherwise. */
    public fun parseOrNull(text: CharSequence): T? = kotlin.runCatching { parse(text) }.getOrNull()

    /** Returns an object of type [T] representing the parsed [text], or throws a [ParsingException] otherwise. */
    public fun parse(text: CharSequence): T

    public companion object {

        /** Returns a [Parser] that can parse a string into a [T] object using the specified [parse]. */
        public inline fun  parser(
            crossinline parse: (CharSequence) -> T?,
        ): Parser = object : AbstractParser(T::class) {
            override fun parseText(text: CharSequence): T? = parse.invoke(text)
        }
    }
}

/** Exception thrown by a [Parser] when parsing fails. */
public class ParsingException(
    message: String,
    /** Optional cause of this exception. */
    cause: Throwable? = null,
) : IllegalArgumentException(message, cause) {
    /** Creates a new parse exception for the specified [string], the specified [type], and the optional [cause]. */
    public constructor(
        string: CharSequence,
        type: KClass<*>,
        cause: Throwable? = null,
    ) : this("Failed to parse ${string.quoted} into an instance of ${type.simpleName ?: type.toString()}", cause)
}

/**
 * Provides a skeletal implementation of the [Parser] interface.
 */
public abstract class AbstractParser(
    private val kClass: KClass,
) : Parser {
    protected abstract fun parseText(text: CharSequence): T?

    override fun parse(text: CharSequence): T = kotlin.runCatching {
        parseText(text) ?: throw ParsingException(text, kClass)
    }.getOrElse {
        if (it is ParsingException) throw it
        throw throw ParsingException(text, kClass, it)
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy