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

kreuzberg.extras.forms.Codec.scala Maven / Gradle / Ivy

There is a newer version: 0.10.3
Show newest version
package kreuzberg.extras.forms

import kreuzberg.extras.forms.Error.DecodingError

import scala.util.control.NonFatal

/** Lifts a value from an encoding */
trait Codec[U, T] {

  /** Encodes a value into a string. */
  def encode(value: U): T

  /** Decodes the value, either an error or the decoded value. */
  def decode(encoded: T): DecodingResult[U]

  /** Decode a value or throw. */
  @throws[UnhandledDecodingError]
  final def decodeOrThrow(transport: T): U = decode(transport) match {
    case Left(failure) => throw UnhandledDecodingError(failure)
    case Right(value)  => value
  }

  /** Maps the encoded type to another type. */
  def xmap[V](mapFn: U => V, contraMapFn: V => U): Codec[V, T] = Codec.Xmap(this, mapFn, contraMapFn)
}

/** A not handled error in [[Codec.decodeOrThrow()]] */
case class UnhandledDecodingError(codecError: DecodingError)
    extends RuntimeException(codecError.asList.mkString(","), null, false, false)

object Codec {

  /** Construct from functions. */
  def fromEncoderAndDecoder[U, T](encoder: U => T, decoder: T => DecodingResult[U]): Codec[U, T] = new Codec[U, T] {
    override def encode(value: U): T = encoder(value)

    override def decode(encoded: T): DecodingResult[U] = decoder(encoded)
  }

  case class Xmap[A, B, E](underlying: Codec[A, E], mapFn: A => B, contraMapFn: B => A) extends Codec[B, E] {
    override def encode(value: B): E = underlying.encode(contraMapFn(value))

    override def decode(encoded: E): DecodingResult[B] = underlying.decode(encoded).map(mapFn)
  }

  given simpleString: Codec[String, String] with {
    override def encode(value: String): String = value

    override def decode(encoded: String): DecodingResult[String] = Right(encoded)
  }

  given simpleInt: Codec[Int, String] with {
    override def encode(value: Int): String = value.toString

    override def decode(encoded: String): DecodingResult[Int] = {
      try {
        Right(encoded.toInt)
      } catch {
        case NonFatal(_) => Left(Error.DecodingError("Invalid Integer"))
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy