From 90f25b234e2cda4cdcc302d86992380a2d485067 Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Sun, 14 Aug 2011 10:53:37 -0400 Subject: [PATCH] Settings overhaul, intended to be source compatible where it matters. Moves many methods previously provided by implicit conversions directly onto the classes for better discoverability, especially with scaladoc. 1. Initialize now allowed in more places. Minor renamings in Initialize to avoid conflicts a. map -> apply b. get -> evaluate 2. Identity on Scoped* is deprecated- it is now redundant 3. Can now use += and <+= for String, Int, Long, Double settings. There may be some problematic corner cases in inference, especially with +=, ++, <+=, <++= 4. Some classes with a scoped: ScopedKey[T] method now have scopedKey: ScopedKey[T] instead. 5. The implicit conversion to ScopedKey[T] is now deprecated. Use the scopedKey method. 6. :== and ::= are now private[sbt] to better reflect that they were internal use only. --- main/Append.scala | 41 +++ main/CommandSupport.scala | 2 +- main/Defaults.scala | 12 +- main/GlobalPlugin.scala | 2 +- main/Main.scala | 2 +- main/Project.scala | 5 +- main/Structure.scala | 303 ++++++++---------- util/collection/Settings.scala | 182 ++++++----- .../src/test/scala/SettingsExample.scala | 9 +- 9 files changed, 285 insertions(+), 273 deletions(-) create mode 100644 main/Append.scala diff --git a/main/Append.scala b/main/Append.scala new file mode 100644 index 000000000..c9a0e7e61 --- /dev/null +++ b/main/Append.scala @@ -0,0 +1,41 @@ +package sbt + + import java.io.File + import Keys.Classpath + import scala.annotation.implicitNotFound + +object Append +{ + @implicitNotFound(msg = "No implicit for Append.Value[${A}, ${B}] found,\n so ${B} cannot be appended to ${A}") + sealed trait Value[A,B] + { + def appendValue(a: A, b: B): A + } + @implicitNotFound(msg = "No implicit for Append.Values[${A}, ${B}] found,\n so ${B} cannot be appended to ${A}") + sealed trait Values[A,B] + { + def appendValues(a: A, b: B): A + } + sealed trait Sequence[A,B,T] extends Value[A,T] with Values[A,B] + + implicit def appendSeq[T, V <: T]: Sequence[Seq[T], Seq[V], V] = new Sequence[Seq[T], Seq[V], V] { + def appendValues(a: Seq[T], b: Seq[V]): Seq[T] = a ++ b + def appendValue(a: Seq[T], b: V): Seq[T] = a :+ b + } + implicit def appendString: Value[String, String] = new Value[String, String] { + def appendValue(a: String, b: String) = a + b + } + implicit def appendInt = new Value[Int, Int] { + def appendValue(a: Int, b: Int) = a + b + } + implicit def appendLong = new Value[Long, Long] { + def appendValue(a: Long, b: Long) = a + b + } + implicit def appendDouble = new Value[Double, Double] { + def appendValue(a: Double, b: Double) = a + b + } + implicit def appendClasspath: Sequence[Classpath, Seq[File], File] = new Sequence[Classpath, Seq[File], File] { + def appendValues(a: Classpath, b: Seq[File]): Classpath = a ++ Attributed.blankSeq(b) + def appendValue(a: Classpath, b: File): Classpath = a :+ Attributed.blank(b) + } +} \ No newline at end of file diff --git a/main/CommandSupport.scala b/main/CommandSupport.scala index 142b88dc7..18f677d81 100644 --- a/main/CommandSupport.scala +++ b/main/CommandSupport.scala @@ -193,7 +193,7 @@ Multi + " command1 " + Multi + """ command2 ... Runs the specified commands. """ - def Append = "append" + def AppendCommand = "append" def AppendLastBrief = (Append + " command", AppendLastDetailed) def AppendLastDetailed = "Appends `command` to list of commands to run." diff --git a/main/Defaults.scala b/main/Defaults.scala index d499f4e4c..1d54191f3 100644 --- a/main/Defaults.scala +++ b/main/Defaults.scala @@ -456,7 +456,7 @@ object Defaults extends BuildCommon } def sbtPluginExtra(m: ModuleID, sbtV: String, scalaV: String): ModuleID = m.extra(CustomPomParser.SbtVersionKey -> sbtV, CustomPomParser.ScalaVersionKey -> scalaV).copy(crossVersion = false) - def writePluginsDescriptor(plugins: Set[String], dir: File): List[File] = + def writePluginsDescriptor(plugins: Set[String], dir: File): Seq[File] = { val descriptor: File = dir / "sbt" / "sbt.plugins" if(plugins.isEmpty) @@ -528,7 +528,7 @@ object Defaults extends BuildCommon val CompletionsID = "completions" - def noAggregation = Seq(run, console, consoleQuick, consoleProject) + def noAggregation: Seq[Scoped] = Seq(run, console, consoleQuick, consoleProject) lazy val disableAggregation = noAggregation map disableAggregate def disableAggregate(k: Scoped) = aggregate in Scope.GlobalScope.copy(task = Select(k.key)) :== false @@ -582,7 +582,7 @@ object Classpaths lazy val defaultArtifactTasks: Seq[ScopedTask[File]] = makePom +: defaultPackages def packaged(pkgTasks: Seq[ScopedTask[File]]): Initialize[Task[Map[Artifact, File]]] = - enabledOnly(packagedArtifact.task, pkgTasks).map(_.join.map(_.toMap)) + enabledOnly(packagedArtifact.task, pkgTasks) apply (_.join.map(_.toMap)) def artifactDefs(pkgTasks: Seq[ScopedTask[File]]): Initialize[Seq[Artifact]] = enabledOnly(artifact, pkgTasks) @@ -617,7 +617,7 @@ object Classpaths organizationHomepage in GlobalScope <<= organizationHomepage or homepage.identity, projectInfo <<= (name, description, homepage, licenses, organizationName, organizationHomepage) apply ModuleInfo, classpathFilter in GlobalScope :== "*.jar" | "*.so" | "*.dll", - externalResolvers <<= (externalResolvers.task.? zipWith resolvers.identity) { + externalResolvers <<= (externalResolvers.task.?, resolvers) { case (Some(delegated), Seq()) => delegated case (_, rs) => task { Resolver.withDefaultResolvers(rs) } }, @@ -1046,14 +1046,14 @@ trait BuildExtra extends BuildCommon def fullRunInputTask(scoped: ScopedInput[Unit], config: Configuration, mainClass: String, baseArguments: String*): Setting[InputTask[Unit]] = scoped <<= inputTask { result => - ( initScoped(scoped.scoped, runnerInit) zipWith (fullClasspath in config, streams, result).identityMap) { (rTask, t) => + ( initScoped(scoped.scopedKey, runnerInit) zipWith (fullClasspath in config, streams, result).identityMap) { (rTask, t) => (t :^: rTask :^: KNil) map { case (cp, s, args) :+: r :+: HNil => toError(r.run(mainClass, data(cp), baseArguments ++ args, s.log)) } } } def fullRunTask(scoped: ScopedTask[Unit], config: Configuration, mainClass: String, arguments: String*): Setting[Task[Unit]] = - scoped <<= ( initScoped(scoped.scoped, runnerInit) zipWith (fullClasspath in config, streams).identityMap ) { case (rTask, t) => + scoped <<= ( initScoped(scoped.scopedKey, runnerInit) zipWith (fullClasspath in config, streams).identityMap ) { case (rTask, t) => (t :^: rTask :^: KNil) map { case (cp, s) :+: r :+: HNil => toError(r.run(mainClass, data(cp), arguments, s.log)) } diff --git a/main/GlobalPlugin.scala b/main/GlobalPlugin.scala index 40db7ce6b..c7557a0ec 100644 --- a/main/GlobalPlugin.scala +++ b/main/GlobalPlugin.scala @@ -43,7 +43,7 @@ object GlobalPlugin val depMap = pdescs + mod.dependencyMapping(log(state)) GlobalPluginData(pid, pdeps, depMap, cp, prods ++ intcp) } - val task = taskInit mapReferenced Project.mapScope(Scope replaceThis p) get data + val task = taskInit mapReferenced Project.mapScope(Scope replaceThis p) evaluate data evaluate(state, structure, task) } def evaluate[T](state: State, structure: BuildStructure, t: Task[T]): T = diff --git a/main/Main.scala b/main/Main.scala index 36f152aa5..cd6ea2920 100644 --- a/main/Main.scala +++ b/main/Main.scala @@ -216,7 +216,7 @@ object BuiltinCommands def ifLast = Command(IfLast, IfLastBrief, IfLastDetailed)(otherCommandParser) { (s, arg) => if(s.remainingCommands.isEmpty) arg :: s else s } - def append = Command(Append, AppendLastBrief, AppendLastDetailed)(otherCommandParser) { (s, arg) => + def append = Command(AppendCommand, AppendLastBrief, AppendLastDetailed)(otherCommandParser) { (s, arg) => s.copy(remainingCommands = s.remainingCommands :+ arg) } diff --git a/main/Project.scala b/main/Project.scala index 219a614b1..9f12c025f 100644 --- a/main/Project.scala +++ b/main/Project.scala @@ -75,8 +75,8 @@ final case class Extracted(structure: BuildStructure, session: SessionSettings, { import EvaluateTask._ val extracted = Project.extract(state) - val rkey = Project.mapScope(Scope.resolveScope(GlobalScope, extracted.currentRef.build, rootProject) )( key ) - val value: Option[Result[T]] = evaluateTask(structure, key.task.scoped, state, currentRef) + val rkey = Project.mapScope(Scope.resolveScope(GlobalScope, extracted.currentRef.build, rootProject) )( key.scopedKey ) + val value: Option[Result[T]] = evaluateTask(structure, key.task.scopedKey, state, currentRef) val result = getOrError(rkey.scope, rkey.key, value) processResult(result, ConsoleLogger()) } @@ -330,6 +330,7 @@ object Project extends Init[Scope] with ProjectExtra } // this is here instead of Scoped so that it is considered without need for import (because of Project.Initialize) implicit def richInitializeTask[T](init: Initialize[Task[T]]): Scoped.RichInitializeTask[T] = new Scoped.RichInitializeTask(init) + implicit def richInitialize[T](i: Initialize[T]): Scoped.RichInitialize[T] = new Scoped.RichInitialize[T](i) } trait ProjectExtra diff --git a/main/Structure.scala b/main/Structure.scala index 26c48886d..bd390e2ef 100644 --- a/main/Structure.scala +++ b/main/Structure.scala @@ -8,7 +8,7 @@ package sbt import Types._ import std.TaskExtra.{task => mktask, _} import Task._ - import Project.{Initialize, ScopedKey, Setting, setting} + import Project.{Initialize, KeyedInitialize, ScopedKey, Setting, setting} import complete.Parser import java.io.File import java.net.URI @@ -56,7 +56,7 @@ object InputTask def apply[I,T](p: Initialize[State => Parser[I]])(action: TaskKey[I] => Initialize[Task[T]]): Initialize[InputTask[T]] = { val key: TaskKey[I] = Keys.parseResult.asInstanceOf[TaskKey[I]] - (p zip Keys.resolvedScoped.identity zipWith action(key)) { case ((parserF, scoped), act) => + (p zip Keys.resolvedScoped zipWith action(key)) { case ((parserF, scoped), act) => new InputDynamic[T] { type Result = I @@ -72,47 +72,45 @@ object InputTask sealed trait Scoped { def scope: Scope; def key: AttributeKey[_] } sealed trait ScopedTaskable[T] extends Scoped -sealed trait ScopedSetting[T] extends ScopedTaskable[T] { def key: AttributeKey[T] } -sealed trait ScopedTask[T] extends ScopedTaskable[T] { def key: AttributeKey[Task[T]] } -sealed trait ScopedInput[T] extends Scoped { def key: AttributeKey[InputTask[T]] } +sealed trait ScopedSetting[T] extends ScopedTaskable[T] with KeyedInitialize[T] with Scoped.ScopingSetting[ScopedSetting[T]] with Scoped.DefinableSetting[T] with Scoped.ListSetting[T, Id] +{ + def key: AttributeKey[T] + def scopedKey: ScopedKey[T] = ScopedKey(scope, key) + def in(scope: Scope): ScopedSetting[T] = Scoped.scopedSetting(Scope.replaceThis(this.scope)(scope), this.key) -sealed trait Key[T] extends Scoped { final def scope: Scope = Scope(This,This,This,This) } + protected[this] def make[S](other: Initialize[S])(f: (T, S) => T): Setting[T] = this <<= (this, other)(f) +} +sealed trait ScopedTask[T] extends ScopedTaskable[T] with KeyedInitialize[Task[T]] with Scoped.ScopingSetting[ScopedTask[T]] with Scoped.ListSetting[T, Task] with Scoped.DefinableTask[T] +{ + def key: AttributeKey[Task[T]] + def scopedKey: ScopedKey[Task[T]] = ScopedKey(scope, key) + def in(scope: Scope): ScopedTask[T] = Scoped.scopedTask(Scope.replaceThis(this.scope)(scope), this.key) + + protected[this] def make[S](other: Initialize[Task[S]])(f: (T, S) => T): Setting[Task[T]] = this <<= (this, other) { (a,b) => (a,b) map f } +} +sealed trait ScopedInput[T] extends Scoped with KeyedInitialize[InputTask[T]] with Scoped.ScopingSetting[ScopedInput[T]] with Scoped.DefinableSetting[InputTask[T]] +{ + def key: AttributeKey[InputTask[T]] + def scopedKey: ScopedKey[InputTask[T]] = ScopedKey(scope, key) + def in(scope: Scope): ScopedInput[T] = Scoped.scopedInput(Scope.replaceThis(this.scope)(scope), this.key) +} + +sealed trait Key[T] extends Scoped { final def scope: Scope = Scope.ThisScope } final class SettingKey[T] private(val key: AttributeKey[T]) extends Key[T] with ScopedSetting[T] final class TaskKey[T] private(val key: AttributeKey[Task[T]]) extends Key[T] with ScopedTask[T] final class InputKey[T] private(val key: AttributeKey[InputTask[T]]) extends Key[InputTask[T]] with ScopedInput[T] object Scoped { - implicit def richSettingScoped[T](s: ScopedSetting[T]): RichSettingScoped[T] = new RichSettingScoped[T](s.scope, s.key) - implicit def richTaskScoped[T](s: ScopedTask[T]): RichTaskScoped[T] = new RichTaskScoped[T](s.scope, s.key) - implicit def richInputScoped[T](s: ScopedInput[T]): RichInputScoped[T] = new RichInputScoped[T](s.scope, s.key) - implicit def richSettingListScoped[T](s: ScopedSetting[Seq[T]]): RichSettingList[T] = new RichSettingList[T](s.scope, s.key) - implicit def richListTaskScoped[T](s: ScopedTask[Seq[T]]): RichListTask[T] = new RichListTask[T](s.scope, s.key) - + @deprecated("Implicit conversion from ScopedTask[T] to ScopedKey[Task[T]] is deprecated. Use the scopedKey method of ScopedTask.") implicit def taskScopedToKey[T](s: ScopedTask[T]): ScopedKey[Task[T]] = ScopedKey(s.scope, s.key) + + @deprecated("Implicit conversion from ScopedInput[T] to ScopedKey[InputTask[T]] is deprecated. Use the scopedKey method of ScopedInput.") implicit def inputScopedToKey[T](s: ScopedInput[T]): ScopedKey[InputTask[T]] = ScopedKey(s.scope, s.key) - implicit def scopedSettingScoping[T](s: ScopedSetting[T]): ScopingSetting[ScopedSetting[T]] = - new ScopingSetting(scope => scopedSetting(Scope.replaceThis(s.scope)(scope), s.key)) - - implicit def scopedTaskScoping[T](s: ScopedTask[T]): ScopingSetting[ScopedTask[T]] = - new ScopingSetting(scope => scopedTask(Scope.replaceThis(s.scope)(scope), s.key)) - - implicit def scopedInputScoping[T](s: ScopedInput[T]): ScopingSetting[ScopedInput[T]] = - new ScopingSetting(scope => scopedInput(Scope.replaceThis(s.scope)(scope), s.key)) - - implicit def settingScoping[T](s: SettingKey[T]): ScopingSetting[ScopedSetting[T]] = - new ScopingSetting(scope => scopedSetting(scope, s.key)) - - implicit def inputScoping[T](s: InputKey[T]): ScopingSetting[ScopedInput[T]] = - new ScopingSetting(scope => scopedInput(scope, s.key)) - - implicit def taskScoping[T](s: TaskKey[T]): ScopingSetting[ScopedTask[T]] = - new ScopingSetting(scope => scopedTask(scope, s.key)) - - final class ScopingSetting[Result](app0: Scope => Result) + sealed trait ScopingSetting[Result] { - def in(s: Scope): Result = app0(s) + def in(s: Scope): Result def in(p: Reference): Result = in(Select(p), This, This) def in(t: Scoped): Result = in(This, This, Select(t.key)) @@ -124,127 +122,94 @@ object Scoped def in(p: ScopeAxis[Reference], c: ScopeAxis[ConfigKey], t: ScopeAxis[AttributeKey[_]]): Result = in( Scope(p, c, t, This) ) } - private[this] def scopedSetting[T](s: Scope, k: AttributeKey[T]): ScopedSetting[T] = new ScopedSetting[T] { val scope = s; val key = k } - private[this] def scopedInput[T](s: Scope, k: AttributeKey[InputTask[T]]): ScopedInput[T] = new ScopedInput[T] { val scope = s; val key = k } - private[this] def scopedTask[T](s: Scope, k: AttributeKey[Task[T]]): ScopedTask[T] = new ScopedTask[T] { val scope = s; val key = k } + def scopedSetting[T](s: Scope, k: AttributeKey[T]): ScopedSetting[T] = new ScopedSetting[T] { val scope = s; val key = k} + def scopedInput[T](s: Scope, k: AttributeKey[InputTask[T]]): ScopedInput[T] = new ScopedInput[T] { val scope = s; val key = k } + def scopedTask[T](s: Scope, k: AttributeKey[Task[T]]): ScopedTask[T] = new ScopedTask[T] { val scope = s; val key = k } - sealed abstract class RichXList[S, M[_]] + sealed trait ListSetting[S, M[_]] { - protected[this] def make[T](other: Initialize[M[T]])(f: (Seq[S], T) => Seq[S]): Setting[M[Seq[S]]] - protected[this] def update(f: Seq[S] => Seq[S]): Setting[M[Seq[S]]] - def <+= (value: Initialize[M[S]]): Setting[M[Seq[S]]] = make(value) {_ :+ _ } - def <++=(values: Initialize[M[Seq[S]]]): Setting[M[Seq[S]]] = make(values) {_ ++ _ } - def += (value: => S): Setting[M[Seq[S]]] = update(_ :+ value) - def ++=(values: => Seq[S]): Setting[M[Seq[S]]] = update(_ ++ values) - } - final class RichSettingList[S](scope: Scope, key: AttributeKey[Seq[S]]) extends RichXList[S, Id] - { - private[this] val base = new RichSettingScoped(scope, key) - protected[this] def make[T](other: Initialize[T])(f: (Seq[S], T) => Seq[S]): Setting[Seq[S]] = base <<= (base.identity zipWith other)(f) - protected[this] def update(f: Seq[S] => Seq[S]): Setting[Seq[S]] = base ~= f - } - final class RichListTask[S](scope: Scope, key: AttributeKey[Task[Seq[S]]]) extends RichXList[S, Task] - { - private[this] val base = new RichTaskScoped(scope, key) - protected[this] def make[T](other: Initialize[Task[T]])(f: (Seq[S], T) => Seq[S]): Setting[Task[Seq[S]]] = base <<= (base.identity zipWith other) { (a,b) => (a,b) map f } - protected[this] def update(f: Seq[S] => Seq[S]): Setting[Task[Seq[S]]] = base ~= f - } - sealed abstract class RichBaseScoped[S] - { - def scope: Scope - def key: AttributeKey[S] - final val scoped = ScopedKey(scope, key) - - final def :==(value: S): Setting[S] = :=(value) - final def := (value: => S): Setting[S] = setting(scoped, Project.value(value)) - final def ~= (f: S => S): Setting[S] = Project.update(scoped)(f) - final def <<= (app: Initialize[S]): Setting[S] = setting(scoped, app) + protected[this] def make[T](other: Initialize[M[T]])(f: (S, T) => S): Setting[M[S]] + protected[this] def ~=(f: S => S): Setting[M[S]] - final def apply[T](f: S => T): Initialize[T] = Apply.single(scoped)(f) - final def identity: Initialize[S] = apply(idFun) - final def ? : Initialize[Option[S]] = Project.optional(scoped)(idFun) - final def or[T >: S](i: Initialize[T]): Initialize[T] = (this.? zipWith i)(_ getOrElse _ ) - final def ??[T >: S](or: => T): Initialize[T] = Project.optional(scoped)(_ getOrElse or ) - - final def get(settings: Settings[Scope]): Option[S] = settings.get(scope, key) + def <+= [V](value: Initialize[M[V]])(implicit a: Append.Value[S, V]): Setting[M[S]] = make(value)(a.appendValue) + def <++= [V](values: Initialize[M[V]])(implicit a: Append.Values[S, V]): Setting[M[S]] = make(values)(a.appendValues) + def += [U](value: => U)(implicit a: Append.Value[S, U]): Setting[M[S]] = this ~= ( v => a.appendValue(v, value) ) + def ++=[U](values: => U)(implicit a: Append.Values[S, U]): Setting[M[S]] = this ~= ( v => a.appendValues(v, values) ) } - final class RichInputScoped[T](val scope: Scope, val key: AttributeKey[InputTask[T]]) extends RichBaseScoped[InputTask[T]] - final class RichSettingScoped[S](val scope: Scope, val key: AttributeKey[S]) extends RichBaseScoped[S] + sealed trait DefinableSetting[S] { - def map[T](f: S => T): Initialize[Task[T]] = flatMap(s => mktask(f(s)) ) - def flatMap[T](f: S => Task[T]): Initialize[Task[T]] = Apply.single(scoped)(f) - } - final class RichTaskScoped[S](scope: Scope, key: AttributeKey[Task[S]]) - { - type ScS = Setting[Task[S]] - def :==(value: S): ScS = :=(value) - def ::=(value: Task[S]): ScS = Project.setting(scoped, Project.value( value )) - def := (value: => S): ScS = ::=(mktask(value)) - def :== (v: ScopedSetting[S]): ScS = <<=( v(constant)) - def ~= (f: S => S): ScS = Project.update(scoped)( _ map f ) + def scopedKey: ScopedKey[S] - def <<= (app: App[S]): ScS = Project.setting(scoped, app) + private[sbt] final def :==(value: S): Setting[S] = :=(value) + final def := (value: => S): Setting[S] = setting(scopedKey, Project.value(value)) + final def ~= (f: S => S): Setting[S] = Project.update(scopedKey)(f) + final def <<= (app: Initialize[S]): Setting[S] = setting(scopedKey, app) + final def get(settings: Settings[Scope]): Option[S] = settings.get(scopedKey.scope, scopedKey.key) + final def ? : Initialize[Option[S]] = Project.optional(scopedKey)(idFun) + final def or[T >: S](i: Initialize[T]): Initialize[T] = (this.?, i)(_ getOrElse _ ) + final def ??[T >: S](or: => T): Initialize[T] = Project.optional(scopedKey)(_ getOrElse or ) + } + final class RichInitialize[S](init: Initialize[S]) + { + @deprecated("A call to 'identity' is no longer necessary and can be removed.") + final def identity: Initialize[S] = init + def map[T](f: S => T): Initialize[Task[T]] = init(s => mktask(f(s)) ) + def flatMap[T](f: S => Task[T]): Initialize[Task[T]] = init(f) + } + sealed trait DefinableTask[S] + { self: ScopedTask[S] => + + private[sbt] def :==(value: S): Setting[Task[S]] = :=(value) + private[sbt] def ::=(value: Task[S]): Setting[Task[S]] = Project.setting(scopedKey, Project.value( value )) + def := (value: => S): Setting[Task[S]] = ::=(mktask(value)) + private[sbt] def :== (v: ScopedSetting[S]): Setting[Task[S]] = <<=( v(constant)) + def ~= (f: S => S): Setting[Task[S]] = Project.update(scopedKey)( _ map f ) + + def <<= (app: Initialize[Task[S]]): Setting[Task[S]] = Project.setting(scopedKey, app) def task: ScopedSetting[Task[S]] = scopedSetting(scope, key) def get(settings: Settings[Scope]): Option[Task[S]] = settings.get(scope, key) - type App[T] = Initialize[Task[T]] - def scoped = ScopedKey(scope, key) - private[this] def mk[T](onTask: Task[S] => Task[T]): App[T] = Apply.single(scoped)(onTask) - - def flatMapR[T](f: Result[S] => Task[T]): App[T] = mk(_ flatMapR f) - def flatMap[T](f: S => Task[T]): App[T] = flatMapR(f compose successM) - def map[T](f: S => T): App[T] = mapR(f compose successM) - def mapR[T](f: Result[S] => T): App[T] = mk(_ mapR f) - def flatFailure[T](f: Incomplete => Task[T]): App[T] = flatMapR(f compose failM) - def mapFailure[T](f: Incomplete => T): App[T] = mapR(f compose failM) - def andFinally(fin: => Unit): App[S] = mk(_ andFinally fin) - def doFinally(t: Task[Unit]): App[S] = mk(_ doFinally t) - def identity: App[S] = mk(idFun) - def ? : Initialize[Task[Option[S]]] = Project.optional(scoped) { case None => mktask { None }; case Some(t) => t map some.fn } - def ??[T >: S](or: => T): Initialize[Task[T]] = Project.optional(scoped)( _ getOrElse mktask(or) ) - def or[T >: S](i: Initialize[Task[T]]): Initialize[Task[T]] = (this.? zipWith i)( (x,y) => (x :^: y :^: KNil) map hf2( _ getOrElse _ )) + @deprecated("A call to 'identity' is no longer necessary and can be removed.") + def identity: Initialize[Task[S]] = this - def || [T >: S](alt: Task[T]): App[T] = mk(_ || alt) - def && [T](alt: Task[T]): App[T] = mk(_ && alt) + def ? : Initialize[Task[Option[S]]] = Project.optional(scopedKey) { case None => mktask { None }; case Some(t) => t map some.fn } + def ??[T >: S](or: => T): Initialize[Task[T]] = Project.optional(scopedKey)( _ getOrElse mktask(or) ) + def or[T >: S](i: Initialize[Task[T]]): Initialize[Task[T]] = (this.? zipWith scopedKey)( (x,y) => (x :^: y :^: KNil) map hf2( _ getOrElse _ )) + } + final class RichInitializeTask[S](i: Initialize[Task[S]]) + { + def flatMapR[T](f: Result[S] => Task[T]): Initialize[Task[T]] = i(_ flatMapR f) + def flatMap[T](f: S => Task[T]): Initialize[Task[T]] = flatMapR(f compose successM) + def map[T](f: S => T): Initialize[Task[T]] = mapR(f compose successM) + def mapR[T](f: Result[S] => T): Initialize[Task[T]] = i(_ mapR f) + def flatFailure[T](f: Incomplete => Task[T]): Initialize[Task[T]] = flatMapR(f compose failM) + def mapFailure[T](f: Incomplete => T): Initialize[Task[T]] = mapR(f compose failM) + def andFinally(fin: => Unit): Initialize[Task[S]] = i(_ andFinally fin) + def doFinally(t: Task[Unit]): Initialize[Task[S]] = i(_ doFinally t) - def dependsOn(tasks: ScopedTask[_]*): App[S] = - { - val in = KCons(scopedTask(scope, key), KList.fromList(tasks)) - Apply.tasks(in) { kl => - kl.head.dependsOn(kl.tail.toList :_*) - } - } - } + def || [T >: S](alt: Task[T]): Initialize[Task[T]] = i(_ || alt) + def && [T](alt: Task[T]): Initialize[Task[T]] = i(_ && alt) - implicit def richSettingSeq[T](in: Seq[ScopedSetting[T]]): RichSettingSeq[T] = new RichSettingSeq(in) - final class RichSettingSeq[T](keys: Seq[ScopedSetting[T]]) - { - def join: Initialize[Seq[T]] = joinWith(idFun) - def joinWith[S](f: Seq[T] => S): Initialize[S] = Apply.uniform(keys)(f) - } - implicit def richTaskSeq[T](in: Seq[ScopedTask[T]]): RichTaskSeq[T] = new RichTaskSeq(in) - final class RichTaskSeq[T](keys: Seq[ScopedTask[T]]) - { - def join: Initialize[Task[Seq[T]]] = Apply.uniformTasks(keys) - } - implicit def richAnyTaskSeq(in: Seq[ScopedTask[_]]): RichAnyTaskSeq = new RichAnyTaskSeq(in) - final class RichAnyTaskSeq(keys: Seq[ScopedTask[_]]) - { - def dependOn: Initialize[Task[Unit]] = Apply.tasks(KList.fromList(keys)) { kl => nop.dependsOn(kl.toList :_*) } - } + def dependsOn(tasks: AnyInitTask*): Initialize[Task[S]] = (i, Initialize.joinAny(tasks)) { (thisTask, deps) => thisTask.dependsOn(deps : _*) } - final class RichInitializeTask[T](init: Initialize[Task[T]]) + def triggeredBy(tasks: AnyInitTask*): Initialize[Task[S]] = nonLocal(tasks, Keys.triggeredBy) + def runBefore(tasks: AnyInitTask*): Initialize[Task[S]] = nonLocal(tasks, Keys.runBefore) + private[this] def nonLocal(tasks: Seq[AnyInitTask], key: AttributeKey[Seq[Task[_]]]): Initialize[Task[S]] = + (Initialize.joinAny(tasks), i) { (ts, i) => i.copy(info = i.info.set(key, ts)) } + } + type AnyInitTask = Initialize[Task[T]] forSome { type T } + + implicit def richTaskSeq[T](in: Seq[Initialize[Task[T]]]): RichTaskSeq[T] = new RichTaskSeq(in) + final class RichTaskSeq[T](keys: Seq[Initialize[Task[T]]]) { - def triggeredBy(tasks: ScopedTask[_]*): Initialize[Task[T]] = nonLocal(tasks, Keys.triggeredBy) - def runBefore(tasks: ScopedTask[_]*): Initialize[Task[T]] = nonLocal(tasks, Keys.runBefore) - private[this] def nonLocal(tasks: Seq[ScopedTask[_]], key: AttributeKey[Seq[Task[_]]]): Initialize[Task[T]] = - { - val getTasks = Apply.tasks(KList.fromList(tasks))(idFun) - (getTasks zipWith init) { (tasks, i) => - i.copy(info = i.info.set(key, tasks.toList)) - } - } + def join: Initialize[Task[Seq[T]]] = tasks(_.join) + def tasks: Initialize[Seq[Task[T]]] = Initialize.join(keys) + } + implicit def richAnyTaskSeq(in: Seq[AnyInitTask]): RichAnyTaskSeq = new RichAnyTaskSeq(in) + final class RichAnyTaskSeq(keys: Seq[AnyInitTask]) + { + def dependOn: Initialize[Task[Unit]] = Initialize.joinAny(keys).apply(deps => nop.dependsOn(deps : _*) ) } @@ -433,36 +398,22 @@ object Scoped def mapFailure[T](f: Seq[Incomplete] => T): App[T] = mapR(f compose anyFailM) } - implicit def t2ToApp2[A,B](t2: (ScopedSetting[A], ScopedSetting[B]) ): Apply2[A,B] = new Apply2(t2) - implicit def t3ToApp3[A,B,C](t3: (ScopedSetting[A], ScopedSetting[B], ScopedSetting[C]) ): Apply3[A,B,C] = new Apply3(t3) - implicit def t4ToApp4[A,B,C,D](t4: (ScopedSetting[A], ScopedSetting[B], ScopedSetting[C], ScopedSetting[D]) ): Apply4[A,B,C,D] = new Apply4(t4) - implicit def t5ToApp5[A,B,C,D,E](t5: (ScopedSetting[A], ScopedSetting[B], ScopedSetting[C], ScopedSetting[D], ScopedSetting[E]) ): Apply5[A,B,C,D,E] = new Apply5(t5) - implicit def t6ToApp6[A,B,C,D,E,F](t6: (ScopedSetting[A], ScopedSetting[B], ScopedSetting[C], ScopedSetting[D], ScopedSetting[E], ScopedSetting[F]) ): Apply6[A,B,C,D,E,F] = new Apply6(t6) - implicit def t7ToApp7[A,B,C,D,E,F,G](t7: (ScopedSetting[A], ScopedSetting[B], ScopedSetting[C], ScopedSetting[D], ScopedSetting[E], ScopedSetting[F], ScopedSetting[G]) ): Apply7[A,B,C,D,E,F,G] = new Apply7(t7) - implicit def t8ToApp8[A,B,C,D,E,F,G,H](t8: (ScopedSetting[A], ScopedSetting[B], ScopedSetting[C], ScopedSetting[D], ScopedSetting[E], ScopedSetting[F], ScopedSetting[G], ScopedSetting[H]) ): Apply8[A,B,C,D,E,F,G,H] = new Apply8(t8) - implicit def t9ToApp9[A,B,C,D,E,F,G,H,I](t9: (ScopedSetting[A], ScopedSetting[B], ScopedSetting[C], ScopedSetting[D], ScopedSetting[E], ScopedSetting[F], ScopedSetting[G], ScopedSetting[H], ScopedSetting[I]) ): Apply9[A,B,C,D,E,F,G,H,I] = new Apply9(t9) + implicit def t2ToApp2[A,B](t2: (Initialize[A], Initialize[B]) ): Apply2[A,B] = new Apply2(t2) + implicit def t3ToApp3[A,B,C](t3: (Initialize[A], Initialize[B], Initialize[C]) ): Apply3[A,B,C] = new Apply3(t3) + implicit def t4ToApp4[A,B,C,D](t4: (Initialize[A], Initialize[B], Initialize[C], Initialize[D]) ): Apply4[A,B,C,D] = new Apply4(t4) + implicit def t5ToApp5[A,B,C,D,E](t5: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E]) ): Apply5[A,B,C,D,E] = new Apply5(t5) + implicit def t6ToApp6[A,B,C,D,E,F](t6: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F]) ): Apply6[A,B,C,D,E,F] = new Apply6(t6) + implicit def t7ToApp7[A,B,C,D,E,F,G](t7: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G]) ): Apply7[A,B,C,D,E,F,G] = new Apply7(t7) + implicit def t8ToApp8[A,B,C,D,E,F,G,H](t8: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H]) ): Apply8[A,B,C,D,E,F,G,H] = new Apply8(t8) + implicit def t9ToApp9[A,B,C,D,E,F,G,H,I](t9: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H], Initialize[I]) ): Apply9[A,B,C,D,E,F,G,H,I] = new Apply9(t9) object Apply { - def single[I,T](in: ScopedKey[I])(f: I => T): Initialize[T] = - Project.app(in :^: KNil)(hl => f(hl.head)) - def apply[HL <: HList, T](in: KList[ScopedSetting, HL])(f: HL => T): Initialize[T] = Project.app(in transform ssToSK)(f) - def uniformTasks[S](inputs: Seq[ScopedTask[S]]): Initialize[Task[Seq[S]]] = - Project.uniform( inputs map stToSK.fn )(_ join) - def uniform[S,T](inputs: Seq[ScopedSetting[S]])(f: Seq[S] => T): Initialize[T] = - Project.uniform( inputs map ssToSK.fn )(f) - def tasks[HL <: HList, T](in: KList[ScopedTask, HL])(f: KList[Task, HL] => T): Initialize[T] = - { - val kapp = new Project.KApp[HL, Task, T] - kapp(in transform stToSK)(f) - } private val ssToSK = new (ScopedSetting ~> ScopedKey) { def apply[T](sk: ScopedSetting[T]) = new ScopedKey(sk.scope, sk.key) } - private val stToSK = new (ScopedTask ~> ScopedTaskKey) { def apply[T](st: ScopedTask[T]) = new ScopedKey(st.scope, st.key) } - type ScopedTaskKey[T] = ScopedKey[Task[T]] } @@ -475,36 +426,36 @@ object Scoped def mkTuple8[A,B,C,D,E,F,G,H] = (a:A,b:B,c:C,d:D,e:E,f:F,g:G,h:H) => (a,b,c,d,e,f,g,h) def mkTuple9[A,B,C,D,E,F,G,H,I] = (a:A,b:B,c:C,d:D,e:E,f:F,g:G,h:H,i:I) => (a,b,c,d,e,f,g,h,i) - final class Apply2[A,B](t2: (ScopedSetting[A], ScopedSetting[B])) { - def apply[T](z: (A,B) => T) = Apply( k2(t2) )( hf2(z) ) + final class Apply2[A,B](t2: (Initialize[A], Initialize[B])) { + def apply[T](z: (A,B) => T) = Project.app( k2(t2) )( hf2(z) ) def identity = apply(mkTuple2) } - final class Apply3[A,B,C](t3: (ScopedSetting[A], ScopedSetting[B], ScopedSetting[C])) { - def apply[T](z: (A,B,C) => T) = Apply( k3(t3) )( hf3(z) ) + final class Apply3[A,B,C](t3: (Initialize[A], Initialize[B], Initialize[C])) { + def apply[T](z: (A,B,C) => T) = Project.app( k3(t3) )( hf3(z) ) def identity = apply(mkTuple3) } - final class Apply4[A,B,C,D](t4: (ScopedSetting[A], ScopedSetting[B], ScopedSetting[C], ScopedSetting[D])) { - def apply[T](z: (A,B,C,D) => T) = Apply( k4(t4) )( hf4(z) ) + final class Apply4[A,B,C,D](t4: (Initialize[A], Initialize[B], Initialize[C], Initialize[D])) { + def apply[T](z: (A,B,C,D) => T) = Project.app( k4(t4) )( hf4(z) ) def identity = apply(mkTuple4) } - final class Apply5[A,B,C,D,E](t5: (ScopedSetting[A], ScopedSetting[B], ScopedSetting[C], ScopedSetting[D], ScopedSetting[E])) { - def apply[T](z: (A,B,C,D,E) => T) = Apply( k5(t5) )( hf5(z) ) + final class Apply5[A,B,C,D,E](t5: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E])) { + def apply[T](z: (A,B,C,D,E) => T) = Project.app( k5(t5) )( hf5(z) ) def identity = apply(mkTuple5) } - final class Apply6[A,B,C,D,E,F](t6: (ScopedSetting[A], ScopedSetting[B], ScopedSetting[C], ScopedSetting[D], ScopedSetting[E], ScopedSetting[F])) { - def apply[T](z: (A,B,C,D,E,F) => T) = Apply( k6(t6) )( hf6(z) ) + final class Apply6[A,B,C,D,E,F](t6: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F])) { + def apply[T](z: (A,B,C,D,E,F) => T) = Project.app( k6(t6) )( hf6(z) ) def identity = apply(mkTuple6) } - final class Apply7[A,B,C,D,E,F,G](t7: (ScopedSetting[A], ScopedSetting[B], ScopedSetting[C], ScopedSetting[D], ScopedSetting[E], ScopedSetting[F], ScopedSetting[G])) { - def apply[T](z: (A,B,C,D,E,F,G) => T) = Apply( k7(t7) )( hf7(z) ) + final class Apply7[A,B,C,D,E,F,G](t7: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G])) { + def apply[T](z: (A,B,C,D,E,F,G) => T) = Project.app( k7(t7) )( hf7(z) ) def identity = apply(mkTuple7) } - final class Apply8[A,B,C,D,E,F,G,H](t8: (ScopedSetting[A], ScopedSetting[B], ScopedSetting[C], ScopedSetting[D], ScopedSetting[E], ScopedSetting[F], ScopedSetting[G], ScopedSetting[H])) { - def apply[T](z: (A,B,C,D,E,F,G,H) => T) = Apply( k8(t8) )( hf8(z) ) + final class Apply8[A,B,C,D,E,F,G,H](t8: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H])) { + def apply[T](z: (A,B,C,D,E,F,G,H) => T) = Project.app( k8(t8) )( hf8(z) ) def identity = apply(mkTuple8) } - final class Apply9[A,B,C,D,E,F,G,H,I](t9: (ScopedSetting[A], ScopedSetting[B], ScopedSetting[C], ScopedSetting[D], ScopedSetting[E], ScopedSetting[F], ScopedSetting[G], ScopedSetting[H], ScopedSetting[I])) { - def apply[T](z: (A,B,C,D,E,F,G,H,I) => T) = Apply( k9(t9) )( hf9(z) ) + final class Apply9[A,B,C,D,E,F,G,H,I](t9: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H], Initialize[I])) { + def apply[T](z: (A,B,C,D,E,F,G,H,I) => T) = Project.app( k9(t9) )( hf9(z) ) def identity = apply(mkTuple9) } diff --git a/util/collection/Settings.scala b/util/collection/Settings.scala index f37302f7f..41fbd4bc3 100644 --- a/util/collection/Settings.scala +++ b/util/collection/Settings.scala @@ -44,28 +44,31 @@ trait Init[Scope] /** The Show instance used when a detailed String needs to be generated. It is typically used when no context is available.*/ def showFullKey: Show[ScopedKey[_]] - final case class ScopedKey[T](scope: Scope, key: AttributeKey[T]) + final case class ScopedKey[T](scope: Scope, key: AttributeKey[T]) extends KeyedInitialize[T] { + def scopedKey = this + } type SettingSeq[T] = Seq[Setting[T]] type ScopedMap = IMap[ScopedKey, SettingSeq] type CompiledMap = Map[ScopedKey[_], Compiled] type MapScoped = ScopedKey ~> ScopedKey type ValidatedRef[T] = Either[Undefined, ScopedKey[T]] + type ValidatedInit[T] = Either[Seq[Undefined], Initialize[T]] type ValidateRef = ScopedKey ~> ValidatedRef type ScopeLocal = ScopedKey[_] => Seq[Setting[_]] type MapConstant = ScopedKey ~> Option def setting[T](key: ScopedKey[T], init: Initialize[T]): Setting[T] = new Setting[T](key, init) def value[T](value: => T): Initialize[T] = new Value(value _) - def optional[T,U](key: ScopedKey[T])(f: Option[T] => U): Initialize[U] = new Optional(Some(key), f) + def optional[T,U](i: Initialize[T])(f: Option[T] => U): Initialize[U] = new Optional(Some(i), f) def update[T](key: ScopedKey[T])(f: T => T): Setting[T] = new Setting[T](key, app(key :^: KNil)(hl => f(hl.head))) - def app[HL <: HList, T](inputs: KList[ScopedKey, HL])(f: HL => T): Initialize[T] = new Apply(f, inputs) - def uniform[S,T](inputs: Seq[ScopedKey[S]])(f: Seq[S] => T): Initialize[T] = new Uniform(f, inputs) - def kapp[HL <: HList, M[_], T](inputs: KList[({type l[t] = ScopedKey[M[t]]})#l, HL])(f: KList[M, HL] => T): Initialize[T] = new KApply[HL, M, T](f, inputs) + def app[HL <: HList, T](inputs: KList[Initialize, HL])(f: HL => T): Initialize[T] = new Apply(f, inputs) + def uniform[S,T](inputs: Seq[Initialize[S]])(f: Seq[S] => T): Initialize[T] = new Uniform(f, inputs) + def kapp[HL <: HList, M[_], T](inputs: KList[({type l[t] = Initialize[M[t]]})#l, HL])(f: KList[M, HL] => T): Initialize[T] = new KApply[HL, M, T](f, inputs) // 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]] + type Composed[S] = Initialize[M[S]] def apply(inputs: KList[Composed, HL])(f: KList[M, HL] => T): Initialize[T] = new KApply[HL, M, T](f, inputs) } @@ -152,7 +155,7 @@ trait Init[Scope] private[this] def applySetting[T](map: Settings[Scope], setting: Setting[T]): Settings[Scope] = { - val value = setting.init.get(map) + val value = setting.init.evaluate(map) val key = setting.key map.set(key.scope, key.key, value) } @@ -194,28 +197,26 @@ trait Init[Scope] sealed trait Initialize[T] { def dependsOn: Seq[ScopedKey[_]] - def map[S](g: T => S): Initialize[S] + def apply[S](g: T => S): Initialize[S] def mapReferenced(g: MapScoped): Initialize[T] - def validateReferenced(g: ValidateRef): Either[Seq[Undefined], Initialize[T]] + def validateReferenced(g: ValidateRef): ValidatedInit[T] def zip[S](o: Initialize[S]): Initialize[(T,S)] = zipWith(o)((x,y) => (x,y)) - def zipWith[S,U](o: Initialize[S])(f: (T,S) => U): Initialize[U] = new Joined[T,S,U](this, o, f) + def zipWith[S,U](o: Initialize[S])(f: (T,S) => U): Initialize[U] = + new Apply[T :+: S :+: HNil, U]( { case t :+: s :+: HNil => f(t,s)}, this :^: o :^: KNil) def mapConstant(g: MapConstant): Initialize[T] - def get(map: Settings[Scope]): T + def evaluate(map: Settings[Scope]): T } object Initialize { implicit def joinInitialize[T](s: Seq[Initialize[T]]): JoinInitSeq[T] = new JoinInitSeq(s) final class JoinInitSeq[T](s: Seq[Initialize[T]]) { - def join[S](f: Seq[T] => S): Initialize[S] = this.join map f - def join: Initialize[Seq[T]] = Initialize.join(s) + def joinWith[S](f: Seq[T] => S): Initialize[S] = uniform(s)(f) + def join: Initialize[Seq[T]] = uniform(s)(idFun) } - def join[T](inits: Seq[Initialize[T]]): Initialize[Seq[T]] = - inits match - { - case Seq() => value( Nil ) - case Seq(x, xs @ _*) => (join(xs) zipWith x)( (t,h) => h +: t) - } + def join[T](inits: Seq[Initialize[T]]): Initialize[Seq[T]] = uniform(inits)(idFun) + def joinAny[M[_]](inits: Seq[Initialize[M[T]] forSome { type T }]): Initialize[Seq[M[_]]] = + join(inits.asInstanceOf[Seq[Initialize[M[Any]]]]).asInstanceOf[Initialize[Seq[M[T] forSome { type T }]]] } object SettingsDefinition { implicit def unwrapSettingsDefinition(d: SettingsDefinition): Seq[Setting[_]] = d.settings @@ -233,103 +234,120 @@ trait Init[Scope] def mapReferenced(g: MapScoped): Setting[T] = new Setting(key, init mapReferenced g) def validateReferenced(g: ValidateRef): Either[Seq[Undefined], Setting[T]] = (init validateReferenced g).right.map(newI => new Setting(key, newI)) def mapKey(g: MapScoped): Setting[T] = new Setting(g(key), init) - def mapInit(f: (ScopedKey[T], T) => T): Setting[T] = new Setting(key, init.map(t => f(key,t))) + def mapInit(f: (ScopedKey[T], T) => T): Setting[T] = new Setting(key, init(t => f(key,t))) def mapConstant(g: MapConstant): Setting[T] = new Setting(key, init mapConstant g) override def toString = "setting(" + key + ")" } - private[this] final class Optional[S,T](a: Option[ScopedKey[S]], f: Option[S] => T) extends Initialize[T] + // mainly for reducing generated class count + private[this] def validateReferencedT(g: ValidateRef) = + new (Initialize ~> ValidatedInit) { def apply[T](i: Initialize[T]) = i validateReferenced g } + + private[this] def mapReferencedT(g: MapScoped) = + new (Initialize ~> Initialize) { def apply[T](i: Initialize[T]) = i mapReferenced g } + + private[this] def mapConstantT(g: MapConstant) = + new (Initialize ~> Initialize) { def apply[T](i: Initialize[T]) = i mapConstant g } + + private[this] def evaluateT(g: Settings[Scope]) = + new (Initialize ~> Id) { def apply[T](i: Initialize[T]) = i evaluate g } + + private[this] def dependencies(ls: Seq[Initialize[_]]): Seq[ScopedKey[_]] = ls.flatMap(_.dependsOn) + + sealed trait Keyed[S, T] extends Initialize[T] { - def dependsOn = a.toList - def map[Z](g: T => Z): Initialize[Z] = new Optional[S,Z](a, g compose f) - def get(map: Settings[Scope]): T = f(a map asFunction(map)) - def mapReferenced(g: MapScoped) = new Optional(a map g.fn, f) - def validateReferenced(g: ValidateRef) = Right( new Optional(a flatMap { sk => g(sk).right.toOption }, f) ) - def mapConstant(g: MapConstant): Initialize[T] = - (a flatMap g.fn) match { - case None => this - case s => new Value(() => f(s)) - } + def scopedKey: ScopedKey[S] + protected def transform: S => T + final def dependsOn = scopedKey :: Nil + final def apply[Z](g: T => Z): Initialize[Z] = new GetValue(scopedKey, g compose transform) + final def evaluate(ss: Settings[Scope]): T = transform(getValue(ss, scopedKey)) + final def mapReferenced(g: MapScoped): Initialize[T] = new GetValue( g(scopedKey), transform) + final def validateReferenced(g: ValidateRef): ValidatedInit[T] = g(scopedKey) match { + case Left(un) => Left(un :: Nil) + case Right(nk) => Right(new GetValue(nk, transform)) + } + final def mapConstant(g: MapConstant): Initialize[T] = g(scopedKey) match { + case None => this + case Some(const) => new Value(() => transform(const)) + } + @deprecated("Use scopedKey.") + def scoped = scopedKey } - private[this] final class Joined[S,T,U](a: Initialize[S], b: Initialize[T], f: (S,T) => U) extends Initialize[U] + private[this] final class GetValue[S,T](val scopedKey: ScopedKey[S], val transform: S => T) extends Keyed[S, T] + trait KeyedInitialize[T] extends Keyed[T, T] { + protected final val transform = idFun[T] + } + + private[this] final class Optional[S,T](a: Option[Initialize[S]], f: Option[S] => T) extends Initialize[T] { - def dependsOn = a.dependsOn ++ b.dependsOn - def mapReferenced(g: MapScoped) = new Joined(a mapReferenced g, b mapReferenced g, f) - def validateReferenced(g: ValidateRef) = - (a validateReferenced g, b validateReferenced g) match { - case (Right(ak), Right(bk)) => Right( new Joined(ak, bk, f) ) - case (au, bu) => Left( (au.left.toSeq ++ bu.left.toSeq).flatten ) - } - def map[Z](g: U => Z) = new Joined[S,T,Z](a, b, (s,t) => g(f(s,t))) - def mapConstant(g: MapConstant) = new Joined[S,T,U](a mapConstant g, b mapConstant g, f) - def get(map: Settings[Scope]): U = f(a get map, b get map) + def dependsOn = dependencies(a.toList) + def apply[Z](g: T => Z): Initialize[Z] = new Optional[S,Z](a, g compose f) + def evaluate(ss: Settings[Scope]): T = f(a map evaluateT(ss).fn) + def mapReferenced(g: MapScoped) = new Optional(a map mapReferencedT(g).fn, f) + def validateReferenced(g: ValidateRef) = Right( new Optional(a flatMap { _.validateReferenced(g).right.toOption }, f) ) + def mapConstant(g: MapConstant): Initialize[T] = new Optional(a map mapConstantT(g).fn, f) } private[this] final class Value[T](value: () => T) extends Initialize[T] { def dependsOn = Nil def mapReferenced(g: MapScoped) = this def validateReferenced(g: ValidateRef) = Right(this) - def map[S](g: T => S) = new Value[S](() => g(value())) + def apply[S](g: T => S) = new Value[S](() => g(value())) def mapConstant(g: MapConstant) = this - def get(map: Settings[Scope]): T = value() + def evaluate(map: Settings[Scope]): T = value() } - private[this] final class Apply[HL <: HList, T](val f: HL => T, val inputs: KList[ScopedKey, HL]) extends Initialize[T] + private[this] final class Apply[HL <: HList, T](val f: HL => T, val inputs: KList[Initialize, HL]) extends Initialize[T] { - def dependsOn = inputs.toList - def mapReferenced(g: MapScoped) = new Apply(f, inputs transform g) - def map[S](g: T => S) = new Apply(g compose f, inputs) - def mapConstant(g: MapConstant) = Reduced.reduceH(inputs, g).combine( (keys, expand) => new Apply(f compose expand, keys) ) - def get(map: Settings[Scope]) = f(inputs down asTransform(map) ) + def dependsOn = dependencies(inputs.toList) + def mapReferenced(g: MapScoped) = mapInputs( mapReferencedT(g) ) + def apply[S](g: T => S) = new Apply(g compose f, inputs) + def mapConstant(g: MapConstant) = mapInputs( mapConstantT(g) ) + def mapInputs(g: Initialize ~> Initialize): Initialize[T] = new Apply(f, inputs transform g) + def evaluate(ss: Settings[Scope]) = f(inputs down evaluateT(ss)) def validateReferenced(g: ValidateRef) = { - val tx = inputs.transform(g) - val undefs = tx.toList.flatMap(_.left.toSeq) - val get = new (ValidatedRef ~> ScopedKey) { def apply[T](vr: ValidatedRef[T]) = vr.right.get } + val tx = inputs transform validateReferencedT(g) + val undefs = tx.toList.flatMap(_.left.toSeq.flatten) + val get = new (ValidatedInit ~> Initialize) { def apply[T](vr: ValidatedInit[T]) = vr.right.get } if(undefs.isEmpty) Right(new Apply(f, tx transform get)) else Left(undefs) } } - private[this] final class KApply[HL <: HList, M[_], T](val f: KList[M, HL] => T, val inputs: KList[({type l[t] = ScopedKey[M[t]]})#l, HL]) extends Initialize[T] + private[this] final class KApply[HL <: HList, M[_], T](val f: KList[M, HL] => T, val inputs: KList[({type l[t] = Initialize[M[t]]})#l, HL]) extends Initialize[T] { - type ScopedKeyM[T] = ScopedKey[M[T]] - type VRefM[T] = ValidatedRef[M[T]] - def dependsOn = unnest(inputs.toList) - def mapReferenced(g: MapScoped) = new KApply[HL, M, T](f, inputs.transform[({type l[t] = ScopedKey[M[t]]})#l]( nestCon(g) ) ) - def map[S](g: T => S) = new KApply[HL, M, S](g compose f, inputs) - def get(map: Settings[Scope]) = f(inputs.transform[M]( nestCon[ScopedKey, Id, M](asTransform(map)) )) - def mapConstant(g: MapConstant) = - { - def mk[HLk <: HList](keys: KList[ScopedKeyM, HLk], expand: KList[M, HLk] => KList[M, HL]) = new KApply[HLk, M, T](f compose expand, keys) - Reduced.reduceK[HL, ScopedKey, M](inputs, nestCon(g)) combine mk - } + type InitializeM[T] = Initialize[M[T]] + type VInitM[T] = ValidatedInit[M[T]] + def dependsOn = dependencies(unnest(inputs.toList)) + def mapReferenced(g: MapScoped) = mapInputs( mapReferencedT(g) ) + def apply[S](g: T => S) = new KApply[HL, M, S](g compose f, inputs) + def evaluate(ss: Settings[Scope]) = f(inputs.transform[M]( nestCon(evaluateT(ss)) )) + def mapConstant(g: MapConstant) = mapInputs(mapConstantT(g)) + def mapInputs(g: Initialize ~> Initialize): Initialize[T] = + new KApply[HL, M, T](f, inputs.transform[({type l[t] = Initialize[M[t]]})#l]( nestCon(g) )) def validateReferenced(g: ValidateRef) = { - val tx = inputs.transform[VRefM](nestCon(g)) - val undefs = tx.toList.flatMap(_.left.toSeq) - val get = new (VRefM ~> ScopedKeyM) { def apply[T](vr: ValidatedRef[M[T]]) = vr.right.get } + val tx = inputs.transform[VInitM](nestCon(validateReferencedT(g))) + val undefs = tx.toList.flatMap(_.left.toSeq.flatten) + val get = new (VInitM ~> InitializeM) { def apply[T](vr: VInitM[T]) = vr.right.get } if(undefs.isEmpty) - Right(new KApply[HL, M, T](f, tx.transform( get ) )) + Right(new KApply[HL, M, T](f, tx transform get)) else Left(undefs) } - private[this] def unnest(l: List[ScopedKey[M[T]] forSome { type T }]): List[ScopedKey[_]] = l.asInstanceOf[List[ScopedKey[_]]] + private[this] def unnest(l: List[Initialize[M[T]] forSome { type T }]): List[Initialize[_]] = l.asInstanceOf[List[Initialize[_]]] } - private[this] final class Uniform[S, T](val f: Seq[S] => T, val inputs: Seq[ScopedKey[S]]) extends Initialize[T] + private[this] final class Uniform[S, T](val f: Seq[S] => T, val inputs: Seq[Initialize[S]]) extends Initialize[T] { - def dependsOn = inputs - def mapReferenced(g: MapScoped) = new Uniform(f, inputs map g.fn[S]) + def dependsOn = dependencies(inputs) + def mapReferenced(g: MapScoped) = new Uniform(f, inputs map mapReferencedT(g).fn) def validateReferenced(g: ValidateRef) = { - val (undefs, ok) = List.separate(inputs map g.fn[S]) - if(undefs.isEmpty) Right( new Uniform(f, ok) ) else Left(undefs) + val (undefs, ok) = List.separate(inputs map validateReferencedT(g).fn ) + if(undefs.isEmpty) Right( new Uniform(f, ok) ) else Left(undefs.flatten) } - def map[S](g: T => S) = new Uniform(g compose f, inputs) - def mapConstant(g: MapConstant) = - { - val red = Reduced.reduceSeq(inputs, g) - new Uniform(f compose red.expand, red.keys) - } - def get(map: Settings[Scope]) = f(inputs map asFunction(map)) + def apply[S](g: T => S) = new Uniform(g compose f, inputs) + def mapConstant(g: MapConstant) = new Uniform(f, inputs map mapConstantT(g).fn) + def evaluate(ss: Settings[Scope]) = f(inputs map evaluateT(ss).fn ) } private def remove[T](s: Seq[T], v: T) = s filterNot (_ == v) } diff --git a/util/collection/src/test/scala/SettingsExample.scala b/util/collection/src/test/scala/SettingsExample.scala index 38c09d634..8d7136f0f 100644 --- a/util/collection/src/test/scala/SettingsExample.scala +++ b/util/collection/src/test/scala/SettingsExample.scala @@ -12,9 +12,10 @@ final case class Scope(index: Int) // That would be a general pain.) object SettingsExample extends Init[Scope] { - // This is the only abstract method, providing a way of showing a Scope+AttributeKey[_] - override def display(key: ScopedKey[_]): String = - key.scope.index + "/" + key.key.label + // Provides a way of showing a Scope+AttributeKey[_] + val showFullKey: Show[ScopedKey[_]] = new Show[ScopedKey[_]] { + def apply(key: ScopedKey[_]) = key.scope.index + "/" + key.key.label + } // A sample delegation function that delegates to a Scope with a lower index. val delegates: Scope => Seq[Scope] = { case s @ Scope(index) => @@ -55,7 +56,7 @@ object SettingsUsage // "compiles" and applies the settings. // This can be split into multiple steps to access intermediate results if desired. // The 'inspect' command operates on the output of 'compile', for example. - val applied: Settings[Scope] = make(mySettings)(delegates, scopeLocal) + val applied: Settings[Scope] = make(mySettings)(delegates, scopeLocal, showFullKey) // Show results. for(i <- 0 to 5; k <- Seq(a, b)) {