
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