Inject challenges input
This commit is contained in:
@@ -0,0 +1 @@
|
||||
package be.vandewalleh.aoc.utils
|
||||
@@ -1,28 +0,0 @@
|
||||
@file:Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
|
||||
package be.vandewalleh.aoc.utils
|
||||
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import kotlin.streams.asSequence
|
||||
|
||||
object Resources {
|
||||
private fun path(name: String): Path {
|
||||
val url = if (name.startsWith('/')) javaClass.getResource(name)
|
||||
else javaClass.getResource("/$name")
|
||||
return Path.of(url.toURI())
|
||||
}
|
||||
|
||||
private fun Path.lines() = Files.lines(this)
|
||||
.asSequence()
|
||||
.filter { it.isNotBlank() }
|
||||
.map { it.trim() }
|
||||
|
||||
private fun Path.text() = Files.readString(this).trim()
|
||||
|
||||
fun text(name: String) = path(name).text()
|
||||
fun lines(name: String) = path(name).lines()
|
||||
fun ints(name: String) = lines(name).map { it.toInt() }
|
||||
fun csv(name: String) = path(name).text().splitToSequence(",")
|
||||
fun csvLong(name: String) = csv(name).map { it.toLong() }
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package be.vandewalleh.aoc.utils.input
|
||||
|
||||
import io.micronaut.context.annotation.Prototype
|
||||
import io.micronaut.core.annotation.Introspected
|
||||
import javax.inject.Qualifier
|
||||
|
||||
@Prototype
|
||||
@Qualifier
|
||||
@Introspected
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
annotation class Day(val day: Int)
|
||||
|
||||
@Qualifier
|
||||
@Prototype
|
||||
annotation class DayInput
|
||||
|
||||
@DayInput
|
||||
annotation class Csv
|
||||
|
||||
@DayInput
|
||||
annotation class Text
|
||||
|
||||
@DayInput
|
||||
annotation class Lines
|
||||
@@ -0,0 +1,7 @@
|
||||
package be.vandewalleh.aoc.utils.input
|
||||
|
||||
/**
|
||||
* Wrapper class so that micronaut is not confused with an other injectable
|
||||
* container type when using an iterable / array
|
||||
*/
|
||||
data class Input<T>(val value: T)
|
||||
@@ -0,0 +1,76 @@
|
||||
package be.vandewalleh.aoc.utils.input
|
||||
|
||||
import io.micronaut.context.annotation.Factory
|
||||
import io.micronaut.inject.InjectionPoint
|
||||
import kotlin.io.path.ExperimentalPathApi
|
||||
import kotlin.io.path.readLines
|
||||
import kotlin.io.path.readText
|
||||
|
||||
/**
|
||||
* Load challenge inputs and convert them to the appropriate format
|
||||
*
|
||||
* contains horrible hacks while waiting for generic support in bean injection
|
||||
* @see [micronaut-2775](https://github.com/micronaut-projects/micronaut-core/issues/2775)
|
||||
*/
|
||||
@Factory
|
||||
@ExperimentalPathApi
|
||||
class InputFactory(private val resourceLoader: ResourceLoader) {
|
||||
|
||||
@Csv
|
||||
fun csvIntArray(injectionPoint: InjectionPoint<*>): Input<IntArray> = injectionPoint
|
||||
.read()
|
||||
.split(",")
|
||||
.map { it.toInt() }
|
||||
.toIntArray()
|
||||
.wrap()
|
||||
|
||||
@Lines
|
||||
fun linesIntArray(injectionPoint: InjectionPoint<*>): Input<*> =
|
||||
when (val param = injectionPoint.typeNameOfAnnotation<Lines>()) {
|
||||
"int[]" -> injectionPoint
|
||||
.lines()
|
||||
.map { it.toInt() }
|
||||
.toList()
|
||||
.toIntArray()
|
||||
.wrap()
|
||||
"java.util.List<java.lang.String>" -> injectionPoint
|
||||
.lines()
|
||||
.toList()
|
||||
.wrap()
|
||||
else -> error("Unsupported type $param")
|
||||
}
|
||||
|
||||
@Text
|
||||
fun string(injectionPoint: InjectionPoint<*>): Input<String> =
|
||||
injectionPoint.read().wrap()
|
||||
|
||||
|
||||
private fun <T> T.wrap() = Input(this)
|
||||
|
||||
private inline fun <reified T : Annotation> InjectionPoint<*>.typeNameOfAnnotation() = declaringBean
|
||||
.constructor
|
||||
.arguments
|
||||
.find { it.hasAnnotation<T>() }
|
||||
?.typeName
|
||||
?.removePrefix("be.vandewalleh.aoc.utils.input.Input<")
|
||||
?.removeSuffix(">")
|
||||
?: error("??")
|
||||
|
||||
private fun InjectionPoint<*>.path() = resourceLoader.ofDay(getDay(this))
|
||||
private fun InjectionPoint<*>.read() = path().readText().trim()
|
||||
private fun InjectionPoint<*>.lines() = path().readLines()
|
||||
.asSequence()
|
||||
.filter { it.isNotBlank() }
|
||||
|
||||
private fun getDay(injectionPoint: InjectionPoint<*>): Int {
|
||||
val dayAnnotation = injectionPoint
|
||||
.declaringBean
|
||||
.findAnnotation<Day>()
|
||||
|
||||
if (dayAnnotation.isEmpty)
|
||||
error("@DayInput cannot only be used on classes annotated with ${Day::class.qualifiedName}")
|
||||
|
||||
return dayAnnotation.get().intValue("day").asInt
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package be.vandewalleh.aoc.utils.input
|
||||
|
||||
import io.micronaut.core.annotation.AnnotationMetadataDelegate
|
||||
import io.micronaut.core.annotation.AnnotationMetadataProvider
|
||||
import io.micronaut.core.annotation.AnnotationValue
|
||||
import io.micronaut.core.beans.BeanIntrospection
|
||||
import java.util.*
|
||||
|
||||
internal inline fun <reified T> getIntrospection(): BeanIntrospection<T> =
|
||||
BeanIntrospection.getIntrospection(T::class.java)
|
||||
|
||||
internal inline fun <reified T : Annotation> AnnotationMetadataDelegate.getAnnotation(): AnnotationValue<T>? =
|
||||
getAnnotation(T::class.java)
|
||||
|
||||
internal inline fun <reified T : Annotation> AnnotationMetadataProvider.findAnnotation(): Optional<AnnotationValue<T>> =
|
||||
findAnnotation(T::class.java)
|
||||
|
||||
internal inline fun <reified T : Annotation> AnnotationMetadataProvider.hasAnnotation(): Boolean =
|
||||
findAnnotation(T::class.java).isPresent
|
||||
@@ -0,0 +1,21 @@
|
||||
package be.vandewalleh.aoc.utils.input
|
||||
|
||||
import java.nio.file.Path
|
||||
import javax.inject.Singleton
|
||||
|
||||
interface ResourceLoader {
|
||||
fun ofDay(day: Int): Path
|
||||
}
|
||||
|
||||
@Singleton
|
||||
class ResourceLoaderImpl : ResourceLoader {
|
||||
override fun ofDay(day: Int): Path {
|
||||
val resourcePath = buildString {
|
||||
append("/day")
|
||||
append(day.toString().padStart(2, '0'))
|
||||
append(".txt")
|
||||
}
|
||||
val url = javaClass.getResource(resourcePath)
|
||||
return Path.of(url.toURI())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<withJansi>true</withJansi>
|
||||
<encoder>
|
||||
<pattern>%cyan(%d{YYYY-MM-dd HH:mm:ss.SSS}) [%thread] %highlight(%-5level) %green(%logger{36}) - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
<logger name="io.micronaut" level="INFO"/>
|
||||
<logger name="io.micronaut.context.lifecycle" level="INFO"/>
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user