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

julienrf.json.derived.DerivedReads.scala Maven / Gradle / Ivy

There is a newer version: 6.0.0
Show newest version
package julienrf.json.derived

import play.api.libs.json.{Reads, __, JsError}
import shapeless.labelled.{FieldType, field}
import shapeless.{::, HList, HNil, LabelledGeneric, Lazy, Witness, Coproduct, :+:, Inr, Inl, CNil}

trait DerivedReads[A] {
  def reads(tagReads: TypeTagReads): Reads[A]
}

object DerivedReads extends DerivedReadsInstances

trait DerivedReadsInstances extends DerivedReadsInstances1 {

  implicit val readsCNil: DerivedReads[CNil] =
    new DerivedReads[CNil] {
      def reads(tagReads: TypeTagReads) = Reads[CNil] { _ => JsError("error.sealed.trait") }
    }

  implicit def readsCoProduct[K <: Symbol, L, R <: Coproduct](implicit
    typeName: Witness.Aux[K],
    readL: Lazy[DerivedReads[L]],
    readR: Lazy[DerivedReads[R]]
  ): DerivedReads[FieldType[K, L] :+: R] =
    new DerivedReads[FieldType[K, L] :+: R] {
      def reads(tagReads: TypeTagReads) =
        tagReads.reads(typeName.value.name, Reads[L](json => readL.value.reads(tagReads).reads(json)))
          .map[FieldType[K, L] :+: R](l => Inl(field[K](l)))
          .orElse(readR.value.reads(tagReads).map(r => Inr(r)))
  }

  implicit val readsHNil: DerivedReads[HNil] =
    new DerivedReads[HNil] {
      def reads(tagReads: TypeTagReads) = Reads.pure[HNil](HNil)
    }

  implicit def readsLabelledHListOpt[K <: Symbol, H, T <: HList](implicit
    fieldName: Witness.Aux[K],
    readH: Lazy[Reads[H]],
    readT: Lazy[DerivedReads[T]]
  ): DerivedReads[FieldType[K, Option[H]] :: T] =
    new DerivedReads[FieldType[K, Option[H]] :: T] {
      def reads(tagReads: TypeTagReads) =
        Reads.applicative.apply(
          (__ \ fieldName.value.name).readNullable(readH.value).map {
            h => { (t: T) => field[K](h) :: t }
          },
          readT.value.reads(tagReads)
        )
    }

}

trait DerivedReadsInstances1 extends DerivedReadsInstances2 {

  implicit def readsLabelledHList[K <: Symbol, H, T <: HList](implicit
    fieldName: Witness.Aux[K],
    readH: Lazy[Reads[H]],
    readT: Lazy[DerivedReads[T]]
  ): DerivedReads[FieldType[K, H] :: T] =
    new DerivedReads[FieldType[K, H] :: T] {
      def reads(tagReads: TypeTagReads) =
        Reads.applicative.apply(
          (__ \ fieldName.value.name).read(readH.value).map {
            h => { (t: T) => field[K](h) :: t }
          },
          readT.value.reads(tagReads)
        )
    }

}

trait DerivedReadsInstances2 {

  implicit def readsGeneric[A, R](implicit
    gen: LabelledGeneric.Aux[A, R],
    derivedReads: Lazy[DerivedReads[R]]
  ): DerivedReads[A] =
    new DerivedReads[A] {
      def reads(tagReads: TypeTagReads) = derivedReads.value.reads(tagReads).map(gen.from)
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy