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

com.freya02.botcommands.internal.Utils.kt Maven / Gradle / Ivy

package com.freya02.botcommands.internal

import com.freya02.botcommands.api.BCInfo
import com.freya02.botcommands.api.core.exceptions.InitializationException
import com.freya02.botcommands.api.core.exceptions.ServiceException
import com.freya02.botcommands.internal.utils.ReflectionUtils.shortSignature
import mu.KLogger
import mu.KotlinLogging
import mu.toKLogger
import net.dv8tion.jda.api.JDAInfo
import net.dv8tion.jda.api.exceptions.ErrorResponseException
import net.dv8tion.jda.api.requests.ErrorResponse
import org.slf4j.LoggerFactory
import java.lang.reflect.Executable
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
import java.lang.reflect.Modifier
import java.util.*
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
import kotlin.reflect.*
import kotlin.reflect.full.isSubclassOf
import kotlin.reflect.jvm.javaConstructor
import kotlin.reflect.jvm.javaMethod
import kotlin.reflect.jvm.jvmErasure

internal inline fun > enumSetOf(): EnumSet = EnumSet.noneOf(T::class.java)
internal inline fun > enumSetOf(vararg elems: T): EnumSet = enumSetOf().apply { addAll(elems) }
internal inline fun , V> enumMapOf(): EnumMap = EnumMap(T::class.java)

internal fun  List.toImmutableList(): List {
    return Collections.unmodifiableList(toMutableList())
}

internal fun  Set.toImmutableSet(): Set {
    return Collections.unmodifiableSet(toMutableSet())
}

internal fun  Map.toImmutableMap(): Map {
    return Collections.unmodifiableMap(LinkedHashMap(this))
}

internal fun KClass<*>.isSubclassOfAny(vararg classes: KClass<*>): Boolean = classes.any { this.isSubclassOf(it) }
internal fun KClass<*>.isSubclassOfAny(classes: Iterable>): Boolean = classes.any { this.isSubclassOf(it) }

internal fun throwInternal(message: String): Nothing =
    throw IllegalArgumentException("$message, please report this to the devs. ${getDiagVersion()}")

internal fun throwInternal(function: KFunction<*>, message: String): Nothing =
    throw IllegalArgumentException("${function.shortSignature} : $message, please report this to the devs. ${getDiagVersion()}")

internal fun getDiagVersion() = "[ BC version: ${BCInfo.VERSION} | Current JDA version: ${JDAInfo.VERSION} ]"

@Suppress("NOTHING_TO_INLINE") //Don't want this to appear in stack trace
internal inline fun throwUser(function: KFunction<*>, message: String): Nothing =
    throw IllegalArgumentException("${function.shortSignature} : $message")

@Suppress("NOTHING_TO_INLINE") //Don't want this to appear in stack trace
internal inline fun rethrowUser(function: KFunction<*>, message: String, e: Throwable): Nothing =
    throw RuntimeException("${function.shortSignature} : $message", e)

@Suppress("NOTHING_TO_INLINE") //Don't want this to appear in stack trace
internal inline fun rethrowUser(message: String, e: Throwable): Nothing =
    throw RuntimeException(message, e)

@PublishedApi
@Suppress("NOTHING_TO_INLINE") //Don't want this to appear in stack trace
internal inline fun throwUser(message: String): Nothing =
    throw IllegalArgumentException(message)

@Suppress("NOTHING_TO_INLINE") //Don't want this to appear in stack trace
internal inline fun throwService(message: String, function: KFunction<*>? = null): Nothing = when (function) {
    null -> throw ServiceException(message)
    else -> throw ServiceException("${function.shortSignature} : $message")
}

@OptIn(ExperimentalContracts::class)
internal inline fun requireUser(value: Boolean, function: KFunction<*>, lazyMessage: () -> String) {
    contract {
        returns() implies value
    }

    if (!value) {
        throwUser(function, lazyMessage())
    }
}

@OptIn(ExperimentalContracts::class)
internal inline fun requireUser(value: Boolean, lazyMessage: () -> String) {
    contract {
        returns() implies value
    }

    if (!value) {
        throwUser(lazyMessage())
    }
}

