mirror of https://github.com/sbt/sbt.git
Merge pull request #7882 from adpi2/2.x-fuse-info
[2.x] Remove instances of `Info` and `BasicAttributeMap`
This commit is contained in:
commit
87e6f66bf8
|
|
@ -344,11 +344,6 @@ object BuildUtilLite:
|
|||
end BuildUtilLite
|
||||
|
||||
object Index {
|
||||
def taskToKeyMap(data: Settings): Map[Task[?], ScopedKey[Task[?]]] =
|
||||
data.data.collect { case (key, value: Task[?]) =>
|
||||
(value, key.asInstanceOf[ScopedKey[Task[?]]])
|
||||
}
|
||||
|
||||
def allKeys(settings: Seq[Setting[?]]): Set[ScopedKey[?]] = {
|
||||
val result = new java.util.HashSet[ScopedKey[?]]
|
||||
settings.foreach { s =>
|
||||
|
|
@ -385,7 +380,7 @@ object Index {
|
|||
val triggeredBy = new TriggerMap
|
||||
ss.values.collect { case base: Task[?] =>
|
||||
def update(map: TriggerMap, key: AttributeKey[Seq[Task[?]]]): Unit =
|
||||
base.info.attributes.get(key).getOrElse(Seq.empty).foreach { task =>
|
||||
base.getOrElse(key, Seq.empty).foreach { task =>
|
||||
map(task) = base +: map.getOrElse(task, Nil)
|
||||
}
|
||||
update(runBefore, Def.runBefore)
|
||||
|
|
|
|||
|
|
@ -463,10 +463,7 @@ object Tests {
|
|||
fun: TestFunction,
|
||||
tags: Seq[(Tag, Int)]
|
||||
): Task[Map[String, SuiteResult]] = {
|
||||
val base = Task[(String, (SuiteResult, Seq[TestTask]))](
|
||||
Info[(String, (SuiteResult, Seq[TestTask]))]().setName(name),
|
||||
Action.Pure(() => (name, fun.apply()), `inline` = false)
|
||||
)
|
||||
val base = Task(Action.Pure(() => (name, fun.apply()), `inline` = false)).setName(name)
|
||||
val taggedBase = base.tagw(tags*).tag(fun.tags.map(ConcurrentRestrictions.Tag(_))*)
|
||||
taggedBase flatMap { case (name, (result, nested)) =>
|
||||
val nestedRunnables = createNestedRunnables(loader, fun, nested)
|
||||
|
|
|
|||
|
|
@ -458,11 +458,11 @@ object Def extends BuildSyntax with Init with InitializeImplicits:
|
|||
sys.error(s"Dummy task '$name' did not get converted to a full task.")
|
||||
)
|
||||
.named(name)
|
||||
base.copy(info = base.info.set(isDummyTask, true))
|
||||
base.set(isDummyTask, true)
|
||||
}
|
||||
|
||||
private[sbt] def isDummy(t: Task[?]): Boolean =
|
||||
t.info.attributes.get(isDummyTask) getOrElse false
|
||||
t.get(isDummyTask).getOrElse(false)
|
||||
end Def
|
||||
|
||||
sealed trait InitializeImplicits { self: Def.type =>
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ object Previous {
|
|||
val successfulTaskResults = (
|
||||
for
|
||||
case results.TPair(task: Task[?], Result.Value(v)) <- results.toTypedSeq
|
||||
key <- task.info.attributes.get(Def.taskDefinitionKey).asInstanceOf[Option[AnyTaskKey]]
|
||||
key <- task.get(Def.taskDefinitionKey).asInstanceOf[Option[AnyTaskKey]]
|
||||
yield key -> v
|
||||
).toMap
|
||||
// We then traverse the successful results and look up all of the referenced values for
|
||||
|
|
|
|||
|
|
@ -384,7 +384,7 @@ object Scoped:
|
|||
): Initialize[Task[A1]] =
|
||||
Initialize
|
||||
.joinAny[Task](coerceToAnyTaskSeq(tasks))
|
||||
.zipWith(init)((ts, i) => i.copy(info = i.info.set(key, ts)))
|
||||
.zipWith(init)((ts, i) => i.set(key, ts))
|
||||
|
||||
extension [A1](init: Initialize[InputTask[A1]])
|
||||
@targetName("onTaskInitializeInputTask")
|
||||
|
|
|
|||
|
|
@ -582,7 +582,7 @@ object EvaluateTask {
|
|||
Function.chain(
|
||||
results.toTypedSeq flatMap {
|
||||
case results.TPair(_, Result.Value(KeyValue(_, st: StateTransform))) => Some(st.transform)
|
||||
case results.TPair(Task(info, _), Result.Value(v)) => info.post(v).get(transformState)
|
||||
case results.TPair(task: Task[?], Result.Value(v)) => task.post(v).get(transformState)
|
||||
case _ => Nil
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -49,10 +49,9 @@ object SessionVar {
|
|||
|
||||
def orEmpty(opt: Option[Map]) = opt.getOrElse(emptyMap)
|
||||
|
||||
def transform[S](task: Task[S], f: (State, S) => State): Task[S] = {
|
||||
def transform[S](task: Task[S], f: (State, S) => State): Task[S] =
|
||||
val g = (s: S, map: AttributeMap) => map.put(Keys.transformState, (state: State) => f(state, s))
|
||||
task.copy(info = task.info.postTransform(g))
|
||||
}
|
||||
task.postTransform(g)
|
||||
|
||||
def resolveContext[T](
|
||||
key: ScopedKey[Task[T]],
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ private[sbt] abstract class AbstractTaskExecuteProgress extends ExecuteProgress
|
|||
}
|
||||
private def taskName0(t: TaskId[?]): String = {
|
||||
def definedName(node: Task[?]): Option[String] =
|
||||
node.info.name.orElse(TaskName.transformNode(node).map(showScopedKey.show))
|
||||
node.name.orElse(TaskName.transformNode(node).map(showScopedKey.show))
|
||||
def inferredName(t: Task[?]): Option[String] = nameDelegate(t) map taskName
|
||||
def nameDelegate(t: Task[?]): Option[TaskId[?]] =
|
||||
Option(anonOwners.get(t)).orElse(Option(calledBy.get(t)))
|
||||
|
|
|
|||
|
|
@ -71,7 +71,6 @@ final class BuildStructure(
|
|||
// information that is not original, but can be reconstructed from the rest of BuildStructure
|
||||
final class StructureIndex(
|
||||
val keyMap: Map[String, AttributeKey[?]],
|
||||
val taskToKey: Map[Task[?], ScopedKey[Task[?]]],
|
||||
val triggers: Triggers,
|
||||
val keyIndex: KeyIndex,
|
||||
val aggregateKeyIndex: KeyIndex,
|
||||
|
|
|
|||
|
|
@ -366,7 +366,7 @@ private[sbt] object Load {
|
|||
}
|
||||
|
||||
def setDefinitionKey[T](tk: Task[T], key: ScopedKey[?]): Task[T] =
|
||||
if (isDummy(tk)) tk else Task(tk.info.set(Keys.taskDefinitionKey, key), tk.work)
|
||||
if (isDummy(tk)) tk else tk.set(Keys.taskDefinitionKey, key)
|
||||
|
||||
def structureIndex(
|
||||
data: Def.Settings,
|
||||
|
|
@ -384,7 +384,6 @@ private[sbt] object Load {
|
|||
val aggIndex = KeyIndex.aggregate(scopedKeys, extra(keyIndex), projectsMap, configsMap)
|
||||
new StructureIndex(
|
||||
Index.stringToKeyMap(attributeKeys),
|
||||
Index.taskToKeyMap(data),
|
||||
Index.triggers(data),
|
||||
keyIndex,
|
||||
aggIndex
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ import Keys.taskDefinitionKey
|
|||
private[sbt] object TaskName {
|
||||
def name(node: Task[?]): String = definedName(node).getOrElse(anonymousName(node))
|
||||
def definedName(node: Task[?]): Option[String] =
|
||||
node.info.name.orElse(transformNode(node).map(displayFull))
|
||||
node.name.orElse(transformNode(node).map(displayFull))
|
||||
def anonymousName(node: TaskId[?]): String =
|
||||
"<anon-" + System.identityHashCode(node).toHexString + ">"
|
||||
def transformNode(node: Task[?]): Option[ScopedKey[?]] =
|
||||
node.info.attributes.get(taskDefinitionKey)
|
||||
node.get(taskDefinitionKey)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ private[sbt] object Settings {
|
|||
* @return the setting with the task definition
|
||||
*/
|
||||
private def addTaskDefinition[T](setting: Def.Setting[Task[T]]): Def.Setting[Task[T]] =
|
||||
setting.mapInit((sk, task) => Task(task.info.set(taskDefinitionKey, sk), task.work))
|
||||
setting.mapInit((sk, task) => task.set(taskDefinitionKey, sk))
|
||||
|
||||
/**
|
||||
* Returns all of the paths described by a glob along with their basic file attributes.
|
||||
|
|
|
|||
|
|
@ -14,32 +14,51 @@ import ConcurrentRestrictions.{ Tag, TagMap, tagsKey }
|
|||
import sbt.util.Monad
|
||||
|
||||
/**
|
||||
* Combines metadata `info` and a computation `work` to define a task.
|
||||
* Combines metadata `attributes` and a computation `work` to define a task.
|
||||
*/
|
||||
final case class Task[A](info: Info[A], work: Action[A]) extends TaskId[A]:
|
||||
override def toString = info.name getOrElse ("Task(" + info + ")")
|
||||
override def hashCode = info.hashCode
|
||||
final class Task[A](
|
||||
val attributes: AttributeMap,
|
||||
val post: A => AttributeMap,
|
||||
val work: Action[A]
|
||||
) extends TaskId[A]:
|
||||
override def toString = name.getOrElse(s"Task($attributes)")
|
||||
|
||||
def name: Option[String] = get(Task.Name)
|
||||
def description: Option[String] = get(Task.Description)
|
||||
def get[B](key: AttributeKey[B]): Option[B] = attributes.get(key)
|
||||
def getOrElse[B](key: AttributeKey[B], default: => B): B = attributes.getOrElse(key, default)
|
||||
|
||||
def setName(name: String): Task[A] = set(Task.Name, name)
|
||||
def setDescription(description: String): Task[A] = set(Task.Description, description)
|
||||
def set[B](key: AttributeKey[B], value: B) =
|
||||
new Task(attributes.put(key, value), post, work)
|
||||
|
||||
def postTransform(f: (A, AttributeMap) => AttributeMap): Task[A] =
|
||||
new Task(attributes, a => f(a, post(a)), work)
|
||||
|
||||
def tag(tags: Tag*): Task[A] = tagw(tags.map(t => (t, 1))*)
|
||||
def tagw(tags: (Tag, Int)*): Task[A] = {
|
||||
val tgs: TagMap = info.get(tagsKey).getOrElse(TagMap.empty)
|
||||
def tagw(tags: (Tag, Int)*): Task[A] =
|
||||
val tgs: TagMap = get(tagsKey).getOrElse(TagMap.empty)
|
||||
val value = tags.foldLeft(tgs)((acc, tag) => acc + tag)
|
||||
val nextInfo = info.set(tagsKey, value)
|
||||
withInfo(info = nextInfo)
|
||||
}
|
||||
|
||||
def tags: TagMap = info.get(tagsKey).getOrElse(TagMap.empty)
|
||||
def name: Option[String] = info.name
|
||||
|
||||
def attributes: AttributeMap = info.attributes
|
||||
|
||||
private[sbt] def withInfo(info: Info[A]): Task[A] =
|
||||
Task(info = info, work = this.work)
|
||||
set(tagsKey, value)
|
||||
def tags: TagMap = get(tagsKey).getOrElse(TagMap.empty)
|
||||
end Task
|
||||
|
||||
object Task:
|
||||
import sbt.std.TaskExtra.*
|
||||
|
||||
def apply[A](work: Action[A]): Task[A] =
|
||||
new Task[A](AttributeMap.empty, defaultAttributeMap, work)
|
||||
|
||||
def apply[A](attributes: AttributeMap, work: Action[A]): Task[A] =
|
||||
new Task[A](attributes, defaultAttributeMap, work)
|
||||
|
||||
def unapply[A](task: Task[A]): Option[Action[A]] = Some(task.work)
|
||||
|
||||
val Name = AttributeKey[String]("name")
|
||||
val Description = AttributeKey[String]("description")
|
||||
val defaultAttributeMap = const(AttributeMap.empty)
|
||||
|
||||
given taskMonad: Monad[Task] with
|
||||
type F[a] = Task[a]
|
||||
override def pure[A1](a: () => A1): Task[A1] = toTask(a)
|
||||
|
|
@ -54,34 +73,3 @@ object Task:
|
|||
override def flatMap[A1, A2](in: F[A1])(f: A1 => F[A2]): F[A2] = in.flatMap(f)
|
||||
override def flatten[A1](in: Task[Task[A1]]): Task[A1] = in.flatMap(identity)
|
||||
end Task
|
||||
|
||||
/**
|
||||
* Used to provide information about a task, such as the name, description, and tags for controlling
|
||||
* concurrent execution.
|
||||
* @param attributes
|
||||
* Arbitrary user-defined key/value pairs describing this task
|
||||
* @param post
|
||||
* a transformation that takes the result of evaluating this task and produces user-defined
|
||||
* key/value pairs.
|
||||
*/
|
||||
final case class Info[T](
|
||||
attributes: AttributeMap = AttributeMap.empty,
|
||||
post: T => AttributeMap = Info.defaultAttributeMap
|
||||
) {
|
||||
import Info._
|
||||
def name = attributes.get(Name)
|
||||
def description = attributes.get(Description)
|
||||
def setName(n: String) = set(Name, n)
|
||||
def setDescription(d: String) = set(Description, d)
|
||||
def set[A](key: AttributeKey[A], value: A) = copy(attributes = this.attributes.put(key, value))
|
||||
def get[A](key: AttributeKey[A]): Option[A] = attributes.get(key)
|
||||
def postTransform(f: (T, AttributeMap) => AttributeMap) = copy(post = (t: T) => f(t, post(t)))
|
||||
|
||||
override def toString = if (attributes.isEmpty) "_" else attributes.toString
|
||||
}
|
||||
|
||||
object Info:
|
||||
val Name = AttributeKey[String]("name")
|
||||
val Description = AttributeKey[String]("description")
|
||||
val defaultAttributeMap = const(AttributeMap.empty)
|
||||
end Info
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ trait TaskExtra0 {
|
|||
joinTasks0[Any](existToAny(in))
|
||||
private[sbt] def joinTasks0[S](in: Seq[Task[S]]): JoinTask[S, Seq] = new JoinTask[S, Seq] {
|
||||
def join: Task[Seq[S]] =
|
||||
Task[Seq[S]](Info(), Action.Join(in, (s: Seq[Result[S]]) => Right(TaskExtra.all(s))))
|
||||
Task[Seq[S]](Action.Join(in, (s: Seq[Result[S]]) => Right(TaskExtra.all(s))))
|
||||
def reduced(f: (S, S) => S): Task[S] = TaskExtra.reduced(in.toIndexedSeq, f)
|
||||
}
|
||||
private[sbt] def existToAny(in: Seq[Task[?]]): Seq[Task[Any]] = in.asInstanceOf[Seq[Task[Any]]]
|
||||
|
|
@ -114,8 +114,8 @@ trait TaskExtra extends TaskExtra0 {
|
|||
final def constant[T](t: T): Task[T] = task(t)
|
||||
|
||||
final def task[T](f: => T): Task[T] = toTask(() => f)
|
||||
final implicit def toTask[T](f: () => T): Task[T] = Task(Info(), Action.Pure(f, false))
|
||||
final def inlineTask[T](value: T): Task[T] = Task(Info(), Action.Pure(() => value, true))
|
||||
final implicit def toTask[T](f: () => T): Task[T] = Task(Action.Pure(f, false))
|
||||
final def inlineTask[T](value: T): Task[T] = Task(Action.Pure(() => value, true))
|
||||
|
||||
final implicit def upcastTask[A >: B, B](t: Task[B]): Task[A] = t mapN { x =>
|
||||
x: A
|
||||
|
|
@ -131,7 +131,7 @@ trait TaskExtra extends TaskExtra0 {
|
|||
|
||||
final implicit def joinTasks[S](in: Seq[Task[S]]): JoinTask[S, Seq] = new JoinTask[S, Seq] {
|
||||
def join: Task[Seq[S]] =
|
||||
Task[Seq[S]](Info(), Action.Join(in, (s: Seq[Result[S]]) => Right(TaskExtra.all(s))))
|
||||
Task[Seq[S]](Action.Join(in, (s: Seq[Result[S]]) => Right(TaskExtra.all(s))))
|
||||
def reduced(f: (S, S) => S): Task[S] = TaskExtra.reduced(in.toIndexedSeq, f)
|
||||
}
|
||||
|
||||
|
|
@ -144,18 +144,18 @@ trait TaskExtra extends TaskExtra0 {
|
|||
final implicit def multInputTask[Tup <: Tuple](tasks: Tuple.Map[Tup, Task]): MultiInTask[Tup] =
|
||||
new MultiInTask[Tup]:
|
||||
override def flatMapN[A](f: Tup => Task[A]): Task[A] =
|
||||
Task(Info(), Action.FlatMapped(tasks, f.compose(allM)))
|
||||
Task(Action.FlatMapped(tasks, f.compose(allM)))
|
||||
override def flatMapR[A](f: Tuple.Map[Tup, Result] => Task[A]): Task[A] =
|
||||
Task(Info(), Action.FlatMapped(tasks, f))
|
||||
Task(Action.FlatMapped(tasks, f))
|
||||
|
||||
override def mapN[A](f: Tup => A): Task[A] =
|
||||
Task(Info(), Action.Mapped(tasks, f.compose(allM)))
|
||||
Task(Action.Mapped(tasks, f.compose(allM)))
|
||||
override def mapR[A](f: Tuple.Map[Tup, Result] => A): Task[A] =
|
||||
Task(Info(), Action.Mapped(tasks, f))
|
||||
Task(Action.Mapped(tasks, f))
|
||||
override def flatFailure[A](f: Seq[Incomplete] => Task[A]): Task[A] =
|
||||
Task(Info(), Action.FlatMapped(tasks, f.compose(anyFailM)))
|
||||
Task(Action.FlatMapped(tasks, f.compose(anyFailM)))
|
||||
override def mapFailure[A](f: Seq[Incomplete] => A): Task[A] =
|
||||
Task(Info(), Action.Mapped(tasks, f.compose(anyFailM)))
|
||||
Task(Action.Mapped(tasks, f.compose(anyFailM)))
|
||||
|
||||
final implicit def singleInputTask[S](in: Task[S]): SingleInTask[S] =
|
||||
new SingleInTask[S]:
|
||||
|
|
@ -164,21 +164,22 @@ trait TaskExtra extends TaskExtra0 {
|
|||
def failure: Task[Incomplete] = mapFailure(identity)
|
||||
def result: Task[Result[S]] = mapR(identity)
|
||||
|
||||
private def newInfo[A]: Info[A] = TaskExtra.newInfo(in.info)
|
||||
private def newAttributes: AttributeMap = TaskExtra.newAttributes(in.attributes)
|
||||
|
||||
override def flatMapR[A](f: Result[S] => Task[A]): Task[A] =
|
||||
Task(
|
||||
newInfo,
|
||||
newAttributes,
|
||||
Action.FlatMapped[A, Tuple1[S]](Tuple1(in), { case Tuple1(a) => f(a) })
|
||||
)
|
||||
|
||||
override def mapR[A](f: Result[S] => A): Task[A] =
|
||||
Task(
|
||||
newInfo,
|
||||
newAttributes,
|
||||
Action.Mapped[A, Tuple1[S]](Tuple1(in), { case Tuple1(a) => f(a) })
|
||||
)
|
||||
|
||||
override def dependsOn(tasks: Task[?]*): Task[S] = Task(newInfo, Action.DependsOn(in, tasks))
|
||||
override def dependsOn(tasks: Task[?]*): Task[S] =
|
||||
Task(newAttributes, Action.DependsOn(in, tasks))
|
||||
|
||||
override def flatMapN[T](f: S => Task[T]): Task[T] = flatMapR(f.compose(successM))
|
||||
|
||||
|
|
@ -206,8 +207,8 @@ trait TaskExtra extends TaskExtra0 {
|
|||
def &&[T](alt: Task[T]): Task[T] = flatMapN(_ => alt)
|
||||
|
||||
final implicit def toTaskInfo[S](in: Task[S]): TaskInfo[S] = new TaskInfo[S] {
|
||||
def describedAs(s: String): Task[S] = in.copy(info = in.info.setDescription(s))
|
||||
def named(s: String): Task[S] = in.copy(info = in.info.setName(s))
|
||||
def describedAs(s: String): Task[S] = in.setDescription(s)
|
||||
def named(s: String): Task[S] = in.setName(s)
|
||||
}
|
||||
|
||||
final implicit def pipeToProcess[Key](
|
||||
|
|
@ -327,10 +328,10 @@ object TaskExtra extends TaskExtra {
|
|||
def incompleteDeps(incs: Seq[Incomplete]): Incomplete = Incomplete(None, causes = incs)
|
||||
|
||||
def select[A, B](fab: Task[Either[A, B]], f: Task[A => B]): Task[B] =
|
||||
Task(newInfo(fab.info), Action.Selected[A, B](fab, f))
|
||||
Task(newAttributes(fab.attributes), Action.Selected[A, B](fab, f))
|
||||
|
||||
// The "taskDefinitionKey" is used, at least, by the ".previous" functionality.
|
||||
// But apparently it *cannot* survive a task map/flatMap/etc. See actions/depends-on.
|
||||
private[sbt] def newInfo[A](info: Info[?]): Info[A] =
|
||||
Info[A](AttributeMap(info.attributes.entries.filter(_.key.label != "taskDefinitionKey")))
|
||||
private[sbt] def newAttributes[A](attributes: AttributeMap): AttributeMap =
|
||||
AttributeMap(attributes.entries.filter(_.key.label != "taskDefinitionKey"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import sbt.internal.util.Types.*
|
|||
|
||||
object Transform:
|
||||
def fromDummy[A](original: Task[A])(action: => A): Task[A] =
|
||||
Task(original.info, Action.Pure(() => action, false))
|
||||
new Task(original.attributes, original.post, work = Action.Pure(() => action, false))
|
||||
|
||||
def fromDummyStrict[T](original: Task[T], value: T): Task[T] = fromDummy(original)(value)
|
||||
|
||||
|
|
@ -57,8 +57,8 @@ object Transform:
|
|||
case Join(in, f) => uniform(in)(f)
|
||||
|
||||
def inline1[T](t: TaskId[T]): Option[() => T] = t match
|
||||
case Task(_, Action.Pure(eval, true)) => Some(eval)
|
||||
case _ => None
|
||||
case Task(Action.Pure(eval, true)) => Some(eval)
|
||||
case _ => None
|
||||
|
||||
def uniform[A1, D](tasks: Seq[Task[D]])(
|
||||
f: Seq[Result[D]] => Either[Task[A1], A1]
|
||||
|
|
|
|||
|
|
@ -158,123 +158,95 @@ object AttributeKey {
|
|||
* keys with the same label but different types. Excluding this possibility is the responsibility of
|
||||
* the client if desired.
|
||||
*/
|
||||
trait AttributeMap {
|
||||
|
||||
/**
|
||||
* Gets the value of type `T` associated with the key `k`. If a key with the same label but
|
||||
* different type is defined, this method will fail.
|
||||
*/
|
||||
def apply[T](k: AttributeKey[T]): T
|
||||
|
||||
/**
|
||||
* Gets the value of type `T` associated with the key `k` or `None` if no value is associated. If
|
||||
* a key with the same label but a different type is defined, this method will return `None`.
|
||||
*/
|
||||
def get[T](k: AttributeKey[T]): Option[T]
|
||||
|
||||
/**
|
||||
* Returns this map without the mapping for `k`. This method will not remove a mapping for a key
|
||||
* with the same label but a different type.
|
||||
*/
|
||||
def remove[T](k: AttributeKey[T]): AttributeMap
|
||||
|
||||
/**
|
||||
* Returns true if this map contains a mapping for `k`. If a key with the same label but a
|
||||
* different type is defined in this map, this method will return `false`.
|
||||
*/
|
||||
def contains[T](k: AttributeKey[T]): Boolean
|
||||
|
||||
/**
|
||||
* Adds the mapping `k -> value` to this map, replacing any existing mapping for `k`. Any mappings
|
||||
* for keys with the same label but different types are unaffected.
|
||||
*/
|
||||
def put[T](k: AttributeKey[T], value: T): AttributeMap
|
||||
|
||||
/**
|
||||
* All keys with defined mappings. There may be multiple keys with the same `label`, but different
|
||||
* types.
|
||||
*/
|
||||
def keys: Iterable[AttributeKey[?]]
|
||||
|
||||
/**
|
||||
* Adds the mappings in `o` to this map, with mappings in `o` taking precedence over existing
|
||||
* mappings.
|
||||
*/
|
||||
def ++(o: Iterable[AttributeEntry[?]]): AttributeMap
|
||||
|
||||
/**
|
||||
* Combines the mappings in `o` with the mappings in this map, with mappings in `o` taking
|
||||
* precedence over existing mappings.
|
||||
*/
|
||||
def ++(o: AttributeMap): AttributeMap
|
||||
|
||||
/**
|
||||
* All mappings in this map. The [[AttributeEntry]] type preserves the typesafety of mappings,
|
||||
* although the specific types are unknown.
|
||||
*/
|
||||
def entries: Iterable[AttributeEntry[?]]
|
||||
|
||||
/** `true` if there are no mappings in this map, `false` if there are. */
|
||||
def isEmpty: Boolean
|
||||
|
||||
/**
|
||||
* Adds the mapping `k -> opt.get` if opt is Some. Otherwise, it returns this map without the
|
||||
* mapping for `k`.
|
||||
*/
|
||||
private[sbt] def setCond[T](k: AttributeKey[T], opt: Option[T]): AttributeMap
|
||||
}
|
||||
|
||||
object AttributeMap {
|
||||
opaque type AttributeMap = Map[AttributeKey[?], Any]
|
||||
|
||||
object AttributeMap:
|
||||
/** An [[AttributeMap]] without any mappings. */
|
||||
val empty: AttributeMap = new BasicAttributeMap(Map.empty)
|
||||
val empty: AttributeMap = Map.empty
|
||||
|
||||
/** Constructs an [[AttributeMap]] containing the given `entries`. */
|
||||
def apply(entries: Iterable[AttributeEntry[?]]): AttributeMap = empty ++ entries
|
||||
def apply(entries: Iterable[AttributeEntry[?]]): AttributeMap = ++(empty)(entries)
|
||||
|
||||
/** Constructs an [[AttributeMap]] containing the given `entries`. */
|
||||
def apply(entries: AttributeEntry[?]*): AttributeMap = empty ++ entries
|
||||
def apply(entries: AttributeEntry[?]*): AttributeMap = ++(empty)(entries)
|
||||
|
||||
/** Presents an `AttributeMap` as a natural transformation. */
|
||||
// implicit def toNatTrans(map: AttributeMap): AttributeKey ~> Id = λ[AttributeKey ~> Id](map(_))
|
||||
}
|
||||
extension (self: AttributeMap)
|
||||
/**
|
||||
* Gets the value of type `T` associated with the key `k`. If a key with the same label but
|
||||
* different type is defined, this method will fail.
|
||||
*/
|
||||
def apply[T](k: AttributeKey[T]): T = self(k).asInstanceOf[T]
|
||||
|
||||
private class BasicAttributeMap(private val backing: Map[AttributeKey[?], Any])
|
||||
extends AttributeMap {
|
||||
/**
|
||||
* Gets the value of type `T` associated with the key `k` or `None` if no value is associated. If
|
||||
* a key with the same label but a different type is defined, this method will return `None`.
|
||||
*/
|
||||
def get[T](k: AttributeKey[T]): Option[T] = self.get(k).asInstanceOf[Option[T]]
|
||||
|
||||
def isEmpty: Boolean = backing.isEmpty
|
||||
def apply[T](k: AttributeKey[T]) = backing(k).asInstanceOf[T]
|
||||
def get[T](k: AttributeKey[T]) = backing.get(k).asInstanceOf[Option[T]]
|
||||
def remove[T](k: AttributeKey[T]): AttributeMap = new BasicAttributeMap(backing - k)
|
||||
def contains[T](k: AttributeKey[T]) = backing.contains(k)
|
||||
/**
|
||||
* Gets the value of type `T` associated with the key `k` or `default` if no value is associated. If
|
||||
* a key with the same label but a different type is defined, this method will return `default`.
|
||||
*/
|
||||
def getOrElse[T](k: AttributeKey[T], default: => T): T =
|
||||
self.getOrElse(k, default).asInstanceOf[T]
|
||||
|
||||
def put[T](k: AttributeKey[T], value: T): AttributeMap =
|
||||
new BasicAttributeMap(backing.updated(k, value: Any))
|
||||
/**
|
||||
* Returns this map without the mapping for `k`. This method will not remove a mapping for a key
|
||||
* with the same label but a different type.
|
||||
*/
|
||||
def remove[T](k: AttributeKey[T]): AttributeMap = self.removed(k)
|
||||
|
||||
def keys: Iterable[AttributeKey[?]] = backing.keys
|
||||
/**
|
||||
* Returns true if this map contains a mapping for `k`. If a key with the same label but a
|
||||
* different type is defined in this map, this method will return `false`.
|
||||
*/
|
||||
def contains[T](k: AttributeKey[T]): Boolean = self.contains(k)
|
||||
|
||||
def ++(o: Iterable[AttributeEntry[?]]): AttributeMap =
|
||||
new BasicAttributeMap(o.foldLeft(backing)((b, e) => b.updated(e.key, e.value: Any)))
|
||||
/**
|
||||
* Adds the mapping `k -> value` to this map, replacing any existing mapping for `k`. Any mappings
|
||||
* for keys with the same label but different types are unaffected.
|
||||
*/
|
||||
def put[T](k: AttributeKey[T], value: T): AttributeMap = self.updated(k, value)
|
||||
|
||||
def ++(o: AttributeMap): AttributeMap = o match {
|
||||
case bam: BasicAttributeMap =>
|
||||
new BasicAttributeMap(Map(backing.toSeq ++ bam.backing.toSeq*))
|
||||
case _ => o ++ this
|
||||
}
|
||||
/**
|
||||
* All keys with defined mappings. There may be multiple keys with the same `label`, but different
|
||||
* types.
|
||||
*/
|
||||
def keys: Iterable[AttributeKey[?]] = self.keys
|
||||
|
||||
def entries: Iterable[AttributeEntry[?]] =
|
||||
backing.collect { case (k: AttributeKey[kt], v) =>
|
||||
AttributeEntry(k, v.asInstanceOf[kt])
|
||||
}
|
||||
/**
|
||||
* Adds the mappings in `o` to this map, with mappings in `o` taking precedence over existing
|
||||
* mappings.
|
||||
*/
|
||||
def ++(o: Iterable[AttributeEntry[?]]): AttributeMap =
|
||||
o.foldLeft(self)((b, e) => b.updated(e.key, e.value))
|
||||
|
||||
private[sbt] def setCond[T](k: AttributeKey[T], opt: Option[T]): AttributeMap =
|
||||
opt match {
|
||||
case Some(v) => put(k, v)
|
||||
case None => remove(k)
|
||||
}
|
||||
/**
|
||||
* Combines the mappings in `o` with the mappings in this map, with mappings in `o` taking
|
||||
* precedence over existing mappings.
|
||||
*/
|
||||
def ++(o: AttributeMap): AttributeMap = self ++ o
|
||||
|
||||
override def toString = entries.mkString("(", ", ", ")")
|
||||
}
|
||||
/**
|
||||
* All mappings in this map. The [[AttributeEntry]] type preserves the typesafety of mappings,
|
||||
* although the specific types are unknown.
|
||||
*/
|
||||
def entries: Iterable[AttributeEntry[?]] =
|
||||
self.collect { case (k: AttributeKey[x], v) => AttributeEntry(k, v.asInstanceOf[x]) }
|
||||
|
||||
/** `true` if there are no mappings in this map, `false` if there are. */
|
||||
def isEmpty: Boolean = self.isEmpty
|
||||
|
||||
/**
|
||||
* Adds the mapping `k -> opt.get` if opt is Some. Otherwise, it returns this map without the
|
||||
* mapping for `k`.
|
||||
*/
|
||||
private[sbt] def setCond[T](k: AttributeKey[T], opt: Option[T]): AttributeMap =
|
||||
opt match
|
||||
case Some(v) => self.updated(k, v)
|
||||
case None => self.removed(k)
|
||||
end extension
|
||||
end AttributeMap
|
||||
|
||||
/**
|
||||
* An immutable map where both key and value are String.
|
||||
|
|
|
|||
Loading…
Reference in New Issue