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

com.nrinaudo.fetch.ValueFormat.scala Maven / Gradle / Ivy

The newest version!
package com.nrinaudo.fetch

import java.nio.charset.Charset

import scala.annotation.implicitNotFound
import scala.util.Try


// - Value reading -----------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------
object ValueReader {
  /** Transforms the specified function into an instance of [[ValueReader]]. */
  def apply[T](f: String => Option[T]): ValueReader[T] = new ValueReader[T] {
    override def read(value: String): Option[T] = f(value)
  }

  /** Acts as a [[ValueReader]] for sequences of the specified type.
    *
    * This method will yield an instance of `None` if at least one of the specified list's values is not legal.
    */
  def sequence[T: ValueReader](values: Seq[String]): Option[List[T]] =
    values.map(implicitly[ValueReader[T]].read).foldRight(Some(Nil): Option[List[T]]) {
      case (Some(v), Some(list)) => Some(v :: list)
      case _                     => None
    }
}

/** Used to read parameter values from an instance of [[Parameters]]. */
@implicitNotFound(msg = "Cannot find a ValueReader type class for ${T}")
trait ValueReader[T] {
  /** Extract an instance of `T` from the specified value. */
  def read(value: String): Option[T]
}



// - Value Writing -----------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------
object ValueWriter {
  /** Transforms the specified function into an instance of [[ValueWriter]]. */
  def apply[T](f: T => Option[String]): ValueWriter[T] = new ValueWriter[T] {
    override def write(value: T): Option[String] = f(value)
  }

  /** Acts as a [[ValueWriter]] for sequences of the specified type. */
  def sequence[T: ValueWriter](values: Seq[T]): Option[Seq[String]] =
    values.map(implicitly[ValueWriter[T]].write).collect {
      case Some(v) => v
    } match {
      case Nil => None
      case list => Some(list)
    }
}

/** Used to write parameter values to an instance of [[Parameters]]. */
@implicitNotFound(msg = "Cannot find a ValueWriter type class for ${T}")
trait ValueWriter[T] {
  /** Writes the specified `T` to a `String`. A return value of `None` means that the specified value serialises to
    * nothing (the empty string, `Nil`, ...).
    */
  def write(value: T): Option[String]
}



// - Formats -----------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------
object ValueFormat {
  // - Standard formatters ---------------------------------------------------------------------------------------------
  // -------------------------------------------------------------------------------------------------------------------
  // TODO: Should empty strings format as None by default?
  val Doubles: ValueFormat[Double]   = apply(s => Try(s.toDouble).toOption,  d => Some {d.toString})
  val Longs: ValueFormat[Long]       = apply(s => Try(s.toLong).toOption,    l => Some {l.toString})
  val Shorts: ValueFormat[Short]     = apply(s => Try(s.toShort).toOption,   s => Some {s.toString})
  val Ints: ValueFormat[Int]         = apply(s => Try(s.toInt).toOption,     i => Some {i.toString})
  val Bytes: ValueFormat[Byte]       = apply(s => Try(s.toByte).toOption,    b => Some {b.toString})
  val Floats: ValueFormat[Float]     = apply(s => Try(s.toFloat).toOption,   f => Some {f.toString})
  val Booleans: ValueFormat[Boolean] = apply(s => Try(s.toBoolean).toOption, b => Some {b.toString})
  val Strings: ValueFormat[String]   = apply(Some(_),                        Some(_))
  val Chars: ValueFormat[Char]       = apply(s => if(s.length == 1) Some(s.charAt(0)) else None, b => Some(b.toString))
  val Charsets: ValueFormat[Charset] = new ValueFormat[Charset] {
    override def write(value: Charset): Option[String] = Some(value.name())
    override def read(value: String): Option[Charset] = Try(Charset.forName(value)).toOption
  }

  /** Transforms the specified functions into an instance of [[ValueFormat]]. */
  def apply[T](f: String => Option[T], g: T => Option[String]): ValueFormat[T] = apply(ValueReader(f), ValueWriter(g))

  /** Transforms the specified [[ValueReader]] and [[ValueWriter]] into an instance of [[ValueFormat]]. */
  def apply[T](reader: ValueReader[T], writer: ValueWriter[T]): ValueFormat[T] = new ValueFormat[T] {
    override def write(value: T): Option[String] = writer.write(value)
    override def read(value: String): Option[T] = reader.read(value)
  }
}

/** Compounds a [[ValueReader]] and [[ValueWriter]]. */
trait ValueFormat[T] extends ValueReader[T] with ValueWriter[T]




© 2015 - 2024 Weber Informatics LLC | Privacy Policy