Skip to content

Commit

Permalink
Java time instances (arrow-kt#84)
Browse files Browse the repository at this point in the history
* fix and try java instances

* move collection codecs to its own file

* create and test java time instances

* add todos

* generate encoders/decoders properly

* format
  • Loading branch information
AdrianRaFo authored Jul 13, 2019
1 parent c15cc32 commit 520ed1d
Show file tree
Hide file tree
Showing 11 changed files with 585 additions and 497 deletions.
8 changes: 4 additions & 4 deletions helios-core/src/main/kotlin/helios/core/helios.kt
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,13 @@ sealed class JsNumber : Json() {
}

open fun toShort(): Option<Short> = toLong().let {
val asShort: Short = it.toShort()
if (asShort.compareTo(it) == 0) Some(asShort) else None
val asShort: Short = it.toShort()
if (asShort.compareTo(it) == 0) Some(asShort) else None
}

open fun toByte(): Option<Byte> = toLong().let {
val asByte: Byte = it.toByte()
if (asByte.compareTo(it) == 0) Some(asByte) else None
val asByte: Byte = it.toByte()
if (asByte.compareTo(it) == 0) Some(asByte) else None
}

override fun equals(other: Any?): Boolean = JsNumber.eq().run {
Expand Down
101 changes: 101 additions & 0 deletions helios-core/src/main/kotlin/helios/instances/instancesCollections.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package helios.instances

import arrow.core.*
import arrow.core.extensions.either.applicative.applicative
import arrow.core.extensions.either.applicative.map2
import arrow.data.extensions.list.foldable.foldLeft
import arrow.data.extensions.list.traverse.sequence
import arrow.data.fix
import arrow.extension
import helios.core.*
import helios.typeclasses.Decoder
import helios.typeclasses.Encoder
import helios.typeclasses.KeyDecoder
import helios.typeclasses.KeyEncoder
import kotlin.collections.mapOf


@extension
interface ListEncoderInstance<in A> : Encoder<List<A>> {

fun encoderA(): Encoder<A>

override fun List<A>.encode(): Json =
JsArray(map { encoderA().run { it.encode() } })

companion object {
operator fun <A> invoke(encoderA: Encoder<A>): Encoder<List<A>> =
object : ListEncoderInstance<A> {
override fun encoderA(): Encoder<A> = encoderA
}
}

}

@extension
interface ListDecoderInstance<out A> : Decoder<List<A>> {

fun decoderA(): Decoder<A>

override fun decode(value: Json): Either<DecodingError, List<A>> =
value.asJsArray().toList()
.flatMap { arr ->
arr.value.map { decoderA().decode(it) }
}.sequence(Either.applicative()).fix().map { it.fix().toList() }

companion object {
operator fun <A> invoke(decoderA: Decoder<A>): Decoder<List<A>> =
object : ListDecoderInstance<A> {
override fun decoderA(): Decoder<A> = decoderA
}
}

}

@extension
interface MapEncoderInstance<A, B> : Encoder<Map<A, B>> {

fun keyEncoderA(): KeyEncoder<A>
fun encoderB(): Encoder<B>

override fun Map<A, B>.encode(): Json =
JsObject(this.map { (key, value) -> (keyEncoderA().run { key.keyEncode() } to encoderB().run { value.encode() }) }.toMap())

companion object {
operator fun <A, B> invoke(keyEncoderA: KeyEncoder<A>, encoderB: Encoder<B>): Encoder<Map<A, B>> =
object : MapEncoderInstance<A, B>, Encoder<Map<A, B>> {
override fun keyEncoderA(): KeyEncoder<A> = keyEncoderA
override fun encoderB(): Encoder<B> = encoderB
}
}

}

@extension
interface MapDecoderInstance<A, B> : Decoder<Map<A, B>> {

fun keyDecoderA(): KeyDecoder<A>
fun decoderB(): Decoder<B>

override fun decode(value: Json): Either<DecodingError, Map<A, B>> =
value.asJsObject().fold({ ObjectDecodingError(value).left() }, { obj ->
obj.value.map { (key, value) ->
val maybeKey: Either<DecodingError, A> =
Json.parseFromString(key).mapLeft { StringDecodingError(value) }.flatMap { keyDecoderA().keyDecode(it) }
val maybeValue: Either<DecodingError, B> = decoderB().decode(value)
maybeKey.map2(maybeValue) { mapOf(it.toPair()) }
}
.foldLeft<Either<DecodingError, Map<A, B>>, Either<DecodingError, Map<A, B>>>(arrow.core.mapOf<A, B>().right()) { acc, either ->
acc.map2(either) { it.a + it.b }
}
})

companion object {
operator fun <A, B> invoke(keyDecoderA: KeyDecoder<A>, decoderB: Decoder<B>): Decoder<Map<A, B>> =
object : MapDecoderInstance<A, B> {
override fun keyDecoderA(): KeyDecoder<A> = keyDecoderA
override fun decoderB(): Decoder<B> = decoderB
}
}

}
107 changes: 23 additions & 84 deletions helios-core/src/main/kotlin/helios/instances/instancesJava.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,114 +16,53 @@ import java.math.BigDecimal
import java.math.BigInteger
import java.util.*

fun UUID.encoder() = object : Encoder<UUID> {
interface UUIDEncoderInstance : Encoder<UUID> {
override fun UUID.encode(): Json = JsString(this.toString())

companion object {
operator fun invoke() = object : UUIDEncoderInstance {}
}
}

fun UUID.decoder() = object : Decoder<UUID> {
interface UUIDDecoderInstance : Decoder<UUID> {
override fun decode(value: Json): Either<DecodingError, UUID> =
value.asJsString().map { UUID.fromString(it.value.toString()) }.toEither { StringDecodingError(value) }
}

fun BigDecimal.encoder() = object : Encoder<BigDecimal> {
override fun BigDecimal.encode(): Json = JsNumber(this)
}

fun BigDecimal.decoder() = object : Decoder<BigDecimal> {
override fun decode(value: Json): Either<DecodingError, BigDecimal> =
value.asJsNumber().map { it.toBigDecimal() }.toEither { NumberDecodingError(value) }
}

fun BigInteger.encoder() = object : Encoder<BigInteger> {
override fun BigInteger.encode(): Json = JsNumber(this)
}

fun BigInteger.decoder() = object : Decoder<BigInteger> {
override fun decode(value: Json): Either<DecodingError, BigInteger> =
value.asJsNumber().map { it.toBigInteger() }.toEither { NumberDecodingError(value) }
companion object {
operator fun invoke() = object : UUIDDecoderInstance {}
}
}

@extension
interface ListEncoderInstance<in A> : Encoder<List<A>> {

fun encoderA(): Encoder<A>

override fun List<A>.encode(): Json =
JsArray(map { encoderA().run { it.encode() } })
interface BigDecimalEncoderInstance : Encoder<BigDecimal> {
override fun BigDecimal.encode(): Json = JsNumber(this)

companion object {
operator fun <A> invoke(encoderA: Encoder<A>): Encoder<List<A>> =
object : ListEncoderInstance<A> {
override fun encoderA(): Encoder<A> = encoderA
}
operator fun invoke() = object : BigDecimalEncoderInstance {}
}

}

@extension
interface ListDecoderInstance<out A> : Decoder<List<A>> {

fun decoderA(): Decoder<A>

override fun decode(value: Json): Either<DecodingError, List<A>> =
value.asJsArray().toList()
.flatMap { arr ->
arr.value.map { decoderA().decode(it) }
}.sequence(Either.applicative()).fix().map { it.fix().toList() }
interface BigDecimalDecoderInstance : Decoder<BigDecimal> {
override fun decode(value: Json): Either<DecodingError, BigDecimal> =
value.asJsNumber().map { it.toBigDecimal() }.toEither { NumberDecodingError(value) }

companion object {
operator fun <A> invoke(decoderA: Decoder<A>): Decoder<List<A>> =
object : ListDecoderInstance<A> {
override fun decoderA(): Decoder<A> = decoderA
}
operator fun invoke() = object : BigDecimalDecoderInstance {}
}

}

@extension
interface MapEncoderInstance<A, B> : Encoder<Map<A, B>> {

fun keyEncoderA(): KeyEncoder<A>
fun encoderB(): Encoder<B>

override fun Map<A, B>.encode(): Json =
JsObject(this.map { (key, value) -> (keyEncoderA().run { key.keyEncode() } to encoderB().run { value.encode() }) }.toMap())
interface BigIntegerEncoderInstance : Encoder<BigInteger> {
override fun BigInteger.encode(): Json = JsNumber(this)

companion object {
operator fun <A, B> invoke(keyEncoderA: KeyEncoder<A>, encoderB: Encoder<B>): Encoder<Map<A, B>> =
object : MapEncoderInstance<A, B>, Encoder<Map<A, B>> {
override fun keyEncoderA(): KeyEncoder<A> = keyEncoderA
override fun encoderB(): Encoder<B> = encoderB
}
operator fun invoke() = object : BigIntegerEncoderInstance {}
}

}

@extension
interface MapDecoderInstance<A, B> : Decoder<Map<A, B>> {

fun keyDecoderA(): KeyDecoder<A>
fun decoderB(): Decoder<B>

override fun decode(value: Json): Either<DecodingError, Map<A, B>> =
value.asJsObject().fold({ ObjectDecodingError(value).left() }, { obj ->
obj.value.map { (key, value) ->
val maybeKey: Either<DecodingError, A> =
Json.parseFromString(key).mapLeft { StringDecodingError(value) }.flatMap { keyDecoderA().keyDecode(it) }
val maybeValue: Either<DecodingError, B> = decoderB().decode(value)
maybeKey.map2(maybeValue) { mapOf(it.toPair()) }
}
.foldLeft<Either<DecodingError, Map<A, B>>, Either<DecodingError, Map<A, B>>>(mapOf<A, B>().right()) { acc, either ->
acc.map2(either) { it.a + it.b }
}
})
interface BigIntegerDecoderInstance : Decoder<BigInteger> {
override fun decode(value: Json): Either<DecodingError, BigInteger> =
value.asJsNumber().map { it.toBigInteger() }.toEither { NumberDecodingError(value) }

companion object {
operator fun <A, B> invoke(keyDecoderA: KeyDecoder<A>, decoderB: Decoder<B>): Decoder<Map<A, B>> =
object : MapDecoderInstance<A, B> {
override fun keyDecoderA(): KeyDecoder<A> = keyDecoderA
override fun decoderB(): Decoder<B> = decoderB
}
operator fun invoke() = object : BigIntegerDecoderInstance {}
}

}
Loading

0 comments on commit 520ed1d

Please sign in to comment.