Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow registration of custom Show typeclasses #2021 #2023

Merged
merged 3 commits into from Jan 30, 2021
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -17,6 +17,46 @@ interface Show<in A> {
fun show(a: A): Printed
}

/**
* Global object that allows for registration of custom [Show] typeclasses.
*/
object Shows {

private val shows = mutableMapOf<KClass<*>, Show<*>>().apply {
put(String::class, StringShow)
put(Map::class, MapShow)
put(BooleanArray::class, ArrayShow)
put(IntArray::class, ArrayShow)
put(ShortArray::class, ArrayShow)
put(FloatArray::class, ArrayShow)
put(DoubleArray::class, ArrayShow)
put(LongArray::class, ArrayShow)
put(ByteArray::class, ArrayShow)
put(CharArray::class, ArrayShow)
put(Array::class, ArrayShow)
put(List::class, ListShow<Any>())
put(Iterable::class, IterableShow<Any>())
put(Long::class, DefaultShow)
put(Int::class, DefaultShow)
put(Short::class, DefaultShow)
put(Byte::class, DefaultShow)
put(Double::class, DefaultShow)
put(Float::class, DefaultShow)
put(Boolean::class, DefaultShow)
put(KClass::class, KClassShow)
}

fun <T : Any> add(kclass: KClass<out T>, show: Show<T>) {
shows[kclass] = show
}

fun remove(kclass: KClass<*>) {
shows.remove(kclass)
}

fun all() = shows.toMap()
}

/**
* Represents a value that has been appropriately formatted for display in output logs or error messages.
* For example, a null might be formatted as <null>.
Expand All @@ -32,27 +72,13 @@ fun <T : Any> showFor(t: T): Show<T> = platformShow(t) ?: commonShowFor(t)
expect fun <A : Any> platformShow(a: A): Show<A>?

@Suppress("UNCHECKED_CAST")
fun <T : Any> commonShowFor(t: T): Show<T> = when (t) {
is String -> StringShow as Show<T>
is Map<*, *> -> MapShow as Show<T>
is BooleanArray -> ArrayShow
is IntArray -> ArrayShow
is ShortArray -> ArrayShow
is FloatArray -> ArrayShow
is DoubleArray -> ArrayShow
is LongArray -> ArrayShow
is ByteArray -> ArrayShow
is CharArray -> ArrayShow
is Array<*> -> ArrayShow
is List<*> -> ListShow<T>() as Show<T>
is Iterable<*> -> IterableShow<T>() as Show<T>
is Long, t is Boolean, t is Int, t is Double, t is Float, t is Short, t is Byte -> DefaultShow
is KClass<*> -> KClassShow as Show<T>
else -> when {
// this won't work in JS or native, so they'll get the boring old toString version
io.kotest.mpp.reflection.isDataClass(t::class) -> dataClassShow<T>()
else -> DefaultShow
}
fun <T : Any> commonShowFor(t: T): Show<T> {
// lookup a show from the registered typeclasses
val kclass = Shows.all().keys.firstOrNull { it.isInstance(t) }
if (kclass != null) Shows.all()[kclass] as Show<T>
ashishkujoy marked this conversation as resolved.
Show resolved Hide resolved
// this won't work in JS or native, so they'll get the boring old toString version
if (io.kotest.mpp.reflection.isDataClass(t::class)) return dataClassShow<T>()
return DefaultShow
}

internal fun recursiveRepr(root: Any, node: Any?): Printed {
Expand Down