All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.malliina.values.Readable.scala Maven / Gradle / Ivy

The newest version!
package com.malliina.values

import com.malliina.http.FullUrl
import com.malliina.measure.{DistanceM, SpeedM, Temperature}
import com.malliina.storage.StorageSize

import scala.util.Try

trait Readable[R] {
  def read(value: String): Either[ErrorMessage, R]
  def map[S](f: R => S): Readable[S] = (s: String) => read(s).map(f)
  def flatMap[S](f: R => Readable[S]): Readable[S] = (s: String) =>
    read(s).flatMap(r => f(r).read(s))
  def emap[S](f: R => Either[ErrorMessage, S]): Readable[S] = (s: String) => read(s).flatMap(f)
}

object Readable {
  implicit val string: Readable[String] = (s: String) => Right(s)
  implicit val int: Readable[Int] = fromTry("integer", s => Try(s.toInt))
  implicit val long: Readable[Long] = fromTry("long", s => Try(s.toLong))
  implicit val float: Readable[Float] = fromTry("float", s => Try(s.toFloat))
  implicit val double: Readable[Double] = fromTry("double", s => Try(s.toDouble))
  implicit val distance: Readable[DistanceM] = double.map(DistanceM.apply)
  implicit val speed: Readable[SpeedM] = double.map(SpeedM.apply)
  implicit val temperature: Readable[Temperature] = double.map(Temperature.apply)
  implicit val storageSize: Readable[StorageSize] = long.map(StorageSize.apply)
  implicit val boolean: Readable[Boolean] = string.emap {
    case "true"  => Right(true)
    case "false" => Right(false)
    case other   => Left(ErrorMessage(s"Invalid boolean: '$other'."))
  }
  implicit val url: Readable[FullUrl] = string.emap(FullUrl.build)

  private def fromTry[T](label: String, t: String => Try[T]) =
    string.emap(s => t(s).fold(_ => Left(ErrorMessage(s"Invalid $label: '$s'.")), v => Right(v)))
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy