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

io.taig.babel.DerivedDecoder.scala Maven / Gradle / Ivy

There is a newer version: 0.5.2
Show newest version
package io.taig.babel

import scala.compiletime.*
import scala.deriving.Mirror

trait DerivedDecoder[A] extends Decoder[A]

object DerivedDecoder {

  private inline def widen[A, B](a: A): A & B = inline a match { case b: B => b }

  private inline def recurse[Names, T <: Tuple](babel: Babel, path: Path): Either[Decoder.Error, T] =
    inline erasedValue[(Names, T)] match {
      case (_: (name *: names), _: (tpe *: types)) =>
        babel match {
          case Babel.Object(values) =>
            val segment = constValue[name].toString
            val step = path / segment
            val decoder = summonInline[Decoder[tpe]]

            val left = values.get(segment) match {
              case Some(value) => decoder.decode(value, step)
              case None =>
                decoder.decode(Babel.Null, step).left.map(_ => Decoder.Error("Missing key", step, cause = None))
            }

            for (head <- left; tail <- recurse[names, types](babel, path))
              yield widen[tpe *: types, T](head *: tail)

          case Babel.Value(_) => Left(Decoder.Error.typeMismatch(expected = "Object", actual = "Value", path))
          case Babel.Null     => Left(Decoder.Error.typeMismatch(expected = "Object", actual = "Null", path))

        }

      case (_: EmptyTuple, _) => Right(widen[EmptyTuple, T](EmptyTuple))
    }

  inline given derivedProduct[A](using m: Mirror.ProductOf[A]): DerivedDecoder[A] =
    (babel: Babel, path: Path) => recurse[m.MirroredElemLabels, m.MirroredElemTypes](babel, path).map(m.fromProduct)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy