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

io.decomat.ProductClass.kt Maven / Gradle / Ivy

There is a newer version: 0.3.0
Show newest version
package io.decomat

import java.util.WeakHashMap
import kotlin.reflect.KProperty1
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.full.isSubclassOf
import kotlin.reflect.full.memberProperties
import kotlin.reflect.full.primaryConstructor

sealed interface ProductClass {
  val value: T
  fun isIfHas() =
    when(val thisComp = this) {
      is HasProductClass -> thisComp.productComponents
      else -> this
    }
}

private fun fail(msg: String): Nothing = throw IllegalArgumentException(msg)

// Does not seem to work, no annotations are found
//@Suppress("UNCHECKED_CAST")
//interface HasProductClassAuto: HasProductClass {
//  override val productComponents: ProductClass get() =
//    cache.computeIfAbsent(this) { _doInit() } as ProductClass
//
//  fun _doInit(): ProductClass {
//    val cls = this::class
//    val ctor = cls.primaryConstructor ?: fail("No primary constructor found in the class ${this}")
//    println(cls.memberProperties.map { "${it.name} (${it.annotations})" })
//    val componentNames = ctor.parameters.filter { it.annotations.any { anno -> anno.annotationClass.qualifiedName == "io.decomat.Component" } }.map { it.name }
//    if (componentNames.isEmpty()) fail("No components annotated with @Component found in the class ${this}. Found components: ${ctor.parameters.map { it.name }}.")
//    val components: List, *>> =
//      cls.memberProperties.filter { componentNames.contains(it.name) }
//    if (components.size != componentNames.size)
//      fail("Not all the parameters with @Component annoations (${componentNames.joinToString(", ")}) were found to be components (${components.joinToString { "," }})")
//
//    fun comp(i: Int) = components[i].getter.call(this)
//
//    val productClass =
//      when(components.size) {
//        1 -> ProductClass1(this as T, comp(0))
//        2 -> ProductClass2(this as T, comp(0), comp(1))
//        3 -> ProductClass3(this as T, comp(0), comp(1), comp(2))
//        else -> fail("Num components needs to be 1, 2, or 3 but was: ${components.size}")
//      }
//
//    return productClass
//  }
//
//  // Sigh, need to use a global cache to compute product-classes we've since since you can't assign
//  // values directly to varaibles inside of kotlin interfaces
//  companion object {
//    val cache = WeakHashMap, ProductClass<*>>()
//  }
//}

interface HasProductClass: ProductClass {
  val productComponents: ProductClass
  override val value get() = productComponents.value
}

fun  productComponentsOf(host: T) = ProductClass0(host)
fun  productComponentsOf(host: T, componentA: A) = ProductClass1(host, componentA)
fun  productComponentsOf(host: T, componentA: A, componentB: B) = ProductClass2(host, componentA, componentB)
fun  productComponentsOf(host: T, componentA: A, componentB: B, componentC: C) = ProductClass3(host, componentA, componentB, componentC)

data class ProductClass0(override val value: T): ProductClass
data class ProductClass1(override val value: T, val a: A): ProductClass
data class ProductClass2(override val value: T, val a: A, val b: B): ProductClass {
  val matchComp get(): Components2 = Components2(a, b)
}

// For example: data class FlatMap(head: Query, body: Query) extends Comp3
data class ProductClass3(override val value: T, val a: A, val b: B, val c: C): ProductClass


sealed interface Components
data class Components1(val a: A): Components
// For example: data class FlatMap(head: Query, body: Query) extends Comp2
data class Components2(val a: A, val b: B): Components
data class Components3(val a: A, val b: B, val c: C): Components




© 2015 - 2024 Weber Informatics LLC | Privacy Policy