2009-08-16 20:29:08 +02:00
|
|
|
package xsbt
|
|
|
|
|
|
|
|
|
|
import Task.{mapTask,bindTask, ITask}
|
|
|
|
|
import scala.collection.{mutable,immutable}
|
|
|
|
|
|
2009-08-29 16:19:00 +02:00
|
|
|
sealed trait Result[O] extends NotNull
|
|
|
|
|
final case class Value[O](t: O) extends Result[O]
|
|
|
|
|
sealed abstract class Task[O] extends Identity with Result[O]
|
2009-08-16 20:29:08 +02:00
|
|
|
{
|
|
|
|
|
type Input
|
|
|
|
|
def dependencies: TreeHashSet[Task[_]] // IMPORTANT!! immutable.HashSet is NOT suitable. It has issues with multi-threaded access
|
|
|
|
|
def map[N](f: O => N): ITask[O,N]
|
2009-08-29 16:19:00 +02:00
|
|
|
def bind[N](f: O => Result[N]): ITask[O,N]
|
2009-08-16 20:29:08 +02:00
|
|
|
def dependsOn(addDependencies: Task[_]*): ITask[Input,O]
|
|
|
|
|
def named(s: String): ITask[Input,O]
|
|
|
|
|
}
|
|
|
|
|
private final class M[I,O,R <: Result[O]](name: Option[String])
|
|
|
|
|
(val dependencies: TreeHashSet[Task[_]])(val extract: Results => I)(val compute: I => R) extends Task[O]
|
|
|
|
|
{
|
|
|
|
|
type Input = I
|
|
|
|
|
def this(dependencies: Task[_]*)(extract: Results => I)(compute: I => R) =
|
|
|
|
|
this(None)(TreeHashSet(dependencies: _*))(extract)(compute)
|
|
|
|
|
|
|
|
|
|
final def dependsOn(addDependencies: Task[_]*) = new M(name)(dependencies ++ addDependencies)(extract)(compute)
|
|
|
|
|
final def map[N](f: O => N) = mapTask(this)(_(this))(f)
|
2009-08-29 16:19:00 +02:00
|
|
|
final def bind[N](f: O => Result[N]) = bindTask(this)(_(this))(f)
|
2009-08-16 20:29:08 +02:00
|
|
|
final def named(s: String) =
|
|
|
|
|
name match
|
|
|
|
|
{
|
|
|
|
|
case Some(n) => error("Cannot rename task already named '" + n + "'. (Tried to rename it to '" + s + "')")
|
|
|
|
|
case None => new M(Some(s))(dependencies)(extract)(compute)
|
|
|
|
|
}
|
|
|
|
|
final override def toString = "Task " + name.getOrElse("<anon>")
|
|
|
|
|
}
|
|
|
|
|
abstract class Identity extends NotNull
|
|
|
|
|
{
|
|
|
|
|
final override def equals(o: Any) = o match { case a: AnyRef => this eq a; case _ => false }
|
|
|
|
|
final override def hashCode = System.identityHashCode(this)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private trait Results extends NotNull
|
|
|
|
|
{
|
|
|
|
|
def apply[O](task: Task[O]): O
|
|
|
|
|
def contains(task: Task[_]): Boolean
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
object Task
|
|
|
|
|
{
|
|
|
|
|
type ITask[I,O] = Task[O] { type Input = I }
|
|
|
|
|
import Function.tupled
|
|
|
|
|
def apply[O](o: => O): ITask[Unit,O] =
|
|
|
|
|
new M[Unit,O,Value[O]]()(r => ())( u => Value(o) )
|
2009-08-29 16:19:00 +02:00
|
|
|
def bindTask[I,O](dependencies: Task[_]*)(extract: Results => I)(compute: I => Result[O]): ITask[I,O] =
|
|
|
|
|
new M[I,O,Result[O]](dependencies : _*)(extract)(compute)
|
2009-08-16 20:29:08 +02:00
|
|
|
def mapTask[I,O](dependencies: Task[_]*)(extract: Results => I)(compute: I => O): ITask[I,O] =
|
|
|
|
|
new M[I,O,Value[O]](dependencies : _*)(extract)(in => Value(compute(in)))
|
|
|
|
|
|
|
|
|
|
private[xsbt] def extract[I,O](t: ITask[I,O], results: Results): I = t match { case m: M[I,O,_] => m.extract(results) }
|
|
|
|
|
private[xsbt] def compute[I,O](t: ITask[I,O], input: I): Result[O] = t match { case m: M[I,O,_] => m.compute(input) }
|
|
|
|
|
|
|
|
|
|
implicit def iterableToForkBuilder[A](t: Iterable[A]): ForkBuilderIterable[A] = new ForkBuilderIterable(t)
|
|
|
|
|
final class ForkBuilderIterable[A] private[Task](a: Iterable[A]) extends NotNull
|
|
|
|
|
{
|
|
|
|
|
def fork[X](f: A => X): Iterable[ITask[Unit,X]] = a.map(x => Task(f(x)))
|
|
|
|
|
def reduce(f: (A,A) => A): Task[A] = fork(x => x) reduce(f)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
implicit def iterableToBuilder[O](t: Iterable[Task[O]]): BuilderIterable[O] = new BuilderIterable(t)
|
|
|
|
|
final class BuilderIterable[O] private[Task](a: Iterable[Task[O]]) extends NotNull
|
|
|
|
|
{
|
|
|
|
|
//def mapBind[X](f: O => Task[_,X]): Iterable[Task[O,XO]] = a.map(_.bind(f))
|
|
|
|
|
def join: Task[Iterable[O]] = join(identity[O])
|
|
|
|
|
def join[X](f: O => X): Task[Iterable[X]] = mapTask(a.toSeq: _*)( r => a.map(t => r(t)) )(_.map(f))
|
|
|
|
|
//def bindJoin[X](f: O => Task[_,X]): Task[Iterable[X],Iterable[X]] = mapBind(f).join
|
|
|
|
|
def reduce(f: (O,O) => O): Task[O] =
|
|
|
|
|
{
|
|
|
|
|
def reduce2(list: List[Task[O]], accumulate: List[Task[O]]): List[Task[O]] =
|
|
|
|
|
list match
|
|
|
|
|
{
|
|
|
|
|
case Nil => accumulate
|
|
|
|
|
case x :: Nil => x :: accumulate
|
|
|
|
|
case xa :: xb :: tail => reduce2(tail, ( (xa, xb) map f ) :: accumulate )
|
|
|
|
|
}
|
|
|
|
|
def reduce1(list: List[Task[O]]): Task[O] =
|
|
|
|
|
list match
|
|
|
|
|
{
|
|
|
|
|
case Nil => error("Empty list")
|
|
|
|
|
case x :: Nil => x
|
|
|
|
|
case _ => reduce1(reduce2(list, Nil))
|
|
|
|
|
}
|
|
|
|
|
reduce1(a.toList)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
import metascala.HLists.{HList,HNil,HCons}
|
|
|
|
|
sealed trait TList
|
|
|
|
|
{
|
|
|
|
|
type Head
|
|
|
|
|
type Tail <: TList
|
|
|
|
|
type HListType <: HList
|
|
|
|
|
def tasks: List[Task[_]]
|
|
|
|
|
def get(results: Results): HListType
|
|
|
|
|
}
|
|
|
|
|
final class TNil extends TList
|
|
|
|
|
{
|
|
|
|
|
type Head = Nothing
|
|
|
|
|
type Tail = TNil
|
|
|
|
|
type HListType = HNil
|
|
|
|
|
def ::[A](t: Task[A]) = TCons[A,HNil,TNil](t, this)
|
|
|
|
|
def tasks = Nil
|
|
|
|
|
def get(results: Results) = HNil
|
|
|
|
|
}
|
|
|
|
|
final case class TCons[H, HL <: HList, T <: TList { type HListType = HL}](head: Task[H], tail: T) extends TList
|
|
|
|
|
{
|
|
|
|
|
type Head = H
|
|
|
|
|
type Tail = T
|
|
|
|
|
type This = TCons[H,HL,T]
|
|
|
|
|
type HListType = HCons[H,HL]
|
|
|
|
|
def ::[A](t: Task[A]) = TCons[A,HListType,This](t, this)
|
|
|
|
|
def tasks = head :: tail.tasks
|
|
|
|
|
def get(results: Results) = HCons(results(head), tail.get(results))
|
|
|
|
|
|
|
|
|
|
def map[X](f: HListType => X): ITask[HListType,X] = mapTask(tasks: _*)(get)(f)
|
2009-08-29 16:19:00 +02:00
|
|
|
def bind[X](f: HListType => Result[X]): ITask[HListType,X] = bindTask(tasks: _*)(get)(f)
|
2009-08-16 20:29:08 +02:00
|
|
|
def join: ITask[HListType,HListType] = map(identity[HListType])
|
|
|
|
|
}
|
|
|
|
|
val TNil = new TNil
|
|
|
|
|
|
|
|
|
|
implicit def twoToBuilder[A,B](t: (Task[A], Task[B]) ): Builder2[A,B] =
|
|
|
|
|
t match { case (a,b) => new Builder2(a,b) }
|
|
|
|
|
final class Builder2[A,B] private[Task](a: Task[A], b: Task[B]) extends NotNull
|
|
|
|
|
{
|
|
|
|
|
def map[X](f: (A,B) => X): ITask[(A,B),X] = mapTask(a,b)(r => (r(a), r(b)))(tupled(f))
|
2009-08-29 16:19:00 +02:00
|
|
|
def bind[X](f: (A,B) => Result[X]): ITask[(A,B),X] = bindTask(a,b)( r => (r(a), r(b)) )(tupled(f))
|
2009-08-16 20:29:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
implicit def threeToBuilder[A,B,C](t: (Task[A], Task[B], Task[C])): Builder3[A,B,C] = t match { case (a,b,c) => new Builder3(a,b,c) }
|
|
|
|
|
final class Builder3[A,B,C] private[Task](a: Task[A], b: Task[B], c: Task[C]) extends NotNull
|
|
|
|
|
{
|
|
|
|
|
def map[X](f: (A,B,C) => X): ITask[(A,B,C),X] = mapTask(a,b,c)( r => (r(a), r(b), r(c)) )(tupled(f))
|
2009-08-29 16:19:00 +02:00
|
|
|
def bind[X](f: (A,B,C) => Result[X]): ITask[(A,B,C),X] = bindTask(a,b,c)( r => (r(a), r(b), r(c)) )(tupled(f))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
implicit def fourToBuilder[A,B,C,D](t: (Task[A], Task[B], Task[C], Task[D])): Builder4[A,B,C,D] = t match { case (a,b,c,d) => new Builder4(a,b,c,d) }
|
|
|
|
|
final class Builder4[A,B,C,D] private[Task](a: Task[A], b: Task[B], c: Task[C], d: Task[D]) extends NotNull
|
|
|
|
|
{
|
|
|
|
|
def map[X](f: (A,B,C,D) => X): ITask[(A,B,C,D),X] = mapTask(a,b,c,d)( r => (r(a), r(b), r(c), r(d)) )(tupled(f))
|
|
|
|
|
def bind[X](f: (A,B,C,D) => Result[X]): ITask[(A,B,C,D),X] = bindTask(a,b,c,d)( r => (r(a), r(b), r(c),r(d)) )(tupled(f))
|
2009-08-16 20:29:08 +02:00
|
|
|
}
|
|
|
|
|
}
|