Skip to content

Commit

Permalink
Add iron-borer module providing borer CBOR and JSON codecs for refi…
Browse files Browse the repository at this point in the history
…ned types
  • Loading branch information
sirthias committed Jan 24, 2024
1 parent a10396c commit ab0c680
Show file tree
Hide file tree
Showing 4 changed files with 537 additions and 455 deletions.
24 changes: 24 additions & 0 deletions borer/src/io/github/iltotore/iron/borer.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.github.iltotore.iron

import io.bullet.borer.{Encoder, Decoder}

/**
* Automatic construction of borer [[Encoder]] and [[Decoder]] instances for refined types.
*/
object borer:

inline given [A, B](using inline encoder: Encoder[A]): Encoder[A :| B] =
encoder.asInstanceOf[Encoder[A :| B]]

inline given [A, B](using inline decoder: Decoder[A], inline constraint: Constraint[A, B]): Decoder[A :| B] =
Decoder { r =>
decoder.read(r).refineEither match
case Left(msg) => r.validationFailure(msg)
case Right(x) => x
}

inline given [T](using m: RefinedTypeOps.Mirror[T], ev: Encoder[m.IronType]): Encoder[T] =
ev.asInstanceOf[Encoder[T]]

inline given [T](using m: RefinedTypeOps.Mirror[T], ev: Decoder[m.IronType]): Decoder[T] =
ev.asInstanceOf[Decoder[T]]
31 changes: 31 additions & 0 deletions borer/test/src/io/github/iltotore/iron/BorerSuite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.github.iltotore.iron

import io.github.iltotore.iron.constraint.all.*
import io.github.iltotore.iron.borer.given
import utest.*
import io.bullet.borer.{Encoder, Json}

object BorerSuite extends TestSuite:

val tests: Tests = Tests {

test("opaque alias encoding") {
Json.encode(Temperature(15.0)).toUtf8String ==> "15.0"
}

test("opaque alias decoding") {
Json.decode("15.0".getBytes).to[Temperature].valueEither ==> Right(Temperature(15.0))
Json.decode("-15.0".getBytes).to[Temperature].valueEither.left.map(_.getMessage) ==>
Left("Should be strictly positive (input position 0)")
}

test("transparent alias encoding") {
Json.encode(15.0:Moisture).toUtf8String ==> "15.0"
}

test("transparent alias decoding") {
Json.decode("15.0".getBytes).to[Moisture].valueEither ==> Right(15.0:Moisture)
Json.decode("-15.0".getBytes).to[Moisture].valueEither.left.map(_.getMessage) ==>
Left("Should be strictly positive (input position 0)")
}
}
13 changes: 13 additions & 0 deletions borer/test/src/io/github/iltotore/iron/RefinedOpsTypes.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.github.iltotore.iron

import io.github.iltotore.iron.*
import io.github.iltotore.iron.constraint.numeric.Positive

/**
* We declare test types here, in a separate file, in order to make the opaque aliases truly opaque.
*/
opaque type Temperature = Double :| Positive
object Temperature extends RefinedTypeOps[Double, Positive, Temperature]

type Moisture = Double :| Positive
object Moisture extends RefinedTypeOps.Transparent[Moisture]
Loading

0 comments on commit ab0c680

Please sign in to comment.