Skip to content

Commit

Permalink
Add codec support for either and subtypes
Browse files Browse the repository at this point in the history
  • Loading branch information
vlovgr committed May 12, 2020
1 parent 241421e commit aba6aed
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 0 deletions.
21 changes: 21 additions & 0 deletions modules/core/src/main/scala/vulcan/Codec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,15 @@ final object Codec {
}
)

/**
* @group General
*/
implicit final def either[A, B](
implicit codecA: Codec[A],
codecB: Codec[B]
): Codec[Either[A, B]] =
Codec.union(alt => alt[Left[A, B]] |+| alt[Right[A, B]])

/**
* Returns the result of encoding the specified value.
*
Expand Down Expand Up @@ -780,6 +789,12 @@ final object Codec {
}
)

/**
* @group General
*/
implicit final def left[A, B](implicit codec: Codec[A]): Codec[Left[A, B]] =
codec.imap(Left[A, B](_))(_.value)

/**
* @group Collection
*/
Expand Down Expand Up @@ -1240,6 +1255,12 @@ final object Codec {
)
}

/**
* @group General
*/
implicit final def right[A, B](implicit codec: Codec[B]): Codec[Right[A, B]] =
codec.imap(Right[A, B](_))(_.value)

/**
* @group Collection
*/
Expand Down
18 changes: 18 additions & 0 deletions modules/core/src/main/scala/vulcan/Prism.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ final object Prism extends PrismLowPriority {
}
}

/**
* Returns a new [[Prism]] from `Either[A, B]` to `Left[A, B]`.
*/
implicit final def left[A, B]: Prism[Either[A, B], Left[A, B]] =
Prism.instance[Either[A, B], Left[A, B]] {
case left @ Left(_) => Some(left)
case Right(_) => None
}(left => left)

/**
* Returns a new [[Prism]] from `Option` to `None`.
*/
Expand All @@ -74,6 +83,15 @@ final object Prism extends PrismLowPriority {
final def partial[S, A](get: PartialFunction[S, A])(reverseGet: A => S): Prism[S, A] =
Prism.instance(get.lift)(reverseGet)

/**
* Returns a new [[Prism]] from `Either[A, B]` to `Right[A, B]`.
*/
implicit final def right[A, B]: Prism[Either[A, B], Right[A, B]] =
Prism.instance[Either[A, B], Right[A, B]] {
case Left(_) => None
case right @ Right(_) => Some(right)
}(right => right)

/**
* Returns a new [[Prism]] from `Option` to `Some`.
*/
Expand Down
50 changes: 50 additions & 0 deletions modules/core/src/test/scala/vulcan/CodecSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,56 @@ final class CodecSpec extends BaseSpec {
}
}

describe("either") {
describe("schema") {
it("should be encoded as union") {
assertSchemaIs[Either[Int, Double]] {
"""["int","double"]"""
}
}
}

describe("encode") {
it("should encode left using left schema") {
assertEncodeIs[Either[Int, Double]](
Left(1),
Right(1)
)
}

it("should encode right using right schema") {
assertEncodeIs[Either[Int, Double]](
Right(1d),
Right(1d)
)
}
}

describe("decode") {
it("should error if schema type not in union") {
assertDecodeError[Either[Int, Double]](
unsafeEncode[Either[Int, Double]](Right(1d)),
unsafeSchema[String],
"Exhausted alternatives for type java.lang.Double"
)
}

it("should decode left value as left") {
assertDecodeIs[Either[Int, Double]](
unsafeEncode[Either[Int, Double]](Left(1)),
Right(Left(1))
)
}

it("should decode right value as right") {
assertDecodeIs[Either[Int, Double]](
unsafeEncode[Either[Int, Double]](Right(1d)),
Right(Right(1d))
)
}
}
}

describe("encode") {
it("should encode using codec for type") {
forAll { n: Int =>
Expand Down

0 comments on commit aba6aed

Please sign in to comment.