Skip to content

Commit 6676949

Browse files
authored
Change Graph's 'mapValues' APIs to pass key path in addition to value to transform closure (#372)
This is a small change which begins passing key path _in addition to_ value to Graph's `mapValue` and `compactMapValue` APIs. ### Motivation: This was extracted out from work in #366, and is initially intended for use in that PR but is a generally-useful enhancement. ### Checklist: - [x] Code and documentation should follow the style of the [Style Guide](https://github.com/apple/swift-testing/blob/main/Documentation/StyleGuide.md). - [x] If public symbols are renamed or modified, DocC references should be updated.
1 parent b46b3f3 commit 6676949

File tree

4 files changed

+127
-63
lines changed

4 files changed

+127
-63
lines changed

Sources/Testing/Running/Configuration.TestFilter.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ extension Configuration.TestFilter.Kind {
219219
case .unfiltered:
220220
return testGraph
221221
case let .precomputed(selection, membership):
222-
return testGraph.mapValues { test in
222+
return testGraph.mapValues { _, test in
223223
guard let test else {
224224
return nil
225225
}
@@ -250,7 +250,9 @@ extension Configuration.TestFilter.Kind {
250250
return zip(
251251
lhs.apply(to: testGraph),
252252
rhs.apply(to: testGraph)
253-
).mapValues(op.functionValue)
253+
).mapValues { _, value in
254+
op.functionValue(value.0, value.1)
255+
}
254256
}
255257
}
256258
}
@@ -271,7 +273,7 @@ extension Configuration.TestFilter {
271273
// combined test filters. It is only consulted on the outermost call to
272274
// apply(to:), not in _apply(to:).
273275
if !includeHiddenTests {
274-
result = result.mapValues { test in
276+
result = result.mapValues { _, test in
275277
(test?.isHidden == true) ? nil : test
276278
}
277279
}

Sources/Testing/Running/Runner.Plan.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -237,13 +237,13 @@ extension Runner.Plan {
237237

238238
// Now that we have allowed all the traits to update their corresponding
239239
// actions, recursively apply those actions to child tests in the graph.
240-
actionGraph = actionGraph.mapValues { action in
240+
actionGraph = actionGraph.mapValues { _, action in
241241
(action, recursivelyApply: action.isRecursive)
242242
}
243243

244244
// Zip the tests and actions together and return them.
245-
return zip(testGraph, actionGraph).mapValues { test, action in
246-
test.map { Step(test: $0, action: action) }
245+
return zip(testGraph, actionGraph).mapValues { _, pair in
246+
pair.0.map { Step(test: $0, action: pair.1) }
247247
}
248248
}
249249

Sources/Testing/Support/Graph.swift

Lines changed: 95 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ extension Graph {
406406
///
407407
/// - Parameters:
408408
/// - keyPath: The key path to use for the root node when passing it to
409-
/// `body`.
409+
/// `body`.
410410
/// - body: A closure that is invoked once per element in the graph. The
411411
/// key path and leaf value of each node are passed to the closure.
412412
///
@@ -485,18 +485,18 @@ extension Graph {
485485
///
486486
/// - Parameters:
487487
/// - transform: A closure that is invoked once per element in the graph.
488-
/// The leaf value of each node is passed to this closure and its result
489-
/// is used as the corresponding value in the new graph. If the result is
490-
/// `nil`, the node and all of its child nodes are omitted from the new
491-
/// graph.
488+
/// The key path and leaf value of each node are passed to this closure
489+
/// and its result is used as the corresponding value in the new graph. If
490+
/// the result is `nil`, the node and all of its child nodes are omitted
491+
/// from the new graph.
492492
///
493493
/// - Returns: A graph containing the transformed nodes of this graph at the
494494
/// same key paths, with `nil` values omitted.
495495
///
496496
/// - Throws: Whatever is thrown by `transform`.
497497
///
498498
/// This function iterates depth-first.
499-
func compactMapValues<U>(_ transform: (V) throws -> U?) rethrows -> Graph<K, U>? {
499+
func compactMapValues<U>(_ transform: (Element) throws -> U?) rethrows -> Graph<K, U>? {
500500
try compactMapValues {
501501
try transform($0).map { ($0, false) }
502502
}
@@ -507,18 +507,18 @@ extension Graph {
507507
///
508508
/// - Parameters:
509509
/// - transform: A closure that is invoked once per element in the graph.
510-
/// The leaf value of each node is passed to this closure and its result
511-
/// is used as the corresponding value in the new graph. If the result is
512-
/// `nil`, the node and all of its child nodes are omitted from the new
513-
/// graph.
510+
/// The key path and leaf value of each node are passed to this closure
511+
/// and its result is used as the corresponding value in the new graph. If
512+
/// the result is `nil`, the node and all of its child nodes are omitted
513+
/// from the new graph.
514514
///
515515
/// - Returns: A graph containing the transformed nodes of this graph at the
516516
/// same key paths, with `nil` values omitted.
517517
///
518518
/// - Throws: Whatever is thrown by `transform`.
519519
///
520520
/// This function iterates depth-first.
521-
func compactMapValues<U>(_ transform: (V) async throws -> U?) async rethrows -> Graph<K, U>? {
521+
func compactMapValues<U>(_ transform: (Element) async throws -> U?) async rethrows -> Graph<K, U>? {
522522
try await compactMapValues {
523523
try await transform($0).map { ($0, false) }
524524
}
@@ -530,31 +530,54 @@ extension Graph {
530530
///
531531
/// - Parameters:
532532
/// - transform: A closure that is invoked once per element in the graph.
533-
/// The leaf value of each node is passed to this closure. The result of
534-
/// the closure is a tuple containing the new value and specifying whether
535-
/// or not the new value should also be applied to each descendant node.
536-
/// If `true`, `transform` is not invoked for those descendant nodes. If
537-
/// the result is `nil`, the node and all of its child nodes are omitted
538-
/// from the new graph.
533+
/// The key path and leaf value of each node are passed to this closure.
534+
/// The result of the closure is a tuple containing the new value and
535+
/// specifying whether or not the new value should also be applied to each
536+
/// descendant node. If `true`, `transform` is not invoked for those
537+
/// descendant nodes. If the result is `nil`, the node and all of its
538+
/// child nodes are omitted from the new graph.
539539
///
540540
/// - Returns: A graph containing the transformed nodes of this graph at the
541541
/// same key paths, with `nil` values omitted.
542542
///
543543
/// - Throws: Whatever is thrown by `transform`.
544544
///
545545
/// This function iterates depth-first.
546-
func compactMapValues<U>(_ transform: (V) throws -> (U, recursivelyApply: Bool)?) rethrows -> Graph<K, U>? {
547-
guard let (newValue, recursivelyApply) = try transform(value) else {
546+
func compactMapValues<U>(_ transform: (Element) throws -> (U, recursivelyApply: Bool)?) rethrows -> Graph<K, U>? {
547+
try _compactMapValues(keyPath: []) {
548+
try transform(($0, $1))
549+
}
550+
}
551+
552+
/// The recursive implementation of `compactMapValues(_:)`.
553+
///
554+
/// - Parameters:
555+
/// - keyPath: The key path to use for the root node when passing it to
556+
/// `transform`.
557+
/// - transform: A closure that is invoked once per element in the graph.
558+
/// The key path and leaf value of each node are passed to this closure.
559+
/// The result of the closure is a tuple containing the new value and
560+
/// specifying whether or not the new value should also be applied to each
561+
/// descendant node. If `true`, `transform` is not invoked for those
562+
/// descendant nodes. If the result is `nil`, the node and all of its
563+
/// child nodes are omitted from the new graph.
564+
///
565+
/// - Throws: Whatever is thrown by `transform`.
566+
private func _compactMapValues<U>(keyPath: [K], _ transform: (Element) throws -> (U, recursivelyApply: Bool)?) rethrows -> Graph<K, U>? {
567+
guard let (newValue, recursivelyApply) = try transform((keyPath, value)) else {
548568
return nil
549569
}
550570

551571
var newChildren = [K: Graph<K,U>]()
552572
newChildren.reserveCapacity(children.count)
553573
for (key, child) in children {
574+
var childKeyPath = keyPath
575+
childKeyPath.append(key)
576+
554577
if recursivelyApply {
555-
newChildren[key] = child.compactMapValues { _ in (newValue, true) }
578+
newChildren[key] = child._compactMapValues(keyPath: childKeyPath) { _ in (newValue, true) }
556579
} else {
557-
newChildren[key] = try child.compactMapValues(transform)
580+
newChildren[key] = try child._compactMapValues(keyPath: childKeyPath, transform)
558581
}
559582
}
560583

@@ -567,31 +590,54 @@ extension Graph {
567590
///
568591
/// - Parameters:
569592
/// - transform: A closure that is invoked once per element in the graph.
570-
/// The leaf value of each node is passed to this closure. The result of
571-
/// the closure is a tuple containing the new value and specifying whether
572-
/// or not the new value should also be applied to each descendant node.
573-
/// If `true`, `transform` is not invoked for those descendant nodes. If
574-
/// the result is `nil`, the node and all of its child nodes are omitted
575-
/// from the new graph.
593+
/// The key path and leaf value of each node are passed to this closure.
594+
/// The result of the closure is a tuple containing the new value and
595+
/// specifying whether or not the new value should also be applied to each
596+
/// descendant node. If `true`, `transform` is not invoked for those
597+
/// descendant nodes. If the result is `nil`, the node and all of its
598+
/// child nodes are omitted from the new graph.
576599
///
577600
/// - Returns: A graph containing the transformed nodes of this graph at the
578601
/// same key paths, with `nil` values omitted.
579602
///
580603
/// - Throws: Whatever is thrown by `transform`.
581604
///
582605
/// This function iterates depth-first.
583-
func compactMapValues<U>(_ transform: (V) async throws -> (U, recursivelyApply: Bool)?) async rethrows -> Graph<K, U>? {
584-
guard let (newValue, recursivelyApply) = try await transform(value) else {
606+
func compactMapValues<U>(_ transform: (Element) async throws -> (U, recursivelyApply: Bool)?) async rethrows -> Graph<K, U>? {
607+
try await _compactMapValues(keyPath: []) {
608+
try await transform(($0, $1))
609+
}
610+
}
611+
612+
/// The recursive implementation of `compactMapValues(_:)`.
613+
///
614+
/// - Parameters:
615+
/// - keyPath: The key path to use for the root node when passing it to
616+
/// `transform`.
617+
/// - transform: A closure that is invoked once per element in the graph.
618+
/// The key path and leaf value of each node are passed to this closure.
619+
/// The result of the closure is a tuple containing the new value and
620+
/// specifying whether or not the new value should also be applied to each
621+
/// descendant node. If `true`, `transform` is not invoked for those
622+
/// descendant nodes. If the result is `nil`, the node and all of its
623+
/// child nodes are omitted from the new graph.
624+
///
625+
/// - Throws: Whatever is thrown by `transform`.
626+
private func _compactMapValues<U>(keyPath: [K], _ transform: (Element) async throws -> (U, recursivelyApply: Bool)?) async rethrows -> Graph<K, U>? {
627+
guard let (newValue, recursivelyApply) = try await transform((keyPath, value)) else {
585628
return nil
586629
}
587630

588631
var newChildren = [K: Graph<K,U>]()
589632
newChildren.reserveCapacity(children.count)
590633
for (key, child) in children {
634+
var childKeyPath = keyPath
635+
childKeyPath.append(key)
636+
591637
if recursivelyApply {
592-
newChildren[key] = child.compactMapValues { _ in (newValue, true) }
638+
newChildren[key] = child._compactMapValues(keyPath: childKeyPath) { _ in (newValue, true) }
593639
} else {
594-
newChildren[key] = try await child.compactMapValues(transform)
640+
newChildren[key] = try await child._compactMapValues(keyPath: childKeyPath, transform)
595641
}
596642
}
597643

@@ -603,16 +649,16 @@ extension Graph {
603649
///
604650
/// - Parameters:
605651
/// - transform: A closure that is invoked once per element in the graph.
606-
/// The leaf value of each node is passed to this closure and its result
607-
/// is used as the corresponding value in the new graph.
652+
/// The key path and leaf value of each node are passed to this closure
653+
/// and its result is used as the corresponding value in the new graph.
608654
///
609655
/// - Returns: A graph containing the transformed nodes of this graph at the
610656
/// same key paths.
611657
///
612658
/// - Throws: Whatever is thrown by `transform`.
613659
///
614660
/// This function iterates depth-first.
615-
func mapValues<U>(_ transform: (V) throws -> U) rethrows -> Graph<K, U> {
661+
func mapValues<U>(_ transform: (Element) throws -> U) rethrows -> Graph<K, U> {
616662
try compactMapValues(transform)!
617663
}
618664

@@ -621,16 +667,16 @@ extension Graph {
621667
///
622668
/// - Parameters:
623669
/// - transform: A closure that is invoked once per element in the graph.
624-
/// The leaf value of each node is passed to this closure and its result
625-
/// is used as the corresponding value in the new graph.
670+
/// The key path and leaf value of each node are passed to this closure
671+
/// and its result is used as the corresponding value in the new graph.
626672
///
627673
/// - Returns: A graph containing the transformed nodes of this graph at the
628674
/// same key paths.
629675
///
630676
/// - Throws: Whatever is thrown by `transform`.
631677
///
632678
/// This function iterates depth-first.
633-
func mapValues<U>(_ transform: (V) async throws -> U) async rethrows -> Graph<K, U> {
679+
func mapValues<U>(_ transform: (Element) async throws -> U) async rethrows -> Graph<K, U> {
634680
try await compactMapValues(transform)!
635681
}
636682

@@ -640,18 +686,19 @@ extension Graph {
640686
///
641687
/// - Parameters:
642688
/// - transform: A closure that is invoked once per element in the graph.
643-
/// The leaf value of each node is passed to this closure. The result of
644-
/// the closure is a tuple containing the new value and specifying whether
645-
/// or not the new value should also be applied to each descendant node.
646-
/// If `true`, `transform` is not invoked for those descendant nodes.
689+
/// The key path and leaf value of each node are passed to this closure.
690+
/// The result of the closure is a tuple containing the new value and
691+
/// specifying whether or not the new value should also be applied to each
692+
/// descendant node. If `true`, `transform` is not invoked for those
693+
/// descendant nodes.
647694
///
648695
/// - Returns: A graph containing the transformed nodes of this graph at the
649696
/// same key paths.
650697
///
651698
/// - Throws: Whatever is thrown by `transform`.
652699
///
653700
/// This function iterates depth-first.
654-
func mapValues<U>(_ transform: (V) throws -> (U, recursivelyApply: Bool)) rethrows -> Graph<K, U> {
701+
func mapValues<U>(_ transform: (Element) throws -> (U, recursivelyApply: Bool)) rethrows -> Graph<K, U> {
655702
try compactMapValues(transform)!
656703
}
657704

@@ -661,18 +708,19 @@ extension Graph {
661708
///
662709
/// - Parameters:
663710
/// - transform: A closure that is invoked once per element in the graph.
664-
/// The leaf value of each node is passed to this closure. The result of
665-
/// the closure is a tuple containing the new value and specifying whether
666-
/// or not the new value should also be applied to each descendant node.
667-
/// If `true`, `transform` is not invoked for those descendant nodes.
711+
/// The key path and leaf value of each node are passed to this closure.
712+
/// The result of the closure is a tuple containing the new value and
713+
/// specifying whether or not the new value should also be applied to each
714+
/// descendant node. If `true`, `transform` is not invoked for those
715+
/// descendant nodes.
668716
///
669717
/// - Returns: A graph containing the transformed nodes of this graph at the
670718
/// same key paths.
671719
///
672720
/// - Throws: Whatever is thrown by `transform`.
673721
///
674722
/// This function iterates depth-first.
675-
func mapValues<U>(_ transform: (V) async throws -> (U, recursivelyApply: Bool)) async rethrows -> Graph<K, U> {
723+
func mapValues<U>(_ transform: (Element) async throws -> (U, recursivelyApply: Bool)) async rethrows -> Graph<K, U> {
676724
try await compactMapValues(transform)!
677725
}
678726

0 commit comments

Comments
 (0)