ciris.generic.decoders.GenericConfigDecoders.scala Maven / Gradle / Ivy
The newest version!
package ciris.generic.decoders
import ciris.api._
import ciris.api.syntax._
import ciris.{ConfigDecoder, ConfigEntry, ConfigError}
import ciris.ConfigError.{left, right}
import shapeless.{:+:, ::, <:!<, CNil, Coproduct, Generic, HList, HNil, Inl, Inr, Lazy}
trait GenericConfigDecoders {
implicit def cNilConfigDecoder[A]: ConfigDecoder[A, CNil] =
new ConfigDecoder[A, CNil] {
override def decode[F[_]: Monad, K, S](
entry: ConfigEntry[F, K, S, A]
): F[Either[ConfigError, CNil]] = {
left[CNil](ConfigError {
s"Could not find any valid coproduct choice while decoding ${entry.keyType.name} [${entry.key}]"
}).pure[F]
}
}
implicit def coproductConfigDecoder[A, B <: Coproduct, C](
implicit decodeC: Lazy[ConfigDecoder[A, C]],
decodeB: ConfigDecoder[A, B]
): ConfigDecoder[A, C :+: B] =
new ConfigDecoder[A, C :+: B] {
override def decode[F[_]: Monad, K, S](
entry: ConfigEntry[F, K, S, A]
): F[Either[ConfigError, C :+: B]] = {
decodeC.value.decode(entry).flatMap {
case Right(a) => right[C :+: B](Inl(a)).pure[F]
case Left(aError) =>
decodeB.decode(entry).map {
case Right(b) => right[C :+: B](Inr(b))
case Left(bError) => left(aError combine bError)
}
}
}
}
implicit def hNilConfigDecoder[A]: ConfigDecoder[A, HNil] =
new ConfigDecoder[A, HNil] {
override def decode[F[_]: Monad, K, S](
entry: ConfigEntry[F, K, S, A]
): F[Either[ConfigError, HNil]] = {
right[HNil](HNil).pure[F]
}
}
implicit def hListConfigDecoder[A, B, C <: HList](
implicit decodeB: Lazy[ConfigDecoder[A, B]],
decodeC: ConfigDecoder[A, C]
): ConfigDecoder[A, B :: C] =
new ConfigDecoder[A, B :: C] {
override def decode[F[_]: Monad, K, S](
entry: ConfigEntry[F, K, S, A]
): F[Either[ConfigError, B :: C]] = {
(decodeB.value.decode(entry) product decodeC.decode(entry)).map {
case (Right(b), Right(c)) => Right(b :: c)
case (Left(error1), Right(_)) => Left(error1)
case (Right(_), Left(error2)) => Left(error2)
case (Left(error1), Left(error2)) => Left(error1 combine error2)
}
}
}
implicit def genericConfigDecoder[A, B, C](
implicit ev: C <:!< Option[_], // Do not override default behaviour for Option
gen: Generic.Aux[C, B],
decodeB: Lazy[ConfigDecoder[A, B]]
): ConfigDecoder[A, C] = {
val _ = ev // Prevent unused warning
decodeB.value.map(gen.from)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy