sbt/util/collection/Settings.scala

196 lines
9.1 KiB
Scala
Raw Normal View History

/* sbt -- Simple Build Tool
* Copyright 2011 Mark Harrah
*/
2010-09-08 20:29:00 +02:00
package sbt
2010-12-29 22:07:17 +01:00
import Types._
2010-12-13 03:33:32 +01:00
sealed trait Settings[Scope]
{
def data: Map[Scope, AttributeMap]
def keys(scope: Scope): Set[AttributeKey[_]]
def scopes: Set[Scope]
def definingScope(scope: Scope, key: AttributeKey[_]): Option[Scope]
def allKeys[T](f: (Scope, AttributeKey[_]) => T): Seq[T]
2010-12-13 03:33:32 +01:00
def get[T](scope: Scope, key: AttributeKey[T]): Option[T]
def set[T](scope: Scope, key: AttributeKey[T], value: T): Settings[Scope]
}
2010-12-29 22:07:17 +01:00
private final class Settings0[Scope](val data: Map[Scope, AttributeMap], val delegates: Scope => Seq[Scope]) extends Settings[Scope]
2010-09-08 20:29:00 +02:00
{
def scopes: Set[Scope] = data.keySet.toSet
def keys(scope: Scope) = data(scope).keys.toSet
def allKeys[T](f: (Scope, AttributeKey[_]) => T): Seq[T] = data.flatMap { case (scope, map) => map.keys.map(k => f(scope, k)) } toSeq;
2010-12-29 22:07:17 +01:00
2010-12-13 03:33:32 +01:00
def get[T](scope: Scope, key: AttributeKey[T]): Option[T] =
2010-12-29 22:07:17 +01:00
delegates(scope).toStream.flatMap(sc => scopeLocal(sc, key) ).headOption
def definingScope(scope: Scope, key: AttributeKey[_]): Option[Scope] =
delegates(scope).toStream.filter(sc => scopeLocal(sc, key).isDefined ).headOption
2010-12-13 03:33:32 +01:00
private def scopeLocal[T](scope: Scope, key: AttributeKey[T]): Option[T] =
(data get scope).flatMap(_ get key)
def set[T](scope: Scope, key: AttributeKey[T], value: T): Settings[Scope] =
{
val map = (data get scope) getOrElse AttributeMap.empty
val newData = data.updated(scope, map.put(key, value))
2010-12-29 22:07:17 +01:00
new Settings0(newData, delegates)
2010-12-13 03:33:32 +01:00
}
2010-09-08 20:29:00 +02:00
}
2010-12-29 22:07:17 +01:00
// delegates should contain the input Scope as the first entry
// this trait is intended to be mixed into an object
trait Init[Scope]
2010-09-08 20:29:00 +02:00
{
2010-12-29 22:07:17 +01:00
final case class ScopedKey[T](scope: Scope, key: AttributeKey[T])
2010-09-08 20:29:00 +02:00
2010-12-29 22:07:17 +01:00
type SettingSeq[T] = Seq[Setting[T]]
type ScopedMap = IMap[ScopedKey, SettingSeq]
type CompiledMap = Map[ScopedKey[_], Compiled]
type MapScoped = ScopedKey ~> ScopedKey
2010-12-13 03:33:32 +01:00
2010-12-29 22:07:17 +01:00
def value[T](key: ScopedKey[T])(value: => T): Setting[T] = new Value(key, value _)
def update[T](key: ScopedKey[T])(f: T => T): Setting[T] = app(key, key :^: KNil)(h => f(h.head))
def app[HL <: HList, T](key: ScopedKey[T], inputs: KList[ScopedKey, HL])(f: HL => T): Setting[T] = new Apply(key, f, inputs)
def uniform[S,T](key: ScopedKey[T], inputs: Seq[ScopedKey[S]])(f: Seq[S] => T): Setting[T] = new Uniform(key, f, inputs)
def kapp[HL <: HList, M[_], T](key: ScopedKey[T], inputs: KList[({type l[t] = ScopedKey[M[t]]})#l, HL])(f: KList[M, HL] => T): Setting[T] = new KApply[HL, M, T](key, f, inputs)
2010-12-13 03:33:32 +01:00
// the following is a temporary workaround for the "... cannot be instantiated from ..." bug, which renders 'kapp' above unusable outside this source file
class KApp[HL <: HList, M[_], T] {
type Composed[S] = ScopedKey[M[S]]
def apply(key: ScopedKey[T], inputs: KList[Composed, HL])(f: KList[M, HL] => T): Setting[T] = new KApply[HL, M, T](key, f, inputs)
}
def empty(implicit delegates: Scope => Seq[Scope]): Settings[Scope] = new Settings0(Map.empty, delegates)
2010-12-29 22:07:17 +01:00
def asTransform(s: Settings[Scope]): ScopedKey ~> Id = new (ScopedKey ~> Id) {
def apply[T](k: ScopedKey[T]): T = getValue(s, k)
2010-12-13 03:33:32 +01:00
}
def getValue[T](s: Settings[Scope], k: ScopedKey[T]) = s.get(k.scope, k.key).get
def asFunction[T](s: Settings[Scope]): ScopedKey[T] => T = k => getValue(s, k)
2010-12-13 03:33:32 +01:00
def compiled(init: Seq[Setting[_]])(implicit delegates: Scope => Seq[Scope], scopeLocal: ScopedKey[_] => Seq[Setting[_]]): CompiledMap =
2010-12-13 03:33:32 +01:00
{
// prepend per-scope settings
2011-02-06 03:39:34 +01:00
val withLocal = addLocal(init)(scopeLocal)
2010-12-29 22:07:17 +01:00
// group by Scope/Key, dropping dead initializations
2011-02-06 03:39:34 +01:00
val sMap: ScopedMap = grouped(withLocal)
2010-12-29 22:07:17 +01:00
// delegate references to undefined values according to 'delegates'
val dMap: ScopedMap = delegate(sMap)(delegates)
2010-12-29 22:07:17 +01:00
// merge Seq[Setting[_]] into Compiled
compile(dMap)
}
def make(init: Seq[Setting[_]])(implicit delegates: Scope => Seq[Scope], scopeLocal: ScopedKey[_] => Seq[Setting[_]]): Settings[Scope] =
{
val cMap = compiled(init)(delegates, scopeLocal)
2010-12-29 22:07:17 +01:00
// order the initializations. cyclic references are detected here.
val ordered: Seq[Compiled] = sort(cMap)
// evaluation: apply the initializations.
applyInits(ordered)
2010-12-13 03:33:32 +01:00
}
2010-12-29 22:07:17 +01:00
def sort(cMap: CompiledMap): Seq[Compiled] =
Dag.topologicalSort(cMap.values)(_.dependencies.map(cMap))
def compile(sMap: ScopedMap): CompiledMap =
sMap.toSeq.map { case (k, ss) =>
val deps = ss flatMap { _.dependsOn }
val eval = (settings: Settings[Scope]) => (settings /: ss)(applySetting)
(k, new Compiled(deps, eval))
2010-12-13 03:33:32 +01:00
} toMap;
2010-12-29 22:07:17 +01:00
def grouped(init: Seq[Setting[_]]): ScopedMap =
((IMap.empty : ScopedMap) /: init) ( (m,s) => add(m,s) )
def add[T](m: ScopedMap, s: Setting[T]): ScopedMap =
m.mapValue[T]( s.key, Nil, ss => append(ss, s))
def append[T](ss: Seq[Setting[T]], s: Setting[T]): Seq[Setting[T]] =
if(s.definitive) s :: Nil else ss :+ s
2011-02-06 03:39:34 +01:00
def addLocal(init: Seq[Setting[_]])(implicit scopeLocal: ScopedKey[_] => Seq[Setting[_]]): Seq[Setting[_]] =
init.flatMap( _.dependsOn flatMap scopeLocal ) ++ init
2010-12-29 22:07:17 +01:00
def delegate(sMap: ScopedMap)(implicit delegates: Scope => Seq[Scope]): ScopedMap =
2010-12-13 03:33:32 +01:00
{
def refMap(refKey: ScopedKey[_]) = new (ScopedKey ~> ScopedKey) { def apply[T](k: ScopedKey[T]) =
delegateForKey(sMap, k, delegates(k.scope), refKey)
}
val f = new (SettingSeq ~> SettingSeq) { def apply[T](ks: Seq[Setting[T]]) =
ks.map{ s => s mapReferenced refMap(s.key) }
}
2010-12-29 22:07:17 +01:00
sMap mapValues f
2010-12-13 03:33:32 +01:00
}
private[this] def delegateForKey[T](sMap: ScopedMap, k: ScopedKey[T], scopes: Seq[Scope], refKey: ScopedKey[_]): ScopedKey[T] =
2010-12-29 22:07:17 +01:00
{
val scache = PMap.empty[ScopedKey, ScopedKey]
def resolve(search: Seq[Scope]): ScopedKey[T] =
search match {
case Seq() => throw Uninitialized(k, refKey)
2010-12-29 22:07:17 +01:00
case Seq(x, xs @ _*) =>
val sk = ScopedKey(x, k.key)
scache.getOrUpdate(sk, if(defines(sMap, sk, refKey)) sk else resolve(xs))
}
resolve(scopes)
2010-12-13 03:33:32 +01:00
}
2010-12-29 22:07:17 +01:00
private[this] def defines(map: ScopedMap, key: ScopedKey[_], refKey: ScopedKey[_]): Boolean =
(map get key) match { case Some(Seq(x, _*)) => (refKey != key) || x.definitive; case _ => false }
private[this] def applyInits(ordered: Seq[Compiled])(implicit delegates: Scope => Seq[Scope]): Settings[Scope] =
2010-12-29 22:07:17 +01:00
(empty /: ordered){ (m, comp) => comp.eval(m) }
2010-12-13 03:33:32 +01:00
private[this] def applySetting[T](map: Settings[Scope], setting: Setting[T]): Settings[Scope] =
{
def execK[HL <: HList, M[_]](a: KApply[HL, M, T]) =
map.set(a.key.scope, a.key.key, a.f(a.inputs.transform[M]( nestCon[ScopedKey, Id, M](asTransform(map)) )) )
setting match
2010-09-08 20:29:00 +02:00
{
2010-12-29 22:07:17 +01:00
case s: Value[T] => map.set(s.key.scope, s.key.key, s.value())
case u: Uniform[s, T] => map.set(u.key.scope, u.key.key, u.f(u.inputs map asFunction(map)) )
case a: Apply[hl, T] => map.set(a.key.scope, a.key.key, a.f(a.inputs down asTransform(map) ) )
case ka: KApply[hl, m, T] => execK[hl, m](ka) // separate method needed to workaround bug where m is not recognized as higher-kinded in inline version
2010-09-08 20:29:00 +02:00
}
}
2010-12-13 03:33:32 +01:00
final class Uninitialized(val key: ScopedKey[_], val refKey: ScopedKey[_], msg: String) extends Exception(msg)
def Uninitialized(key: ScopedKey[_], refKey: ScopedKey[_]): Uninitialized =
new Uninitialized(key, refKey, "Reference to uninitialized setting " + key.key.label + " (in " + key.scope + ") from " + refKey.key.label +" (in " + refKey.scope + ")")
2010-12-29 22:07:17 +01:00
final class Compiled(val dependencies: Iterable[ScopedKey[_]], val eval: Settings[Scope] => Settings[Scope])
2010-12-13 03:33:32 +01:00
sealed trait Setting[T]
{
2010-12-29 22:07:17 +01:00
def key: ScopedKey[T]
def definitive: Boolean
def dependsOn: Seq[ScopedKey[_]]
def mapReferenced(g: MapScoped): Setting[T]
def mapKey(g: MapScoped): Setting[T]
2010-12-13 03:33:32 +01:00
}
2010-12-29 22:07:17 +01:00
private[this] final class Value[T](val key: ScopedKey[T], val value: () => T) extends Setting[T]
2010-12-13 03:33:32 +01:00
{
2010-12-29 22:07:17 +01:00
def definitive = true
def dependsOn = Nil
def mapReferenced(g: MapScoped) = this
def mapKey(g: MapScoped): Setting[T] = new Value(g(key), value)
2010-09-08 20:29:00 +02:00
}
2010-12-29 22:07:17 +01:00
private[this] final class Apply[HL <: HList, T](val key: ScopedKey[T], val f: HL => T, val inputs: KList[ScopedKey, HL]) extends Setting[T]
2010-12-13 03:33:32 +01:00
{
2010-12-29 22:07:17 +01:00
def definitive = !inputs.toList.contains(key)
def dependsOn = remove(inputs.toList, key)
2010-12-29 22:07:17 +01:00
def mapReferenced(g: MapScoped) = new Apply(key, f, inputs transform g)
def mapKey(g: MapScoped): Setting[T] = new Apply(g(key), f, inputs)
}
private[this] final class KApply[HL <: HList, M[_], T](val key: ScopedKey[T], val f: KList[M, HL] => T, val inputs: KList[({type l[t] = ScopedKey[M[t]]})#l, HL]) extends Setting[T]
{
def definitive = !inputs.toList.contains(key)
def dependsOn = remove(unnest(inputs.toList), key)
def mapReferenced(g: MapScoped) = new KApply[HL, M, T](key, f, inputs.transform[({type l[t] = ScopedKey[M[t]]})#l]( nestCon(g) ) )
def mapKey(g: MapScoped): Setting[T] = new KApply[HL, M, T](g(key), f, inputs)
private[this] def unnest(l: List[ScopedKey[M[T]] forSome { type T }]): List[ScopedKey[_]] = l.asInstanceOf[List[ScopedKey[_]]]
}
private[this] final class Uniform[S, T](val key: ScopedKey[T], val f: Seq[S] => T, val inputs: Seq[ScopedKey[S]]) extends Setting[T]
{
def definitive = !inputs.contains(key)
def dependsOn = remove(inputs, key)
def mapReferenced(g: MapScoped) = new Uniform(key, f, inputs map g.fn[S])
def mapKey(g: MapScoped): Setting[T] = new Uniform(g(key), f, inputs)
2010-12-13 03:33:32 +01:00
}
private def remove[T](s: Seq[T], v: T) = s filterNot (_ == v)
2010-12-13 03:33:32 +01:00
}