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

scalaz.macros.DerivingConfig.scala Maven / Gradle / Ivy

// Copyright: 2017 - 2024 Sam Halliday
// License: http://www.gnu.org/licenses/lgpl-3.0.en.html

package scalaz.macros

import java.net.URL

import scala.Predef.{ wrapRefArray, ArrowAssoc }
import scala.collection.immutable.{ List, Map }
import scala.collection.JavaConverters._

private[scalaz] final case class DerivingConfig(targets: Map[String, String])
private[scalaz] object DerivingConfig {
  private type Result[T] = Either[String, T]
  private type Stringy   = Map[String, String]

  // cached to avoid hitting disk on every use of the macro.
  private[scalaz] lazy val targets: Result[Stringy] =
    getClass.getClassLoader
      .getResources("deriving.conf")
      .asScala
      .toList
      .map { res =>
        for {
          s <- readResource(res)
          c <- parseProperties(s)
        } yield c
      }
      .reverse // map addition means the last element wins
      .fold(EmptyResults) {
        // it's almost like we have a Monoid! Except, no, it's stdlib
        case (Right(m1), Right(m2)) => Right(m1 ++ m2)
        case (Left(e1), _)          => Left(e1)
        case (_, Left(e2))          => Left(e2)
      }
  private[this] val EmptyResults: Result[Stringy]   = Right(Map.empty)

  private[this] def parseProperties(config: String): Result[Stringy] =
    try
      Right(
        config
          .split("\n")
          .toList
          .filterNot(_.isEmpty)
          .filterNot(_.startsWith("#"))
          .map(_.split("=").toList)
          .map {
            case List(from, to) => from.trim -> to.trim
            case other          =>
              // I'd have used Left with traverse, but this is stdlib...
              throw new IllegalArgumentException(
                s"expected 2 parts but got ${other.size} in $other"
              )
          }
          .toMap
      )
    catch {
      case t: Throwable =>
        Left(t.getMessage)
    }

  private[this] def readResource(resUrl: URL): Either[String, String] =
    readInputStream(resUrl.openStream())

  private[this] def readInputStream(
    is: java.io.InputStream
  ): Either[String, String] =
    try {
      val baos        = new java.io.ByteArrayOutputStream()
      val data        = Array.ofDim[Byte](2048)
      var len: Int    = 0
      def read(): Int = { len = is.read(data); len }
      while (read() != -1)
        baos.write(data, 0, len)
      Right(baos.toString("UTF-8"))
    } catch {
      case t: Throwable => Left(t.getMessage)
    } finally is.close()

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy