mirror of https://github.com/sbt/sbt.git
Port Task
This commit is contained in:
parent
1b42f40508
commit
7d33a5949e
|
|
@ -189,6 +189,7 @@ lazy val sbtRoot: Project = (project in file("."))
|
|||
completeProj,
|
||||
logicProj,
|
||||
utilCache,
|
||||
taskProj,
|
||||
)
|
||||
.settings(
|
||||
minimalSettings,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import scala.annotation.tailrec
|
|||
import scala.collection.mutable
|
||||
import scala.collection.JavaConverters._
|
||||
import mutable.Map
|
||||
import sbt.internal.util.AList
|
||||
|
||||
private[sbt] object Execute {
|
||||
def idMap[A1, A2]: Map[A1, A2] = (new java.util.IdentityHashMap[A1, A2]).asScala
|
||||
|
|
@ -43,12 +44,12 @@ sealed trait Completed {
|
|||
}
|
||||
private[sbt] trait NodeView[F[_]] {
|
||||
def apply[A](a: F[A]): Node[F, A]
|
||||
def inline[A](a: F[A]): Option[() => A]
|
||||
def inline1[A](a: F[A]): Option[() => A]
|
||||
}
|
||||
final class Triggers[F[_]](
|
||||
val runBefore: collection.Map[F[_], Seq[F[_]]],
|
||||
val injectFor: collection.Map[F[_], Seq[F[_]]],
|
||||
val onComplete: RMap[F, Result] => RMap[F, Result]
|
||||
val runBefore: collection.Map[F[Any], Seq[F[Any]]],
|
||||
val injectFor: collection.Map[F[Any], Seq[F[Any]]],
|
||||
val onComplete: RMap[F, Result] => RMap[F, Result],
|
||||
)
|
||||
|
||||
private[sbt] final class Execute[F[_] <: AnyRef](
|
||||
|
|
@ -56,21 +57,20 @@ private[sbt] final class Execute[F[_] <: AnyRef](
|
|||
triggers: Triggers[F],
|
||||
progress: ExecuteProgress[F]
|
||||
)(implicit view: NodeView[F]) {
|
||||
type Strategy = CompletionService[F[_], Completed]
|
||||
type Strategy = CompletionService[F[Any], Completed]
|
||||
|
||||
private[this] val forward = idMap[F[_], IDSet[F[_]]]
|
||||
private[this] val reverse = idMap[F[_], Iterable[F[_]]]
|
||||
private[this] val forward = idMap[F[Any], IDSet[F[Any]]]
|
||||
private[this] val reverse = idMap[F[Any], Iterable[F[Any]]]
|
||||
private[this] val callers = pMap[F, Compose[IDSet, F]#Apply]
|
||||
private[this] val state = idMap[F[_], State]
|
||||
private[this] val state = idMap[F[Any], State]
|
||||
private[this] val viewCache = pMap[F, Node[F, *]]
|
||||
private[this] val results = pMap[F, Result]
|
||||
|
||||
private[this] val getResult: F ~> Result = λ[F ~> Result](a =>
|
||||
view.inline(a) match {
|
||||
case Some(v) => Value(v())
|
||||
case None => results(a)
|
||||
}
|
||||
)
|
||||
private[this] val getResult: [A] => F[A] => Result[A] = [A] =>
|
||||
(a: F[A]) =>
|
||||
view.inline1(a) match
|
||||
case Some(v) => Result.Value(v())
|
||||
case None => results(a)
|
||||
private[this] type State = State.Value
|
||||
private[this] object State extends Enumeration {
|
||||
val Pending, Running, Calling, Done = Value
|
||||
|
|
@ -85,7 +85,7 @@ private[sbt] final class Execute[F[_] <: AnyRef](
|
|||
def run[A](root: F[A])(implicit strategy: Strategy): Result[A] =
|
||||
try {
|
||||
runKeep(root)(strategy)(root)
|
||||
} catch { case i: Incomplete => Inc(i) }
|
||||
} catch { case i: Incomplete => Result.Inc(i) }
|
||||
|
||||
def runKeep[A](root: F[A])(implicit strategy: Strategy): RMap[F, Result] = {
|
||||
assert(state.isEmpty, "Execute already running/ran.")
|
||||
|
|
@ -142,7 +142,7 @@ private[sbt] final class Execute[F[_] <: AnyRef](
|
|||
results.get(target) match {
|
||||
case Some(result) => retire(node, result)
|
||||
case None =>
|
||||
state(node) = Calling
|
||||
state(node.asInstanceOf) = Calling
|
||||
addChecked(target)
|
||||
addCaller(node, target)
|
||||
}
|
||||
|
|
@ -164,10 +164,10 @@ private[sbt] final class Execute[F[_] <: AnyRef](
|
|||
}
|
||||
|
||||
results(node) = result
|
||||
state(node) = Done
|
||||
state(node.asInstanceOf) = Done
|
||||
progress.afterCompleted(node, result)
|
||||
remove(reverse.asInstanceOf[Map[F[A], Iterable[F[_]]]], node) foreach { dep =>
|
||||
notifyDone(node, dep)
|
||||
remove(reverse.asInstanceOf[Map[F[A], Iterable[F[Any]]]], node) foreach { dep =>
|
||||
notifyDone(node, dep.asInstanceOf)
|
||||
}
|
||||
callers.remove(node).toList.flatten.foreach { c =>
|
||||
retire(c, callerResult(c, result))
|
||||
|
|
@ -180,23 +180,23 @@ private[sbt] final class Execute[F[_] <: AnyRef](
|
|||
assert(done(node))
|
||||
assert(results(node) == result)
|
||||
readyInv(node)
|
||||
assert(!(reverse contains node))
|
||||
assert(!(callers contains node))
|
||||
assert(!(reverse.contains(node.asInstanceOf)))
|
||||
assert(!(callers.contains(node)))
|
||||
assert(triggeredBy(node) forall added)
|
||||
}
|
||||
}
|
||||
def callerResult[A](node: F[A], result: Result[A]): Result[A] =
|
||||
result match {
|
||||
case _: Value[A] => result
|
||||
case Inc(i) => Inc(Incomplete(Some(node), tpe = i.tpe, causes = i :: Nil))
|
||||
case _: Result.Value[A] => result
|
||||
case Result.Inc(i) => Result.Inc(Incomplete(Some(node), tpe = i.tpe, causes = i :: Nil))
|
||||
}
|
||||
|
||||
def notifyDone(node: F[_], dependent: F[_])(implicit strategy: Strategy): Unit = {
|
||||
def notifyDone[A](node: F[A], dependent: F[Any])(implicit strategy: Strategy): Unit = {
|
||||
val f = forward(dependent)
|
||||
f -= node
|
||||
f -= node.asInstanceOf
|
||||
if (f.isEmpty) {
|
||||
remove[F[_], IDSet[F[_]]](forward, dependent)
|
||||
ready(dependent)
|
||||
remove[F[Any], IDSet[F[Any]]](forward.asInstanceOf, dependent)
|
||||
ready[Any](dependent)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -220,10 +220,10 @@ private[sbt] final class Execute[F[_] <: AnyRef](
|
|||
pre { newPre(node) }
|
||||
|
||||
val v = register(node)
|
||||
val deps = dependencies(v) ++ runBefore(node)
|
||||
val active = IDSet[F[_]](deps filter notDone)
|
||||
val deps: Iterable[F[Any]] = dependencies(v) ++ runBefore(node.asInstanceOf)
|
||||
val active = IDSet[F[Any]](deps filter notDone.asInstanceOf)
|
||||
progress.afterRegistered(
|
||||
node,
|
||||
node.asInstanceOf,
|
||||
deps,
|
||||
active.toList
|
||||
/* active is mutable, so take a snapshot */
|
||||
|
|
@ -231,10 +231,10 @@ private[sbt] final class Execute[F[_] <: AnyRef](
|
|||
|
||||
if (active.isEmpty) ready(node)
|
||||
else {
|
||||
forward(node) = active
|
||||
forward(node.asInstanceOf) = active.asInstanceOf
|
||||
for (a <- active) {
|
||||
addChecked(a)
|
||||
addReverse(a, node)
|
||||
addChecked[Any](a.asInstanceOf)
|
||||
addReverse[Any](a.asInstanceOf, node.asInstanceOf)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -254,32 +254,33 @@ private[sbt] final class Execute[F[_] <: AnyRef](
|
|||
pre {
|
||||
assert(pending(node))
|
||||
readyInv(node)
|
||||
assert(reverse contains node)
|
||||
assert(reverse.contains(node.asInstanceOf))
|
||||
}
|
||||
|
||||
state(node) = Running
|
||||
progress.afterReady(node)
|
||||
state(node.asInstanceOf) = Running
|
||||
progress.afterReady(node.asInstanceOf)
|
||||
submit(node)
|
||||
|
||||
post {
|
||||
readyInv(node)
|
||||
assert(reverse contains node)
|
||||
assert(reverse.contains(node.asInstanceOf))
|
||||
assert(running(node))
|
||||
}
|
||||
}
|
||||
|
||||
/** Enters the given node into the system. */
|
||||
def register[A](node: F[A]): Node[F, A] = {
|
||||
state(node) = Pending
|
||||
reverse(node) = Seq()
|
||||
state(node.asInstanceOf) = Pending
|
||||
reverse(node.asInstanceOf) = Seq()
|
||||
viewCache.getOrUpdate(node, view(node))
|
||||
}
|
||||
|
||||
/** Send the work for this node to the provided Strategy. */
|
||||
def submit[A](node: F[A])(implicit strategy: Strategy): Unit = {
|
||||
val v = viewCache(node)
|
||||
val rs = v.alist.transform(v.in, getResult)
|
||||
strategy.submit(node, () => work(node, v.work(rs)))
|
||||
val rs = AList.tuple.transform[F, Result, v.Tup](v.in)(getResult)
|
||||
// v.alist.transform(v.in)(getResult)
|
||||
strategy.submit(node.asInstanceOf, () => work(node, v.work(rs)))
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -287,7 +288,7 @@ private[sbt] final class Execute[F[_] <: AnyRef](
|
|||
* post-processing to perform after the result is retrieved from the Strategy.
|
||||
*/
|
||||
def work[A](node: F[A], f: => Either[F[A], A])(implicit strategy: Strategy): Completed = {
|
||||
progress.beforeWork(node)
|
||||
progress.beforeWork(node.asInstanceOf)
|
||||
val rawResult = wideConvert(f).left.map {
|
||||
case i: Incomplete => if (config.overwriteNode(i)) i.copy(node = Some(node)) else i
|
||||
case e => Incomplete(Some(node), Incomplete.Error, directCause = Some(e))
|
||||
|
|
@ -305,86 +306,87 @@ private[sbt] final class Execute[F[_] <: AnyRef](
|
|||
rawResult: Either[Incomplete, Either[F[A], A]]
|
||||
): Either[F[A], Result[A]] =
|
||||
rawResult match {
|
||||
case Left(i) => Right(Inc(i))
|
||||
case Right(Right(v)) => Right(Value(v))
|
||||
case Left(i) => Right(Result.Inc(i))
|
||||
case Right(Right(v)) => Right(Result.Value(v))
|
||||
case Right(Left(target)) => Left(target)
|
||||
}
|
||||
|
||||
def remove[K, V](map: Map[K, V], k: K): V =
|
||||
map.remove(k).getOrElse(sys.error("Key '" + k + "' not in map :\n" + map))
|
||||
|
||||
def addReverse(node: F[_], dependent: F[_]): Unit = reverse(node) ++= Seq(dependent)
|
||||
def addReverse[A](node: F[A], dependent: F[Any]): Unit =
|
||||
reverse(node.asInstanceOf) ++= Seq(dependent)
|
||||
def addCaller[A](caller: F[A], target: F[A]): Unit =
|
||||
callers.getOrUpdate(target, IDSet.create[F[A]]) += caller
|
||||
|
||||
def dependencies(node: F[_]): Iterable[F[_]] = dependencies(viewCache(node))
|
||||
def dependencies(v: Node[F, _]): Iterable[F[_]] =
|
||||
v.alist.toList(v.in).filter(dep => view.inline(dep).isEmpty)
|
||||
def dependencies[A](node: F[A]): Iterable[F[Any]] = dependencies(viewCache(node.asInstanceOf))
|
||||
def dependencies[A](v: Node[F, A]): Iterable[F[Any]] =
|
||||
AList.tuple.toList[F, v.Tup](v.in).filter(dep => view.inline1(dep).isEmpty)
|
||||
// v.alist.toList(v.in).filter(dep => view.inline(dep).isEmpty)
|
||||
|
||||
def runBefore(node: F[_]): Seq[F[_]] = getSeq(triggers.runBefore, node)
|
||||
def triggeredBy(node: F[_]): Seq[F[_]] = getSeq(triggers.injectFor, node)
|
||||
def getSeq(map: collection.Map[F[_], Seq[F[_]]], node: F[_]): Seq[F[_]] =
|
||||
map.getOrElse(node, nilSeq[F[_]])
|
||||
def runBefore[A](node: F[A]): Seq[F[A]] =
|
||||
getSeq[A](triggers.runBefore, node)
|
||||
def triggeredBy[A](node: F[A]): Seq[F[A]] = getSeq(triggers.injectFor, node)
|
||||
def getSeq[A](map: collection.Map[F[Any], Seq[F[Any]]], node: F[A]): Seq[F[A]] =
|
||||
map.getOrElse(node.asInstanceOf, nilSeq[F[Any]]).asInstanceOf
|
||||
|
||||
// Contracts
|
||||
|
||||
def addedInv(node: F[_]): Unit = topologicalSort(node) foreach addedCheck
|
||||
def addedCheck(node: F[_]): Unit = {
|
||||
def addedInv[A](node: F[A]): Unit = topologicalSort(node) foreach addedCheck
|
||||
def addedCheck[A](node: F[A]): Unit = {
|
||||
assert(added(node), "Not added: " + node)
|
||||
assert(viewCache contains node, "Not in view cache: " + node)
|
||||
dependencyCheck(node)
|
||||
assert(viewCache.contains[Any](node.asInstanceOf), "Not in view cache: " + node)
|
||||
dependencyCheck(node.asInstanceOf)
|
||||
}
|
||||
def dependencyCheck(node: F[_]): Unit = {
|
||||
def dependencyCheck(node: F[Any]): Unit = {
|
||||
dependencies(node) foreach { dep =>
|
||||
def onOpt[A](o: Option[A])(f: A => Boolean) = o match {
|
||||
case None => false; case Some(x) => f(x)
|
||||
}
|
||||
def checkForward = onOpt(forward.get(node)) { _ contains dep }
|
||||
def checkReverse = onOpt(reverse.get(dep)) { _.exists(_ == node) }
|
||||
assert(done(dep) ^ (checkForward && checkReverse))
|
||||
def checkForward = onOpt(forward.get(node.asInstanceOf)) { _ contains dep.asInstanceOf }
|
||||
def checkReverse = onOpt(reverse.get(dep.asInstanceOf)) { _.exists(_ == node) }
|
||||
assert(done(dep.asInstanceOf) ^ (checkForward && checkReverse))
|
||||
}
|
||||
}
|
||||
def pendingInv(node: F[_]): Unit = {
|
||||
def pendingInv[A](node: F[A]): Unit = {
|
||||
assert(atState(node, Pending))
|
||||
assert((dependencies(node) ++ runBefore(node)) exists notDone)
|
||||
assert((dependencies(node) ++ runBefore(node)) exists notDone.asInstanceOf)
|
||||
}
|
||||
def runningInv(node: F[_]): Unit = {
|
||||
assert(dependencies(node) forall done)
|
||||
assert(!(forward contains node))
|
||||
def runningInv[A](node: F[A]): Unit = {
|
||||
assert(dependencies(node) forall done.asInstanceOf)
|
||||
assert(!(forward.contains(node.asInstanceOf)))
|
||||
}
|
||||
def newPre(node: F[_]): Unit = {
|
||||
def newPre[A](node: F[A]): Unit = {
|
||||
isNew(node)
|
||||
assert(!(reverse contains node))
|
||||
assert(!(forward contains node))
|
||||
assert(!(callers contains node))
|
||||
assert(!(viewCache contains node))
|
||||
assert(!(results contains node))
|
||||
assert(!(reverse.contains(node.asInstanceOf)))
|
||||
assert(!(forward.contains(node.asInstanceOf)))
|
||||
assert(!(callers.contains[Any](node.asInstanceOf)))
|
||||
assert(!(viewCache.contains[Any](node.asInstanceOf)))
|
||||
assert(!(results.contains[Any](node.asInstanceOf)))
|
||||
}
|
||||
|
||||
def topologicalSort(node: F[_]): Seq[F[_]] = {
|
||||
val seen = IDSet.create[F[_]]
|
||||
def visit(n: F[_]): List[F[_]] =
|
||||
(seen process n)(List[F[_]]()) {
|
||||
node :: dependencies(n).foldLeft(List[F[_]]()) { (ss, dep) =>
|
||||
visit(dep) ::: ss
|
||||
def topologicalSort[A](node: F[A]): Seq[F[Any]] = {
|
||||
val seen = IDSet.create[F[Any]]
|
||||
def visit(n: F[Any]): List[F[Any]] =
|
||||
(seen process n)(List[F[Any]]()) {
|
||||
node.asInstanceOf :: dependencies(n).foldLeft(List[F[Any]]()) { (ss, dep) =>
|
||||
visit(dep.asInstanceOf) ::: ss
|
||||
}
|
||||
}
|
||||
|
||||
visit(node).reverse
|
||||
visit(node.asInstanceOf).reverse
|
||||
}
|
||||
|
||||
def readyInv(node: F[_]): Unit = {
|
||||
assert(dependencies(node) forall done)
|
||||
assert(!(forward contains node))
|
||||
def readyInv[A](node: F[A]): Unit = {
|
||||
assert(dependencies(node) forall done.asInstanceOf)
|
||||
assert(!(forward.contains(node.asInstanceOf)))
|
||||
}
|
||||
|
||||
// cyclic reference checking
|
||||
|
||||
def snapshotCycleCheck(): Unit =
|
||||
callers.toSeq foreach {
|
||||
case (called: F[c], callers) =>
|
||||
for (caller <- callers) cycleCheck(caller.asInstanceOf[F[c]], called)
|
||||
case _ => ()
|
||||
callers.toSeq foreach { case (called: F[c], callers) =>
|
||||
for (caller <- callers) cycleCheck(caller.asInstanceOf[F[c]], called)
|
||||
}
|
||||
|
||||
def cycleCheck[A](node: F[A], target: F[A]): Unit = {
|
||||
|
|
@ -407,14 +409,14 @@ private[sbt] final class Execute[F[_] <: AnyRef](
|
|||
|
||||
// state testing
|
||||
|
||||
def pending(d: F[_]) = atState(d, Pending)
|
||||
def running(d: F[_]) = atState(d, Running)
|
||||
def calling(d: F[_]) = atState(d, Calling)
|
||||
def done(d: F[_]) = atState(d, Done)
|
||||
def notDone(d: F[_]) = !done(d)
|
||||
def atState(d: F[_], s: State) = state.get(d) == Some(s)
|
||||
def isNew(d: F[_]) = !added(d)
|
||||
def added(d: F[_]) = state contains d
|
||||
def pending[A](d: F[A]) = atState(d, Pending)
|
||||
def running[A](d: F[A]) = atState(d, Running)
|
||||
def calling[A](d: F[A]) = atState(d, Calling)
|
||||
def done[A](d: F[A]) = atState(d, Done)
|
||||
def notDone[A](d: F[A]) = !done(d)
|
||||
private def atState[A](d: F[A], s: State) = state.get(d.asInstanceOf) == Some(s)
|
||||
def isNew[A](d: F[A]) = !added(d)
|
||||
def added[A](d: F[A]) = state.contains(d.asInstanceOf)
|
||||
def complete = state.values.forall(_ == Done)
|
||||
|
||||
def pre(f: => Unit) = if (checkPreAndPostConditions) f
|
||||
|
|
|
|||
|
|
@ -22,20 +22,20 @@ trait ExecuteProgress[F[_]] {
|
|||
* `task` are `allDeps` and the subset of those dependencies that have not completed are
|
||||
* `pendingDeps`.
|
||||
*/
|
||||
def afterRegistered(task: F[_], allDeps: Iterable[F[_]], pendingDeps: Iterable[F[_]]): Unit
|
||||
def afterRegistered(task: F[Any], allDeps: Iterable[F[Any]], pendingDeps: Iterable[F[Any]]): Unit
|
||||
|
||||
/**
|
||||
* Notifies that all of the dependencies of `task` have completed and `task` is therefore ready to
|
||||
* run. The task has not been scheduled on a thread yet.
|
||||
*/
|
||||
def afterReady(task: F[_]): Unit
|
||||
def afterReady(task: F[Any]): Unit
|
||||
|
||||
/**
|
||||
* Notifies that the work for `task` is starting after this call returns. This is called from the
|
||||
* thread the task executes on, unlike most other methods in this callback. It is called
|
||||
* immediately before the task's work starts with minimal intervening executor overhead.
|
||||
*/
|
||||
def beforeWork(task: F[_]): Unit
|
||||
def beforeWork(task: F[Any]): Unit
|
||||
|
||||
/**
|
||||
* Notifies that the work for `task` work has finished. The task may have computed the next task
|
||||
|
|
@ -67,13 +67,13 @@ object ExecuteProgress {
|
|||
def empty[F[_]]: ExecuteProgress[F] = new ExecuteProgress[F] {
|
||||
override def initial(): Unit = ()
|
||||
override def afterRegistered(
|
||||
task: F[_],
|
||||
allDeps: Iterable[F[_]],
|
||||
pendingDeps: Iterable[F[_]]
|
||||
task: F[Any],
|
||||
allDeps: Iterable[F[Any]],
|
||||
pendingDeps: Iterable[F[Any]]
|
||||
): Unit =
|
||||
()
|
||||
override def afterReady(task: F[_]): Unit = ()
|
||||
override def beforeWork(task: F[_]): Unit = ()
|
||||
override def afterReady(task: F[Any]): Unit = ()
|
||||
override def beforeWork(task: F[Any]): Unit = ()
|
||||
override def afterWork[A](task: F[A], result: Either[F[A], Result[A]]): Unit = ()
|
||||
override def afterCompleted[A](task: F[A], result: Result[A]): Unit = ()
|
||||
override def afterAllCompleted(results: RMap[F, Result]): Unit = ()
|
||||
|
|
@ -85,16 +85,16 @@ object ExecuteProgress {
|
|||
reporters foreach { _.initial() }
|
||||
}
|
||||
override def afterRegistered(
|
||||
task: F[_],
|
||||
allDeps: Iterable[F[_]],
|
||||
pendingDeps: Iterable[F[_]]
|
||||
task: F[Any],
|
||||
allDeps: Iterable[F[Any]],
|
||||
pendingDeps: Iterable[F[Any]]
|
||||
): Unit = {
|
||||
reporters foreach { _.afterRegistered(task, allDeps, pendingDeps) }
|
||||
}
|
||||
override def afterReady(task: F[_]): Unit = {
|
||||
override def afterReady(task: F[Any]): Unit = {
|
||||
reporters foreach { _.afterReady(task) }
|
||||
}
|
||||
override def beforeWork(task: F[_]): Unit = {
|
||||
override def beforeWork(task: F[Any]): Unit = {
|
||||
reporters foreach { _.beforeWork(task) }
|
||||
}
|
||||
override def afterWork[A](task: F[A], result: Either[F[A], Result[A]]): Unit = {
|
||||
|
|
|
|||
|
|
@ -7,21 +7,18 @@
|
|||
|
||||
package sbt
|
||||
|
||||
import sbt.internal.util.AList
|
||||
|
||||
/**
|
||||
* Represents a task node in a format understood by the task evaluation engine Execute.
|
||||
*
|
||||
* @tparam A
|
||||
* @tparam Effect
|
||||
* the task type constructor
|
||||
* @tparam T
|
||||
* @tparam A
|
||||
* the type computed by this node
|
||||
*/
|
||||
trait Node[A[_], T] {
|
||||
type K[L[x]]
|
||||
val in: K[A]
|
||||
val alist: AList[K]
|
||||
trait Node[Effect[_], A] {
|
||||
type Tup <: Tuple
|
||||
def in: Tuple.Map[Tup, Effect]
|
||||
|
||||
/** Computes the result of this task given the results from the inputs. */
|
||||
def work(inputs: K[Result]): Either[A[T], T]
|
||||
def work(inputs: Tuple.Map[Tup, Result]): Either[Effect[A], A]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,26 +12,27 @@ import sbt.internal.util.~>
|
|||
// used instead of Either[Incomplete, T] for type inference
|
||||
|
||||
/** Result of completely evaluating a task. */
|
||||
sealed trait Result[+T] {
|
||||
def toEither: Either[Incomplete, T]
|
||||
}
|
||||
enum Result[+A]:
|
||||
/** Indicates the task did not complete normally and so it does not have a value. */
|
||||
case Inc(cause: Incomplete) extends Result[Nothing]
|
||||
|
||||
/** Indicates the task did not complete normally and so it does not have a value. */
|
||||
final case class Inc(cause: Incomplete) extends Result[Nothing] {
|
||||
def toEither: Either[Incomplete, Nothing] = Left(cause)
|
||||
}
|
||||
/** Indicates the task completed normally and produced the given `value`. */
|
||||
case Value[+A](value: A) extends Result[A]
|
||||
|
||||
/** Indicates the task completed normally and produced the given `value`. */
|
||||
final case class Value[+T](value: T) extends Result[T] {
|
||||
def toEither: Either[Incomplete, T] = Right(value)
|
||||
}
|
||||
def toEither: Either[Incomplete, A] = this match
|
||||
case Inc(cause) => Left(cause)
|
||||
case Value(value) => Right(value)
|
||||
end Result
|
||||
|
||||
object Result {
|
||||
type Id[X] = X
|
||||
val tryValue = λ[Result ~> Id] {
|
||||
case Value(v) => v
|
||||
case Inc(i) => throw i
|
||||
}
|
||||
val tryValue: [A] => Result[A] => A =
|
||||
[A] =>
|
||||
(r: Result[A]) =>
|
||||
r match
|
||||
case Result.Value(v) => v
|
||||
case Result.Inc(i) => throw i
|
||||
|
||||
def tryValues[S](r: Seq[Result[Unit]], v: Result[S]): S = {
|
||||
r foreach tryValue[Unit]
|
||||
tryValue[S](v)
|
||||
|
|
|
|||
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
* sbt
|
||||
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||
* Copyright 2008 - 2010, Mark Harrah
|
||||
* Licensed under Apache License 2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
package sbt.internal.util
|
||||
|
||||
import collection.mutable
|
||||
|
||||
trait RMap[K[_], V[_]] {
|
||||
def apply[T](k: K[T]): V[T]
|
||||
def get[T](k: K[T]): Option[V[T]]
|
||||
def contains[T](k: K[T]): Boolean
|
||||
def toSeq: Seq[(K[_], V[_])]
|
||||
|
||||
def toTypedSeq: Seq[TPair[_]] = toSeq.map {
|
||||
case (k: K[t], v) => TPair[t](k, v.asInstanceOf[V[t]])
|
||||
}
|
||||
|
||||
def keys: Iterable[K[_]]
|
||||
def values: Iterable[V[_]]
|
||||
def isEmpty: Boolean
|
||||
|
||||
sealed case class TPair[T](key: K[T], value: V[T])
|
||||
}
|
||||
|
||||
trait IMap[K[_], V[_]] extends (K ~> V) with RMap[K, V] {
|
||||
def put[T](k: K[T], v: V[T]): IMap[K, V]
|
||||
def remove[T](k: K[T]): IMap[K, V]
|
||||
def mapValue[T](k: K[T], init: V[T], f: V[T] => V[T]): IMap[K, V]
|
||||
def mapValues[V2[_]](f: V ~> V2): IMap[K, V2]
|
||||
def mapSeparate[VL[_], VR[_]](f: V ~> λ[T => Either[VL[T], VR[T]]]): (IMap[K, VL], IMap[K, VR])
|
||||
}
|
||||
|
||||
trait PMap[K[_], V[_]] extends (K ~> V) with RMap[K, V] {
|
||||
def update[T](k: K[T], v: V[T]): Unit
|
||||
def remove[T](k: K[T]): Option[V[T]]
|
||||
def getOrUpdate[T](k: K[T], make: => V[T]): V[T]
|
||||
def mapValue[T](k: K[T], init: V[T], f: V[T] => V[T]): V[T]
|
||||
}
|
||||
|
||||
object PMap {
|
||||
implicit def toFunction[K[_], V[_]](map: PMap[K, V]): K[_] => V[_] = k => map(k)
|
||||
def empty[K[_], V[_]]: PMap[K, V] = new DelegatingPMap[K, V](new mutable.HashMap)
|
||||
}
|
||||
|
||||
object IMap {
|
||||
|
||||
/**
|
||||
* Only suitable for K that is invariant in its type parameter.
|
||||
* Option and List keys are not suitable, for example,
|
||||
* because None <:< Option[String] and None <: Option[Int].
|
||||
*/
|
||||
def empty[K[_], V[_]]: IMap[K, V] = new IMap0[K, V](Map.empty)
|
||||
|
||||
private[sbt] def fromJMap[K[_], V[_]](map: java.util.Map[K[_], V[_]]): IMap[K, V] =
|
||||
new IMap0[K, V](new WrappedMap(map))
|
||||
|
||||
private[sbt] class IMap0[K[_], V[_]](val backing: Map[K[_], V[_]])
|
||||
extends AbstractRMap[K, V]
|
||||
with IMap[K, V] {
|
||||
def get[T](k: K[T]): Option[V[T]] = (backing get k).asInstanceOf[Option[V[T]]]
|
||||
def put[T](k: K[T], v: V[T]) = new IMap0[K, V](backing.updated(k, v))
|
||||
def remove[T](k: K[T]) = new IMap0[K, V](backing - k)
|
||||
|
||||
def mapValue[T](k: K[T], init: V[T], f: V[T] => V[T]) =
|
||||
put(k, f(this get k getOrElse init))
|
||||
|
||||
def mapValues[V2[_]](f: V ~> V2) =
|
||||
new IMap0[K, V2](Map(backing.iterator.map { case (k, v) => k -> f(v) }.toArray: _*))
|
||||
|
||||
def mapSeparate[VL[_], VR[_]](f: V ~> λ[T => Either[VL[T], VR[T]]]) = {
|
||||
val left = new java.util.concurrent.ConcurrentHashMap[K[_], VL[_]]
|
||||
val right = new java.util.concurrent.ConcurrentHashMap[K[_], VR[_]]
|
||||
Par(backing.toVector).foreach {
|
||||
case (k, v) =>
|
||||
f(v) match {
|
||||
case Left(l) => left.put(k, l)
|
||||
case Right(r) => right.put(k, r)
|
||||
}
|
||||
}
|
||||
(new IMap0[K, VL](new WrappedMap(left)), new IMap0[K, VR](new WrappedMap(right)))
|
||||
}
|
||||
|
||||
def toSeq = backing.toSeq
|
||||
def keys = backing.keys
|
||||
def values = backing.values
|
||||
def isEmpty = backing.isEmpty
|
||||
|
||||
override def toString = backing.toString
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractRMap[K[_], V[_]] extends RMap[K, V] {
|
||||
def apply[T](k: K[T]): V[T] = get(k).get
|
||||
def contains[T](k: K[T]): Boolean = get(k).isDefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Only suitable for K that is invariant in its type parameter.
|
||||
* Option and List keys are not suitable, for example,
|
||||
* because None <:< Option[String] and None <: Option[Int].
|
||||
*/
|
||||
class DelegatingPMap[K[_], V[_]](backing: mutable.Map[K[_], V[_]])
|
||||
extends AbstractRMap[K, V]
|
||||
with PMap[K, V] {
|
||||
def get[T](k: K[T]): Option[V[T]] = cast[T](backing.get(k))
|
||||
def update[T](k: K[T], v: V[T]): Unit = { backing(k) = v }
|
||||
def remove[T](k: K[T]) = cast(backing.remove(k))
|
||||
def getOrUpdate[T](k: K[T], make: => V[T]) = cast[T](backing.getOrElseUpdate(k, make))
|
||||
|
||||
def mapValue[T](k: K[T], init: V[T], f: V[T] => V[T]): V[T] = {
|
||||
val v = f(this get k getOrElse init)
|
||||
update(k, v)
|
||||
v
|
||||
}
|
||||
|
||||
def toSeq = backing.toSeq
|
||||
def keys = backing.keys
|
||||
def values = backing.values
|
||||
def isEmpty = backing.isEmpty
|
||||
|
||||
private[this] def cast[T](v: V[_]): V[T] = v.asInstanceOf[V[T]]
|
||||
private[this] def cast[T](o: Option[V[_]]): Option[V[T]] = o map cast[T]
|
||||
|
||||
override def toString = backing.toString
|
||||
}
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* sbt
|
||||
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||
* Copyright 2008 - 2010, Mark Harrah
|
||||
* Licensed under Apache License 2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
package sbt.internal.util
|
||||
|
||||
import collection.mutable
|
||||
|
||||
trait RMap[K[_], V[_]] {
|
||||
def apply[T](k: K[T]): V[T]
|
||||
def get[T](k: K[T]): Option[V[T]]
|
||||
def contains[T](k: K[T]): Boolean
|
||||
def toSeq: Seq[(K[Any], V[Any])]
|
||||
|
||||
def toTypedSeq: Seq[TPair[_]] = toSeq.map { case (k: K[t], v) =>
|
||||
TPair[t](k, v.asInstanceOf[V[t]])
|
||||
}
|
||||
|
||||
def keys: Iterable[K[Any]]
|
||||
def values: Iterable[V[Any]]
|
||||
def isEmpty: Boolean
|
||||
|
||||
sealed case class TPair[T](key: K[T], value: V[T])
|
||||
}
|
||||
|
||||
trait IMap[K[_], V[_]] extends (K ~> V) with RMap[K, V] {
|
||||
def put[T](k: K[T], v: V[T]): IMap[K, V]
|
||||
def remove[T](k: K[T]): IMap[K, V]
|
||||
def mapValue[T](k: K[T], init: V[T], f: V[T] => V[T]): IMap[K, V]
|
||||
def mapValues[V2[_]](f: [A] => V[A] => V2[A]): IMap[K, V2]
|
||||
def mapSeparate[VL[_], VR[_]](f: V ~> λ[T => Either[VL[T], VR[T]]]): (IMap[K, VL], IMap[K, VR])
|
||||
}
|
||||
|
||||
trait PMap[K[_], V[_]] extends (K ~> V) with RMap[K, V] {
|
||||
def update[T](k: K[T], v: V[T]): Unit
|
||||
def remove[T](k: K[T]): Option[V[T]]
|
||||
def getOrUpdate[T](k: K[T], make: => V[T]): V[T]
|
||||
def mapValue[T](k: K[T], init: V[T], f: V[T] => V[T]): V[T]
|
||||
}
|
||||
|
||||
object PMap {
|
||||
// implicit def toFunction[K[_], V[_]](map: PMap[K, V]): [A] => K[A] => V[A] =
|
||||
// [A] => (k: K[A]) => map.apply[A](k)
|
||||
|
||||
given [K[_], V[_]]: Conversion[PMap[K, V], [A] => (K[A]) => V[A]] =
|
||||
new Conversion[PMap[K, V], [A] => K[A] => V[A]]:
|
||||
def apply(map: PMap[K, V]): [A] => K[A] => V[A] =
|
||||
[A] => (k: K[A]) => map.apply[A](k)
|
||||
def empty[K[_], V[_]]: PMap[K, V] = new DelegatingPMap[K, V](new mutable.HashMap)
|
||||
}
|
||||
|
||||
object IMap {
|
||||
|
||||
/**
|
||||
* Only suitable for K that is invariant in its type parameter. Option and List keys are not
|
||||
* suitable, for example, because None <:< Option[String] and None <: Option[Int].
|
||||
*/
|
||||
def empty[K[_], V[_]]: IMap[K, V] = new IMap0[K, V](Map.empty)
|
||||
|
||||
private[sbt] def fromJMap[K[_], V[_]](map: java.util.Map[K[Any], V[Any]]): IMap[K, V] =
|
||||
new IMap0[K, V](new WrappedMap[K[Any], V[Any]](map))
|
||||
|
||||
private[sbt] class IMap0[K[_], V[_]](val backing: Map[K[Any], V[Any]])
|
||||
extends AbstractRMap[K, V]
|
||||
with IMap[K, V] {
|
||||
def get[T](k: K[T]): Option[V[T]] =
|
||||
(backing get k.asInstanceOf).asInstanceOf[Option[V[T]]]
|
||||
def put[T](k: K[T], v: V[T]) =
|
||||
new IMap0[K, V](backing.updated(k.asInstanceOf, v.asInstanceOf))
|
||||
def remove[T](k: K[T]) = new IMap0[K, V](backing - k.asInstanceOf)
|
||||
|
||||
def mapValue[T](k: K[T], init: V[T], f: V[T] => V[T]) =
|
||||
put(k, f(this get k getOrElse init))
|
||||
|
||||
def mapValues[V2[_]](f: [A] => V[A] => V2[A]) =
|
||||
new IMap0[K, V2](Map(backing.iterator.map { case (k, v) =>
|
||||
k -> f(v.asInstanceOf[V[Any]])
|
||||
}.toArray: _*))
|
||||
|
||||
def mapSeparate[VL[_], VR[_]](f: V ~> λ[T => Either[VL[T], VR[T]]]) = {
|
||||
val left = new java.util.concurrent.ConcurrentHashMap[K[Any], VL[Any]]
|
||||
val right = new java.util.concurrent.ConcurrentHashMap[K[Any], VR[Any]]
|
||||
Par(backing.toVector).foreach { case (k, v) =>
|
||||
f(v.asInstanceOf[V[Any]]) match {
|
||||
case Left(l) => left.put(k, l)
|
||||
case Right(r) => right.put(k, r)
|
||||
}
|
||||
}
|
||||
(
|
||||
new IMap0[K, VL](new WrappedMap(left.asInstanceOf)),
|
||||
new IMap0[K, VR](new WrappedMap(right.asInstanceOf))
|
||||
)
|
||||
}
|
||||
|
||||
def toSeq = backing.toSeq.asInstanceOf[Seq[(K[Any], V[Any])]]
|
||||
def keys = backing.keys.asInstanceOf[Iterable[K[Any]]]
|
||||
def values = backing.values.asInstanceOf[Iterable[V[Any]]]
|
||||
def isEmpty = backing.isEmpty
|
||||
|
||||
override def toString = backing.toString
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractRMap[K[_], V[_]] extends RMap[K, V] {
|
||||
def apply[T](k: K[T]): V[T] = get(k).get
|
||||
def contains[T](k: K[T]): Boolean = get(k).isDefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Only suitable for K that is invariant in its type parameter. Option and List keys are not
|
||||
* suitable, for example, because None <:< Option[String] and None <: Option[Int].
|
||||
*/
|
||||
class DelegatingPMap[K[_], V[_]](backing: mutable.Map[K[Any], V[Any]])
|
||||
extends AbstractRMap[K, V]
|
||||
with PMap[K, V] {
|
||||
def get[T](k: K[T]): Option[V[T]] = cast[T](backing.get(k.asInstanceOf))
|
||||
def update[T](k: K[T], v: V[T]): Unit = { backing(k.asInstanceOf) = v.asInstanceOf }
|
||||
def remove[T](k: K[T]) = cast(backing.remove(k.asInstanceOf))
|
||||
def getOrUpdate[T](k: K[T], make: => V[T]) =
|
||||
cast[T](backing.getOrElseUpdate(k.asInstanceOf, make.asInstanceOf))
|
||||
|
||||
def mapValue[T](k: K[T], init: V[T], f: V[T] => V[T]): V[T] = {
|
||||
val v = f(this get k getOrElse init)
|
||||
update(k, v)
|
||||
v
|
||||
}
|
||||
|
||||
def toSeq = backing.toSeq.asInstanceOf[Seq[(K[Any], V[Any])]]
|
||||
def keys = backing.keys.asInstanceOf[Iterable[K[Any]]]
|
||||
def values = backing.values.asInstanceOf[Iterable[V[Any]]]
|
||||
def isEmpty = backing.isEmpty
|
||||
|
||||
private[this] def cast[A](v: V[Any]): V[A] = v.asInstanceOf[V[A]]
|
||||
private[this] def cast[A](o: Option[V[Any]]): Option[V[A]] = o map cast[A]
|
||||
|
||||
override def toString = backing.toString
|
||||
}
|
||||
|
|
@ -15,10 +15,10 @@ trait TypeFunctions:
|
|||
import TypeFunctions._
|
||||
sealed trait Const[A] { type Apply[B] = A }
|
||||
sealed trait ConstK[A] { type l[L[x]] = A }
|
||||
sealed trait Compose[A[_], B[_]] { type Apply[T] = A[B[T]] }
|
||||
sealed trait ∙[A[_], B[_]] { type l[T] = A[B[T]] }
|
||||
|
||||
*/
|
||||
sealed trait Compose[A[_], B[_]] { type Apply[T] = A[B[T]] }
|
||||
|
||||
sealed trait ∙[A[_], B[_]] { type l[T] = A[B[T]] }
|
||||
private type AnyLeft[T] = Left[T, Nothing]
|
||||
private type AnyRight[T] = Right[Nothing, T]
|
||||
final val left: [A] => A => Left[A, Nothing] = [A] => (a: A) => Left(a)
|
||||
|
|
@ -71,15 +71,17 @@ object TypeFunctions extends TypeFunctions:
|
|||
end TypeFunctions
|
||||
*/
|
||||
|
||||
/*
|
||||
trait ~>[-A[_], +B[_]] { outer =>
|
||||
def apply[T](a: A[T]): B[T]
|
||||
trait ~>[-F1[_], +F2[_]] { outer =>
|
||||
def apply[A](f1: F1[A]): F2[A]
|
||||
// directly on ~> because of type inference limitations
|
||||
final def ∙[C[_]](g: C ~> A): C ~> B = λ[C ~> B](c => outer.apply(g(c)))
|
||||
final def ∙[C, D](g: C => D)(implicit ev: D <:< A[D]): C => B[D] = i => apply(ev(g(i)))
|
||||
final def fn[T]: A[T] => B[T] = (t: A[T]) => apply[T](t)
|
||||
final def ∙[F3[_]](g: F3 ~> F1): F3 ~> F2 = new ~>[F3, F2] {
|
||||
override def apply[A](f3: F3[A]) = outer.apply(g(f3))
|
||||
}
|
||||
final def ∙[C, D](g: C => D)(implicit ev: D <:< F1[D]): C => F2[D] = i => apply(ev(g(i)))
|
||||
lazy val fn: [A] => F1[A] => F2[A] = [A] => (f1: F1[A]) => outer.apply[A](f1)
|
||||
}
|
||||
|
||||
/*
|
||||
object ~> {
|
||||
import TypeFunctions._
|
||||
val Id: Id ~> Id = idK[Id]
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
package sbt.internal.util
|
||||
|
||||
import scala.collection.JavaConverters._
|
||||
|
||||
private[util] class WrappedMap[K, V](val jmap: java.util.Map[K, V]) extends Map[K, V] {
|
||||
def removed(key: K): scala.collection.immutable.Map[K, V] = jmap.asScala.toMap.removed(key)
|
||||
def updated[V1 >: V](key: K, value: V1): scala.collection.immutable.Map[K, V1] =
|
||||
Loading…
Reference in New Issue