summaryrefslogtreecommitdiff
path: root/src/main/scala/cc/spray/json/lenses/package.scala
blob: 685a52b142c7864fab8e42ed58d00951a2a02744 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package cc.spray.json

package object lenses {
  type JsPred = JsValue => Boolean
  type Id[T] = T
  type Validated[T] = Either[Exception, T]
  type SafeJsValue = Validated[JsValue]

  type Operation = SafeJsValue => SafeJsValue

  type ScalarProjection = Projection[Id]
  type OptProjection = Projection[Option]
  type SeqProjection = Projection[Seq]

  def ??? = sys.error("NYI")
  def unexpected(message: String) = Left(new RuntimeException(message))
  def outOfBounds(message: String) = Left(new IndexOutOfBoundsException(message))

  implicit def rightBiasEither[A, B](e: Either[A, B]): Either.RightProjection[A, B] = e.right

  case class GetOrThrow[B](e: Either[Throwable, B]) {
    def getOrThrow: B = e match {
      case Right(b) => b
      case Left(e) => throw e
    }
  }

  implicit def orThrow[B](e: Either[Throwable, B]): GetOrThrow[B] = GetOrThrow(e)

  trait Reader[T] {
    def read(js: JsValue): Validated[T]
  }

  object Reader {
    implicit def safeMonadicReader[T: JsonReader]: Reader[T] = new Reader[T] {
      def read(js: JsValue): Validated[T] =
        safe(js.convertTo[T])
    }
  }

  def safe[T](body: => T): Validated[T] =
    try {
      Right(body)
    } catch {
      case e: Exception => Left(e)
    }

  case class ValidateOption[T](option: Option[T]) {
    def getOrError(message: => String): Validated[T] = option match {
      case Some(t) => Right(t)
      case None => unexpected(message)
    }
  }

  implicit def validateOption[T](o: Option[T]): ValidateOption[T] = ValidateOption(o)
}