val KParameter.isPrimitive: Boolean
    get() = this.type.jvmErasure.java.isPrimitive || this.type.jvmErasure.javaPrimitiveType != null

val KParameter.bestName: String
    get() = this.name ?: "arg${this.index}"

fun String.asDiscordString(): String {
    val sb: StringBuilder = StringBuilder()

    for (c in this) {
        if (c.isUpperCase()) {
            sb.append('_').append(c.lowercaseChar())
        } else {
            sb.append(c)
        }
    }

    return sb.toString()
}

fun KParameter.findDeclarationName(): String {
//    val annotatedName = findAnnotation()?.declaredName
//    if (!annotatedName.isNullOrBlank()) {
//        return annotatedName
//    }

    return name ?: throwUser("Parameter '$this' does not have any name information, please add the compiler options to include those (see wiki or readme)")
}

fun KParameter.findOptionName(): String {
//    val annotatedName = findAnnotation()?.name
//    if (!annotatedName.isNullOrBlank()) {
//        return annotatedName
//    }

    return name ?: throwUser("Parameter '$this' does not have any name information, please add the compiler options to include those (see wiki or readme)")
}

val KType.simpleNestedName: String
    get() = buildString {
        append(jvmErasure.simpleNestedName)
        if (arguments.isNotEmpty()) {
            append("<")
            append(arguments.joinToString {
                it.type?.simpleNestedName ?: "*"
            })
            append(">")
        }
        if (isMarkedNullable) append("?")
    }

val KClass<*>.shortQualifiedName
    get() = java.packageName.split('.').joinToString(".") { it.first().toString() } + "." + simpleNestedName

val KClass<*>.simpleNestedName: String
    inline get() = this.java.simpleNestedName

val Class<*>.simpleNestedName: String
    get() = when {
        this.isPrimitive -> canonicalName
        this.isArray -> componentType.simpleNestedName + "[]"
        else -> this.canonicalName.substring(this.packageName.length + 1)
    }

fun  Class.toKotlin(): KClass = this.kotlin
fun  KClass.toJava(): Class = this.java

val KFunction<*>.isPublic: Boolean
    get() = this.visibility == KVisibility.PUBLIC || this.visibility == KVisibility.INTERNAL

val KFunction<*>.isStatic: Boolean
    get() = !isConstructor && Modifier.isStatic(this.javaMethodInternal.modifiers)

val KFunction<*>.isConstructor: Boolean
    get() = this.javaConstructor != null

val KFunction<*>.javaMethodOrConstructorOrNull: Executable?
    get() = javaMethod ?: javaConstructor

val KFunction<*>.javaMethodOrConstructor: Executable
    get() = javaMethodOrConstructorOrNull ?: throwInternal(this, "Could not resolve Java method or constructor")

val KFunction<*>.javaMethodInternal: Method
    get() = javaMethod ?: throwInternal(this, "Could not resolve Java method")

inline fun  arrayOfSize(size: Int) = ArrayList(size)

fun String.nullIfEmpty(): String? = when {
    isEmpty() -> null
    else -> this
}

fun Throwable.unreflect(): Throwable {
    if (this is InvocationTargetException) return targetException
    return this
}

inline fun  runInitialization(block: () -> R): R {
    try {
        return block()
    } catch (e: Throwable) {
        throw InitializationException("An exception occurred while building the framework", e)
    }
}

inline fun  Result.onErrorResponseException(block: (ErrorResponseException) -> Unit): Result {
    return also { onFailure { if (it is ErrorResponseException) block(it) } }
}

inline fun  Result.onErrorResponse(block: (ErrorResponse) -> Unit): Result {
    return onErrorResponseException { block(it.errorResponse) }
}

inline fun  Result.onErrorResponse(error: ErrorResponse, block: (ErrorResponseException) -> Unit): Result {
    return onErrorResponseException { if (it.errorResponse == error) block(it) }
}

internal inline fun  Any.throwMixin(): Nothing {
    throwInternal("${this::class.simpleName} should implement ${T::class.simpleName}")
}

@Suppress("UnusedReceiverParameter")
internal inline fun  KotlinLogging.logger(): KLogger =
    LoggerFactory.getLogger(T::class.java).toKLogger()




© 2015 - 2025 Weber Informatics LLC | Privacy Policy