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

scala.build.options.ConfigMonoid.scala Maven / Gradle / Ivy

package scala.build.options

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

trait ConfigMonoid[T]:
  def zero: T
  def orElse(main: T, defaults: T): T

  def sum(values: Seq[T]): T =
    values.foldLeft(zero)(orElse(_, _))

case class ConfigMonoidImpl[T](override val zero: T)(orElseFun: (T, T) => T)
    extends ConfigMonoid[T]:
  def orElse(main: T, defaults: T) = orElseFun(main, defaults)

object ConfigMonoid:
  def apply[T](implicit instance: ConfigMonoid[T]): ConfigMonoid[T] = instance

  def instance[T](zeroValue: => T)(orElseFn: (T, T) => T): ConfigMonoid[T] =
    new ConfigMonoid[T] {
      def zero                         = zeroValue
      def orElse(main: T, defaults: T) = orElseFn(main, defaults)
    }

  def sum[T](values: Seq[T])(implicit monoid: ConfigMonoid[T]): T =
    monoid.sum(values)

  given seq[T]: ConfigMonoid[Seq[T]]       = ConfigMonoidImpl(Nil)(_ ++ _)
  given list[T]: ConfigMonoid[List[T]]     = ConfigMonoidImpl(Nil)(_ ++ _)
  given set[T]: ConfigMonoid[Set[T]]       = ConfigMonoidImpl(Set.empty)(_ ++ _)
  given option[T]: ConfigMonoid[Option[T]] = ConfigMonoidImpl(None)(_ orElse _)
  given boolean: ConfigMonoid[Boolean]     = ConfigMonoidImpl(false)(_ || _)
  given unit: ConfigMonoid[Unit]           = ConfigMonoidImpl[Unit](())((_, _) => ())
  given map[K, V](using valueMonoid: ConfigMonoid[V]): ConfigMonoid[Map[K, V]] =
    ConfigMonoidImpl(Map.empty[K, V]) {
      (main, defaults) =>
        (main.keySet ++ defaults.keySet).map {
          key =>
            val mainVal     = main.getOrElse(key, valueMonoid.zero)
            val defaultsVal = defaults.getOrElse(key, valueMonoid.zero)
            key -> valueMonoid.orElse(mainVal, defaultsVal)
        }.toMap
    }

  inline def zeroTuple[C <: Tuple]: Tuple =
    inline erasedValue[C] match
      case _: EmptyTuple => EmptyTuple
      case _: (t *: ts) =>
        summonInline[ConfigMonoid[t]].zero *: zeroTuple[ts]

  inline def valueTuple[C <: Tuple, T](index: Int, main: T, defaults: T): Tuple =
    inline erasedValue[C] match
      case _: EmptyTuple => EmptyTuple
      case _: (t *: ts) =>
        def get(v: T) = v.asInstanceOf[Product].productElement(index).asInstanceOf[t]
        summonInline[ConfigMonoid[t]].orElse(get(main), get(defaults)) *: valueTuple[ts, T](
          index + 1,
          main,
          defaults
        )

  inline given derive[T](using m: Mirror.ProductOf[T]): ConfigMonoid[T] =
    inline m match
      case p: Mirror.ProductOf[T] =>
        new ConfigMonoid[T]:
          def zero: T =
            p.fromProduct(zeroTuple[m.MirroredElemTypes])

          def orElse(main: T, defaults: T): T =
            p.fromProduct(valueTuple[m.MirroredElemTypes, T](0, main, defaults))




© 2015 - 2025 Weber Informatics LLC | Privacy Policy