Skip to content

Instantly share code, notes, and snippets.

@beer-avalanche
Last active September 10, 2024 18:54
Show Gist options
  • Save beer-avalanche/efb1e8e4c1b94197d21592b1f60a4f31 to your computer and use it in GitHub Desktop.
Save beer-avalanche/efb1e8e4c1b94197d21592b1f60a4f31 to your computer and use it in GitHub Desktop.
inline fun <reified K : Any> summon(): K {
val tpe = typeOf<K>()
return summon(tpe) as? K
?: error("Trait instance must be of type $tpe")
}
// FIXME: Come up with a way to make it sufficiently weak to prevent
// memory leaks due to accumulation of the underlying classes
// if class loaders are being closed.
private val instances = ConcurrentHashMap<KType, Any>()
fun summon(tpe: KType): Any {
return instances.computeIfAbsent(tpe) {
require(tpe.arguments.size == 1) {
"Multi-parameter traits are not supported"
}
val arg = tpe.arguments[0].type?.classifier as? KClass<*>
?: throw IllegalArgumentException("Trait's type parameter must be a class")
val companion = arg.companionObjectInstance
?: throw IllegalArgumentException("Trait's type parameter must have a companion object")
val companionType = arg.companionObject
?: throw IllegalArgumentException("Trait's type parameter must have a companion object")
val companionProperties = companionType.memberProperties
val count = companionProperties.count { it.returnType == tpe }
require(count == 1) {
"Companion object of the trait's type parameter must have exactly one property of trait's type $tpe"
}
val field = companionProperties.find { it.returnType == tpe }
?: throw IllegalArgumentException("Companion object of the trait's type parameter must have a property of trait's type $tpe")
field.getter.call(companion)
?: throw IllegalArgumentException("Trait instance must not be null")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment