Integration with PureConfig (HOCON configuration files)

Importing the PureConfig integration:

// For Circe version 0.14.x
libraryDependencies += "io.monix" %% "newtypes-pureconfig-v0-17" % "0.3.0"

Usage:

import monix.newtypes._
import monix.newtypes.integrations.DerivedPureConfigConvert
import pureconfig._
import pureconfig.generic.semiauto._

type EmailAddress = EmailAddress.Type
object EmailAddress extends NewtypeValidated[String] with DerivedPureConfigConvert {
  def apply(v: String): Either[BuildFailure[Type], Type] =
    if (v.contains("@"))
      Right(unsafeCoerce(v))
    else
      Left(BuildFailure("missing @"))
}

// Sample document
final case class Envelope[A](
  value: A
)

object Envelope {
  implicit def reader[A: ConfigReader]: ConfigReader[Envelope[A]] =
    deriveReader
  implicit def writer[A: ConfigWriter]: ConfigWriter[Envelope[A]] =
    deriveWriter
}

You can now serialize and deserialize to/from HOCON configuration:

import pureconfig._
import com.typesafe.config._

val renderOptions =
  ConfigRenderOptions
    .defaults()
    .setOriginComments(false)
    .setComments(false)
    .setFormatted(true)
    .setJson(true)
// renderOptions: ConfigRenderOptions = ConfigRenderOptions(formatted,json,showEnvVariableValues)

val serialized =
  ConfigWriter[Envelope[EmailAddress]]
    .to(Envelope(EmailAddress.unsafe("[email protected]")))
    .render(renderOptions)
// serialized: String = """{
//     "value" : "[email protected]"
// }
// """

ConfigSource
  .string(serialized)
  .load[Envelope[EmailAddress]]
// res0: ConfigReader.Result[Envelope[EmailAddress]] = Right(
//   value = Envelope(value = "[email protected]")
// )