From 5fff2c65f6c2248a16e8c849302328c4a115850a Mon Sep 17 00:00:00 2001
From: Clive <clive819@gmail.com>
Date: Mon, 29 Jul 2024 22:35:52 -0400
Subject: [PATCH 01/11] Implement AsyncMapErrorSequence

---
 .../AsyncMapErrorSequence.swift               | 78 +++++++++++++++++
 Tests/AsyncAlgorithmsTests/TestMapError.swift | 83 +++++++++++++++++++
 2 files changed, 161 insertions(+)
 create mode 100644 Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
 create mode 100644 Tests/AsyncAlgorithmsTests/TestMapError.swift

diff --git a/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift b/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
new file mode 100644
index 00000000..97f9b0cc
--- /dev/null
+++ b/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2024 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+public extension AsyncSequence {
+
+    /// Converts any failure into a new error.
+    ///
+    /// - Parameter transform: A closure that takes the failure as a parameter and returns a new error.
+    /// - Returns: An asynchronous sequence that maps the error thrown into the one produced by the transform closure.
+    ///
+    /// Use the ``mapError(_:)`` operator when you need to replace one error type with another.
+    func mapError<ErrorType>(transform: @Sendable @escaping (Error) -> ErrorType) -> AsyncMapErrorSequence<Self, ErrorType> {
+        .init(base: self, transform: transform)
+    }
+}
+
+/// An asynchronous sequence that converts any failure into a new error.
+public struct AsyncMapErrorSequence<Base: AsyncSequence, ErrorType: Error>: AsyncSequence, Sendable where Base: Sendable {
+
+    public typealias AsyncIterator = Iterator
+    public typealias Element = Base.Element
+
+    private let base: Base
+    private let transform: @Sendable (Error) -> ErrorType
+
+    init(
+        base: Base,
+        transform: @Sendable @escaping (Error) -> ErrorType
+    ) {
+        self.base = base
+        self.transform = transform
+    }
+
+    public func makeAsyncIterator() -> Iterator {
+        Iterator(
+            base: base.makeAsyncIterator(),
+            transform: transform
+        )
+    }
+}
+
+public extension AsyncMapErrorSequence {
+    
+    /// The iterator that produces elements of the map sequence.
+    struct Iterator: AsyncIteratorProtocol {
+
+        public typealias Element = Base.Element
+
+        private var base: Base.AsyncIterator
+
+        private let transform: @Sendable (Error) -> ErrorType
+
+        public init(
+            base: Base.AsyncIterator,
+            transform: @Sendable @escaping (Error) -> ErrorType
+        ) {
+            self.base = base
+            self.transform = transform
+        }
+
+        public mutating func next() async throws -> Element? {
+            do {
+                return try await base.next()
+            } catch {
+                throw transform(error)
+            }
+        }
+    }
+}
diff --git a/Tests/AsyncAlgorithmsTests/TestMapError.swift b/Tests/AsyncAlgorithmsTests/TestMapError.swift
new file mode 100644
index 00000000..7e6636a6
--- /dev/null
+++ b/Tests/AsyncAlgorithmsTests/TestMapError.swift
@@ -0,0 +1,83 @@
+import AsyncAlgorithms
+import XCTest
+
+final class TestMapError: XCTestCase {
+
+    func test_mapError() async throws {
+        let array = [URLError(.badURL)]
+        let sequence = array.async
+            .map { throw $0 }
+            .mapError { _ in
+                MyAwesomeError()
+            }
+
+        do {
+            for try await _ in sequence {
+                XCTFail("sequence should throw")
+            }
+        } catch {
+            _ = try XCTUnwrap(error as? MyAwesomeError)
+        }
+    }
+
+    func test_nonThrowing() async throws {
+        let array = [1, 2, 3, 4, 5]
+        let sequence = array.async
+            .mapError { _ in
+                MyAwesomeError()
+            }
+
+        var actual: [Int] = []
+        for try await value in sequence {
+            actual.append(value)
+        }
+        XCTAssertEqual(array, actual)
+    }
+
+    func test_cancellation() async throws {
+        let source = Indefinite(value: "test").async
+        let sequence = source.mapError { _ in MyAwesomeError() }
+
+        let finished = expectation(description: "finished")
+        let iterated = expectation(description: "iterated")
+
+        let task = Task {
+            var firstIteration = false
+            for try await el in sequence {
+                XCTAssertEqual(el, "test")
+
+                if !firstIteration {
+                    firstIteration = true
+                    iterated.fulfill()
+                }
+            }
+            finished.fulfill()
+        }
+
+        // ensure the other task actually starts
+        await fulfillment(of: [iterated], timeout: 1.0)
+        // cancellation should ensure the loop finishes
+        // without regards to the remaining underlying sequence
+        task.cancel()
+        await fulfillment(of: [finished], timeout: 1.0)
+    }
+
+    func test_empty() async throws {
+        let array: [Int] = []
+        let sequence = array.async
+            .mapError { _ in
+                MyAwesomeError()
+            }
+
+        var actual: [Int] = []
+        for try await value in sequence {
+            actual.append(value)
+        }
+        XCTAssert(actual.isEmpty)
+    }
+}
+
+private extension TestMapError {
+
+    struct MyAwesomeError: Error {}
+}

From e54d1fd21a67b1749b77d442617fce1349164ca6 Mon Sep 17 00:00:00 2001
From: Clive <clive819@gmail.com>
Date: Tue, 15 Oct 2024 18:51:28 -0400
Subject: [PATCH 02/11] Address PR comments

---
 .../AsyncMapErrorSequence.swift               | 33 +++++++++++++++----
 Tests/AsyncAlgorithmsTests/TestMapError.swift |  8 ++++-
 2 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift b/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
index 97f9b0cc..dffcba82 100644
--- a/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
+++ b/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
@@ -10,7 +10,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-public extension AsyncSequence {
+extension AsyncSequence {
 
     /// Converts any failure into a new error.
     ///
@@ -18,13 +18,13 @@ public extension AsyncSequence {
     /// - Returns: An asynchronous sequence that maps the error thrown into the one produced by the transform closure.
     ///
     /// Use the ``mapError(_:)`` operator when you need to replace one error type with another.
-    func mapError<ErrorType>(transform: @Sendable @escaping (Error) -> ErrorType) -> AsyncMapErrorSequence<Self, ErrorType> {
+    public func mapError<ErrorType>(transform: @Sendable @escaping (Error) -> ErrorType) -> AsyncMapErrorSequence<Self, ErrorType> {
         .init(base: self, transform: transform)
     }
 }
 
 /// An asynchronous sequence that converts any failure into a new error.
-public struct AsyncMapErrorSequence<Base: AsyncSequence, ErrorType: Error>: AsyncSequence, Sendable where Base: Sendable {
+public struct AsyncMapErrorSequence<Base: AsyncSequence, ErrorType: Error>: AsyncSequence {
 
     public typealias AsyncIterator = Iterator
     public typealias Element = Base.Element
@@ -48,10 +48,10 @@ public struct AsyncMapErrorSequence<Base: AsyncSequence, ErrorType: Error>: Asyn
     }
 }
 
-public extension AsyncMapErrorSequence {
+extension AsyncMapErrorSequence {
     
     /// The iterator that produces elements of the map sequence.
-    struct Iterator: AsyncIteratorProtocol {
+    public struct Iterator: AsyncIteratorProtocol {
 
         public typealias Element = Base.Element
 
@@ -59,7 +59,7 @@ public extension AsyncMapErrorSequence {
 
         private let transform: @Sendable (Error) -> ErrorType
 
-        public init(
+        init(
             base: Base.AsyncIterator,
             transform: @Sendable @escaping (Error) -> ErrorType
         ) {
@@ -67,6 +67,24 @@ public extension AsyncMapErrorSequence {
             self.transform = transform
         }
 
+#if compiler(>=6.0)
+        public mutating func next() async throws(ErrorType) -> Element? {
+            do {
+                return try await base.next()
+            } catch {
+                throw transform(error)
+            }
+        }
+
+        @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
+        public mutating func next(isolation actor: isolated (any Actor)?) async throws(ErrorType) -> Element? {
+            do {
+                return try await base.next(isolation: actor)
+            } catch {
+                throw transform(error)
+            }
+        }
+#else
         public mutating func next() async throws -> Element? {
             do {
                 return try await base.next()
@@ -74,5 +92,8 @@ public extension AsyncMapErrorSequence {
                 throw transform(error)
             }
         }
+#endif
     }
 }
+
+extension AsyncMapErrorSequence: Sendable where Base: Sendable, Base.Element: Sendable {}
diff --git a/Tests/AsyncAlgorithmsTests/TestMapError.swift b/Tests/AsyncAlgorithmsTests/TestMapError.swift
index 7e6636a6..2aaae9c4 100644
--- a/Tests/AsyncAlgorithmsTests/TestMapError.swift
+++ b/Tests/AsyncAlgorithmsTests/TestMapError.swift
@@ -16,7 +16,13 @@ final class TestMapError: XCTestCase {
                 XCTFail("sequence should throw")
             }
         } catch {
-            _ = try XCTUnwrap(error as? MyAwesomeError)
+#if compiler(>=6.0)
+            // NO-OP
+            // The compiler already checks that for us since we're using typed throws.
+            // Writing that assert will just give compiler warning.
+#else
+            XCTAssert(error is MyAwesomeError)
+#endif
         }
     }
 

From 79ef6cd7824132defc8a71408d04847c83145f9a Mon Sep 17 00:00:00 2001
From: Clive <clive819@gmail.com>
Date: Tue, 15 Oct 2024 19:23:24 -0400
Subject: [PATCH 03/11] fix rookie mistake

---
 Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift b/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
index dffcba82..9fc873dc 100644
--- a/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
+++ b/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
@@ -18,7 +18,7 @@ extension AsyncSequence {
     /// - Returns: An asynchronous sequence that maps the error thrown into the one produced by the transform closure.
     ///
     /// Use the ``mapError(_:)`` operator when you need to replace one error type with another.
-    public func mapError<ErrorType>(transform: @Sendable @escaping (Error) -> ErrorType) -> AsyncMapErrorSequence<Self, ErrorType> {
+    public func mapError<ErrorType: Error>(transform: @Sendable @escaping (any Error) -> ErrorType) -> AsyncMapErrorSequence<Self, ErrorType> {
         .init(base: self, transform: transform)
     }
 }
@@ -30,11 +30,11 @@ public struct AsyncMapErrorSequence<Base: AsyncSequence, ErrorType: Error>: Asyn
     public typealias Element = Base.Element
 
     private let base: Base
-    private let transform: @Sendable (Error) -> ErrorType
+    private let transform: @Sendable (any Error) -> ErrorType
 
     init(
         base: Base,
-        transform: @Sendable @escaping (Error) -> ErrorType
+        transform: @Sendable @escaping (any Error) -> ErrorType
     ) {
         self.base = base
         self.transform = transform
@@ -57,11 +57,11 @@ extension AsyncMapErrorSequence {
 
         private var base: Base.AsyncIterator
 
-        private let transform: @Sendable (Error) -> ErrorType
+        private let transform: @Sendable (any Error) -> ErrorType
 
         init(
             base: Base.AsyncIterator,
-            transform: @Sendable @escaping (Error) -> ErrorType
+            transform: @Sendable @escaping (any Error) -> ErrorType
         ) {
             self.base = base
             self.transform = transform

From 4ba9c84becdc3279ced63bf2faea6ce705a9769d Mon Sep 17 00:00:00 2001
From: Clive <clive819@gmail.com>
Date: Wed, 16 Oct 2024 21:06:38 -0400
Subject: [PATCH 04/11] Adopt Failure type + add pitch doc

---
 Evolution/NNNN-map-error.md                   | 139 ++++++++++++++++++
 .../AsyncMapErrorSequence.swift               | 100 ++++++++++++-
 Tests/AsyncAlgorithmsTests/TestMapError.swift |  40 +++--
 3 files changed, 266 insertions(+), 13 deletions(-)
 create mode 100644 Evolution/NNNN-map-error.md

diff --git a/Evolution/NNNN-map-error.md b/Evolution/NNNN-map-error.md
new file mode 100644
index 00000000..ed10b08d
--- /dev/null
+++ b/Evolution/NNNN-map-error.md
@@ -0,0 +1,139 @@
+# Map Error
+
+* Proposal: [NNNN](NNNN-map-error.md)
+* Authors: [Clive Liu](https://github.com/clive819)
+* Review Manager: TBD
+* Status: **Awaiting review**
+
+*During the review process, add the following fields as needed:*
+
+* Implementation: [apple/swift-async-algorithms#324](https://github.com/apple/swift-async-algorithms/pull/324)
+* Decision Notes: 
+* Bugs: 
+
+## Introduction
+
+The mapError function empowers developers to elegantly transform errors within asynchronous sequences, enhancing code readability and maintainability.
+
+```swift
+extension AsyncSequence {
+
+    public func mapError<ErrorType: Error>(_ transform: @Sendable @escaping (Self.Failure) -> ErrorType) -> AsyncMapErrorSequence<Self, ErrorType>
+
+}
+```
+
+## Detailed design
+
+The actual implementation is quite simple actually - it's just simple do-catch block and invoking the transform closure inside the catch block - so we'll focus more on implementation decisions with regard to the compiler and OS versions difference.
+
+```swift
+extension AsyncSequence {
+
+#if compiler(>=6.0)
+    /// Converts any failure into a new error.
+    ///
+    /// - Parameter transform: A closure that takes the failure as a parameter and returns a new error.
+    /// - Returns: An asynchronous sequence that maps the error thrown into the one produced by the transform closure.
+    ///
+    /// Use the ``mapError(_:)`` operator when you need to replace one error type with another.
+    @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
+    public func mapError<ErrorType: Error>(_ transform: @Sendable @escaping (Self.Failure) -> ErrorType) -> AsyncMapErrorSequence<Self, ErrorType>
+#endif
+
+    /// Converts any failure into a new error.
+    ///
+    /// - Parameter transform: A closure that takes the failure as a parameter and returns a new error.
+    /// - Returns: An asynchronous sequence that maps the error thrown into the one produced by the transform closure.
+    ///
+    /// Use the ``mapError(_:)`` operator when you need to replace one error type with another.
+    @available(macOS, deprecated: 15.0, renamed: "mapError")
+    @available(iOS, deprecated: 18.0, renamed: "mapError")
+    @available(watchOS, deprecated: 11.0, renamed: "mapError")
+    @available(tvOS, deprecated: 18.0, renamed: "mapError")
+    @available(visionOS, deprecated: 2.0, renamed: "mapError")
+    public func mapAnyError<ErrorType: Error>(_ transform: @Sendable @escaping (any Error) -> ErrorType) -> AsyncMapAnyErrorSequence<Self, ErrorType>
+}
+```
+
+The compiler check is needed to ensure the code can be built on older Xcode versions (15 and below). `AsyncSequence.Failure` is only available in new SDK that ships with Xcode 16 that has the 6.0 compiler, we'd get this error without the compiler check `'Failure' is not a member type of type 'Self'`.
+
+As to the naming `mapError` versus `mapAnyError`, this is the trade off we have to make due to the lack of the ability to mark function as unavailable from certain OS version. The function signatures are the same, if the function names were the same, compiler will always choose the one with `any Error` instead of the one that has more specific error type.
+
+This function returns a concrete type instead of `some AsyncSequence` because using an opaque type would render typed throws feature ineffective by erasing the type, thereby preventing the compiler from ensuring that the returned sequence matches our intended new type. The benefits of using typed throws for this specific case outweigh the exposure of the internal types.
+
+```
+/// An asynchronous sequence that converts any failure into a new error.
+@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
+public struct AsyncMapErrorSequence<Base: AsyncSequence, ErrorType: Error>: AsyncSequence {
+
+    public typealias AsyncIterator = Iterator
+    public typealias Element = Base.Element
+
+    private let base: Base
+    private let transform: @Sendable (Base.Failure) -> ErrorType
+
+    init(
+        base: Base,
+        transform: @Sendable @escaping (Base.Failure) -> ErrorType
+    ) {
+        self.base = base
+        self.transform = transform
+    }
+
+    public func makeAsyncIterator() -> Iterator {
+        Iterator(
+            base: base.makeAsyncIterator(),
+            transform: transform
+        )
+    }
+}
+
+@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
+extension AsyncMapErrorSequence {
+
+    /// The iterator that produces elements of the map sequence.
+    public struct Iterator: AsyncIteratorProtocol {
+
+        public typealias Element = Base.Element
+
+        private var base: Base.AsyncIterator
+
+        private let transform: @Sendable (Base.Failure) -> ErrorType
+
+        init(
+            base: Base.AsyncIterator,
+            transform: @Sendable @escaping (Base.Failure) -> ErrorType
+        ) {
+            self.base = base
+            self.transform = transform
+        }
+
+
+        public mutating func next() async throws(ErrorType) -> Element? {
+            do {
+                return try await base.next(isolation: nil)
+            } catch {
+                throw transform(error)
+            }
+        }
+
+        public mutating func next(isolation actor: isolated (any Actor)?) async throws(ErrorType) -> Element? {
+            do {
+                return try await base.next(isolation: actor)
+            } catch {
+                throw transform(error)
+            }
+        }
+    }
+}
+
+@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
+extension AsyncMapErrorSequence: Sendable where Base: Sendable, Base.Element: Sendable {}
+```
+
+`AsyncMapAnyErrorSequence` would have similar implementation except it uses `any Error` instead of the associated Failure type, and doesn't support typed throws if the compiler is less than 6.0.
+
+## Naming
+
+The naming follows to current method naming of the Combine [mapError](https://developer.apple.com/documentation/combine/publisher/maperror(_:)) method.
diff --git a/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift b/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
index 9fc873dc..e1bdf72d 100644
--- a/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
+++ b/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
@@ -12,23 +12,115 @@
 
 extension AsyncSequence {
 
+#if compiler(>=6.0)
     /// Converts any failure into a new error.
     ///
     /// - Parameter transform: A closure that takes the failure as a parameter and returns a new error.
     /// - Returns: An asynchronous sequence that maps the error thrown into the one produced by the transform closure.
     ///
     /// Use the ``mapError(_:)`` operator when you need to replace one error type with another.
-    public func mapError<ErrorType: Error>(transform: @Sendable @escaping (any Error) -> ErrorType) -> AsyncMapErrorSequence<Self, ErrorType> {
+    @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
+    public func mapError<ErrorType: Error>(_ transform: @Sendable @escaping (Self.Failure) -> ErrorType) -> AsyncMapErrorSequence<Self, ErrorType> {
+        .init(base: self, transform: transform)
+    }
+#endif
+
+    /// Converts any failure into a new error.
+    ///
+    /// - Parameter transform: A closure that takes the failure as a parameter and returns a new error.
+    /// - Returns: An asynchronous sequence that maps the error thrown into the one produced by the transform closure.
+    ///
+    /// Use the ``mapAnyError(_:)`` operator when you need to replace one error type with another.
+    @available(macOS, deprecated: 15.0, renamed: "mapError")
+    @available(iOS, deprecated: 18.0, renamed: "mapError")
+    @available(watchOS, deprecated: 11.0, renamed: "mapError")
+    @available(tvOS, deprecated: 18.0, renamed: "mapError")
+    @available(visionOS, deprecated: 2.0, renamed: "mapError")
+    public func mapAnyError<ErrorType: Error>(_ transform: @Sendable @escaping (any Error) -> ErrorType) -> AsyncMapAnyErrorSequence<Self, ErrorType> {
         .init(base: self, transform: transform)
     }
 }
 
+// MARK: - AsyncMapErrorSequence
+
+#if compiler(>=6.0)
 /// An asynchronous sequence that converts any failure into a new error.
+@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
 public struct AsyncMapErrorSequence<Base: AsyncSequence, ErrorType: Error>: AsyncSequence {
 
     public typealias AsyncIterator = Iterator
     public typealias Element = Base.Element
 
+    private let base: Base
+    private let transform: @Sendable (Base.Failure) -> ErrorType
+
+    init(
+        base: Base,
+        transform: @Sendable @escaping (Base.Failure) -> ErrorType
+    ) {
+        self.base = base
+        self.transform = transform
+    }
+
+    public func makeAsyncIterator() -> Iterator {
+        Iterator(
+            base: base.makeAsyncIterator(),
+            transform: transform
+        )
+    }
+}
+
+@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
+extension AsyncMapErrorSequence {
+
+    /// The iterator that produces elements of the map sequence.
+    public struct Iterator: AsyncIteratorProtocol {
+
+        public typealias Element = Base.Element
+
+        private var base: Base.AsyncIterator
+
+        private let transform: @Sendable (Base.Failure) -> ErrorType
+
+        init(
+            base: Base.AsyncIterator,
+            transform: @Sendable @escaping (Base.Failure) -> ErrorType
+        ) {
+            self.base = base
+            self.transform = transform
+        }
+
+
+        public mutating func next() async throws(ErrorType) -> Element? {
+            do {
+                return try await base.next(isolation: nil)
+            } catch {
+                throw transform(error)
+            }
+        }
+
+        public mutating func next(isolation actor: isolated (any Actor)?) async throws(ErrorType) -> Element? {
+            do {
+                return try await base.next(isolation: actor)
+            } catch {
+                throw transform(error)
+            }
+        }
+    }
+}
+
+@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
+extension AsyncMapErrorSequence: Sendable where Base: Sendable, Base.Element: Sendable {}
+#endif
+
+// MARK: - AsyncMapAnyErrorSequence
+
+/// An asynchronous sequence that converts any failure into a new error.
+public struct AsyncMapAnyErrorSequence<Base: AsyncSequence, ErrorType: Error>: AsyncSequence {
+
+    public typealias AsyncIterator = Iterator
+    public typealias Element = Base.Element
+
     private let base: Base
     private let transform: @Sendable (any Error) -> ErrorType
 
@@ -48,8 +140,8 @@ public struct AsyncMapErrorSequence<Base: AsyncSequence, ErrorType: Error>: Asyn
     }
 }
 
-extension AsyncMapErrorSequence {
-    
+extension AsyncMapAnyErrorSequence {
+
     /// The iterator that produces elements of the map sequence.
     public struct Iterator: AsyncIteratorProtocol {
 
@@ -96,4 +188,4 @@ extension AsyncMapErrorSequence {
     }
 }
 
-extension AsyncMapErrorSequence: Sendable where Base: Sendable, Base.Element: Sendable {}
+extension AsyncMapAnyErrorSequence: Sendable where Base: Sendable, Base.Element: Sendable {}
diff --git a/Tests/AsyncAlgorithmsTests/TestMapError.swift b/Tests/AsyncAlgorithmsTests/TestMapError.swift
index 2aaae9c4..655717ff 100644
--- a/Tests/AsyncAlgorithmsTests/TestMapError.swift
+++ b/Tests/AsyncAlgorithmsTests/TestMapError.swift
@@ -3,11 +3,11 @@ import XCTest
 
 final class TestMapError: XCTestCase {
 
-    func test_mapError() async throws {
+    func test_mapAnyError() async throws {
         let array = [URLError(.badURL)]
         let sequence = array.async
             .map { throw $0 }
-            .mapError { _ in
+            .mapAnyError { _ in
                 MyAwesomeError()
             }
 
@@ -20,19 +20,38 @@ final class TestMapError: XCTestCase {
             // NO-OP
             // The compiler already checks that for us since we're using typed throws.
             // Writing that assert will just give compiler warning.
+            error.hoorayTypedThrows()
 #else
             XCTAssert(error is MyAwesomeError)
 #endif
         }
     }
 
-    func test_nonThrowing() async throws {
-        let array = [1, 2, 3, 4, 5]
+    @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
+    func test_mapError() async throws {
+        let array = [URLError(.badURL)]
         let sequence = array.async
+            .map { throw $0 }
             .mapError { _ in
                 MyAwesomeError()
             }
 
+        do {
+            for try await _ in sequence {
+                XCTFail("sequence should throw")
+            }
+        } catch {
+            error.hoorayTypedThrows()
+        }
+    }
+
+    func test_mapAnyError_nonThrowing() async throws {
+        let array = [1, 2, 3, 4, 5]
+        let sequence = array.async
+            .mapAnyError { _ in
+                MyAwesomeError()
+            }
+
         var actual: [Int] = []
         for try await value in sequence {
             actual.append(value)
@@ -40,9 +59,9 @@ final class TestMapError: XCTestCase {
         XCTAssertEqual(array, actual)
     }
 
-    func test_cancellation() async throws {
+    func test_mapAnyError_cancellation() async throws {
         let source = Indefinite(value: "test").async
-        let sequence = source.mapError { _ in MyAwesomeError() }
+        let sequence = source.mapAnyError { _ in MyAwesomeError() }
 
         let finished = expectation(description: "finished")
         let iterated = expectation(description: "iterated")
@@ -68,10 +87,10 @@ final class TestMapError: XCTestCase {
         await fulfillment(of: [finished], timeout: 1.0)
     }
 
-    func test_empty() async throws {
+    func test_mapAnyError_empty() async throws {
         let array: [Int] = []
         let sequence = array.async
-            .mapError { _ in
+            .mapAnyError { _ in
                 MyAwesomeError()
             }
 
@@ -85,5 +104,8 @@ final class TestMapError: XCTestCase {
 
 private extension TestMapError {
 
-    struct MyAwesomeError: Error {}
+    struct MyAwesomeError: Error {
+
+        func hoorayTypedThrows() {}
+    }
 }

From 201c84ceff0b527a56977717d45640f2ca780860 Mon Sep 17 00:00:00 2001
From: Clive <clive819@gmail.com>
Date: Wed, 16 Oct 2024 21:08:27 -0400
Subject: [PATCH 05/11] fix typo

---
 Evolution/NNNN-map-error.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Evolution/NNNN-map-error.md b/Evolution/NNNN-map-error.md
index ed10b08d..385942a8 100644
--- a/Evolution/NNNN-map-error.md
+++ b/Evolution/NNNN-map-error.md
@@ -1,6 +1,6 @@
 # Map Error
 
-* Proposal: [NNNN](NNNN-map-error.md)
+* Proposal: [SAA-NNNN](NNNN-map-error.md)
 * Authors: [Clive Liu](https://github.com/clive819)
 * Review Manager: TBD
 * Status: **Awaiting review**
@@ -62,7 +62,7 @@ As to the naming `mapError` versus `mapAnyError`, this is the trade off we have
 
 This function returns a concrete type instead of `some AsyncSequence` because using an opaque type would render typed throws feature ineffective by erasing the type, thereby preventing the compiler from ensuring that the returned sequence matches our intended new type. The benefits of using typed throws for this specific case outweigh the exposure of the internal types.
 
-```
+```swift
 /// An asynchronous sequence that converts any failure into a new error.
 @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
 public struct AsyncMapErrorSequence<Base: AsyncSequence, ErrorType: Error>: AsyncSequence {

From 9d490f4a95b2c1c10bdd8d05b26c7787c27be658 Mon Sep 17 00:00:00 2001
From: Clive <clive819@gmail.com>
Date: Wed, 16 Oct 2024 21:10:34 -0400
Subject: [PATCH 06/11] remove extra empty line

---
 Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift b/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
index e1bdf72d..7245f7a1 100644
--- a/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
+++ b/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
@@ -90,7 +90,6 @@ extension AsyncMapErrorSequence {
             self.transform = transform
         }
 
-
         public mutating func next() async throws(ErrorType) -> Element? {
             do {
                 return try await base.next(isolation: nil)

From 0193e847803b5acaf0905953aa0c28cd36992713 Mon Sep 17 00:00:00 2001
From: Clive <clive819@gmail.com>
Date: Thu, 17 Oct 2024 19:50:18 -0400
Subject: [PATCH 07/11] address forums feedback

---
 Evolution/NNNN-map-error.md                   | 139 ----------------
 Evolution/NNNN-map-failure.md                 | 149 ++++++++++++++++++
 ...ce.swift => AsyncMapFailureSequence.swift} |  75 ++++-----
 Tests/AsyncAlgorithmsTests/TestMapError.swift |  20 +--
 4 files changed, 197 insertions(+), 186 deletions(-)
 delete mode 100644 Evolution/NNNN-map-error.md
 create mode 100644 Evolution/NNNN-map-failure.md
 rename Sources/AsyncAlgorithms/{AsyncMapErrorSequence.swift => AsyncMapFailureSequence.swift} (62%)

diff --git a/Evolution/NNNN-map-error.md b/Evolution/NNNN-map-error.md
deleted file mode 100644
index 385942a8..00000000
--- a/Evolution/NNNN-map-error.md
+++ /dev/null
@@ -1,139 +0,0 @@
-# Map Error
-
-* Proposal: [SAA-NNNN](NNNN-map-error.md)
-* Authors: [Clive Liu](https://github.com/clive819)
-* Review Manager: TBD
-* Status: **Awaiting review**
-
-*During the review process, add the following fields as needed:*
-
-* Implementation: [apple/swift-async-algorithms#324](https://github.com/apple/swift-async-algorithms/pull/324)
-* Decision Notes: 
-* Bugs: 
-
-## Introduction
-
-The mapError function empowers developers to elegantly transform errors within asynchronous sequences, enhancing code readability and maintainability.
-
-```swift
-extension AsyncSequence {
-
-    public func mapError<ErrorType: Error>(_ transform: @Sendable @escaping (Self.Failure) -> ErrorType) -> AsyncMapErrorSequence<Self, ErrorType>
-
-}
-```
-
-## Detailed design
-
-The actual implementation is quite simple actually - it's just simple do-catch block and invoking the transform closure inside the catch block - so we'll focus more on implementation decisions with regard to the compiler and OS versions difference.
-
-```swift
-extension AsyncSequence {
-
-#if compiler(>=6.0)
-    /// Converts any failure into a new error.
-    ///
-    /// - Parameter transform: A closure that takes the failure as a parameter and returns a new error.
-    /// - Returns: An asynchronous sequence that maps the error thrown into the one produced by the transform closure.
-    ///
-    /// Use the ``mapError(_:)`` operator when you need to replace one error type with another.
-    @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-    public func mapError<ErrorType: Error>(_ transform: @Sendable @escaping (Self.Failure) -> ErrorType) -> AsyncMapErrorSequence<Self, ErrorType>
-#endif
-
-    /// Converts any failure into a new error.
-    ///
-    /// - Parameter transform: A closure that takes the failure as a parameter and returns a new error.
-    /// - Returns: An asynchronous sequence that maps the error thrown into the one produced by the transform closure.
-    ///
-    /// Use the ``mapError(_:)`` operator when you need to replace one error type with another.
-    @available(macOS, deprecated: 15.0, renamed: "mapError")
-    @available(iOS, deprecated: 18.0, renamed: "mapError")
-    @available(watchOS, deprecated: 11.0, renamed: "mapError")
-    @available(tvOS, deprecated: 18.0, renamed: "mapError")
-    @available(visionOS, deprecated: 2.0, renamed: "mapError")
-    public func mapAnyError<ErrorType: Error>(_ transform: @Sendable @escaping (any Error) -> ErrorType) -> AsyncMapAnyErrorSequence<Self, ErrorType>
-}
-```
-
-The compiler check is needed to ensure the code can be built on older Xcode versions (15 and below). `AsyncSequence.Failure` is only available in new SDK that ships with Xcode 16 that has the 6.0 compiler, we'd get this error without the compiler check `'Failure' is not a member type of type 'Self'`.
-
-As to the naming `mapError` versus `mapAnyError`, this is the trade off we have to make due to the lack of the ability to mark function as unavailable from certain OS version. The function signatures are the same, if the function names were the same, compiler will always choose the one with `any Error` instead of the one that has more specific error type.
-
-This function returns a concrete type instead of `some AsyncSequence` because using an opaque type would render typed throws feature ineffective by erasing the type, thereby preventing the compiler from ensuring that the returned sequence matches our intended new type. The benefits of using typed throws for this specific case outweigh the exposure of the internal types.
-
-```swift
-/// An asynchronous sequence that converts any failure into a new error.
-@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-public struct AsyncMapErrorSequence<Base: AsyncSequence, ErrorType: Error>: AsyncSequence {
-
-    public typealias AsyncIterator = Iterator
-    public typealias Element = Base.Element
-
-    private let base: Base
-    private let transform: @Sendable (Base.Failure) -> ErrorType
-
-    init(
-        base: Base,
-        transform: @Sendable @escaping (Base.Failure) -> ErrorType
-    ) {
-        self.base = base
-        self.transform = transform
-    }
-
-    public func makeAsyncIterator() -> Iterator {
-        Iterator(
-            base: base.makeAsyncIterator(),
-            transform: transform
-        )
-    }
-}
-
-@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-extension AsyncMapErrorSequence {
-
-    /// The iterator that produces elements of the map sequence.
-    public struct Iterator: AsyncIteratorProtocol {
-
-        public typealias Element = Base.Element
-
-        private var base: Base.AsyncIterator
-
-        private let transform: @Sendable (Base.Failure) -> ErrorType
-
-        init(
-            base: Base.AsyncIterator,
-            transform: @Sendable @escaping (Base.Failure) -> ErrorType
-        ) {
-            self.base = base
-            self.transform = transform
-        }
-
-
-        public mutating func next() async throws(ErrorType) -> Element? {
-            do {
-                return try await base.next(isolation: nil)
-            } catch {
-                throw transform(error)
-            }
-        }
-
-        public mutating func next(isolation actor: isolated (any Actor)?) async throws(ErrorType) -> Element? {
-            do {
-                return try await base.next(isolation: actor)
-            } catch {
-                throw transform(error)
-            }
-        }
-    }
-}
-
-@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-extension AsyncMapErrorSequence: Sendable where Base: Sendable, Base.Element: Sendable {}
-```
-
-`AsyncMapAnyErrorSequence` would have similar implementation except it uses `any Error` instead of the associated Failure type, and doesn't support typed throws if the compiler is less than 6.0.
-
-## Naming
-
-The naming follows to current method naming of the Combine [mapError](https://developer.apple.com/documentation/combine/publisher/maperror(_:)) method.
diff --git a/Evolution/NNNN-map-failure.md b/Evolution/NNNN-map-failure.md
new file mode 100644
index 00000000..95d06b5c
--- /dev/null
+++ b/Evolution/NNNN-map-failure.md
@@ -0,0 +1,149 @@
+# Map Failure
+
+* Proposal: [SAA-NNNN](NNNN-map-failure.md)
+* Authors: [Clive Liu](https://github.com/clive819)
+* Review Manager: TBD
+* Status: **Awaiting review**
+
+*During the review process, add the following fields as needed:*
+
+* Implementation: [apple/swift-async-algorithms#324](https://github.com/apple/swift-async-algorithms/pull/324)
+* Decision Notes: 
+* Bugs: 
+
+## Introduction
+
+The `mapFailure` function empowers developers to elegantly transform errors within asynchronous sequences, enhancing code readability and maintainability.
+
+```swift
+extension AsyncSequence {
+
+    public func mapFailure<MappedFailure: Error>(_ transform: @Sendable @escaping (Self.Failure) -> MappedFailure) -> some AsyncSequence<Self.Element, MappedFailure> {
+        AsyncMapFailureSequence(base: self, transform: transform)
+    }
+
+}
+```
+
+## Detailed design
+
+The actual implementation is quite simple actually - it's just simple do-catch block and invoking the transform closure inside the catch block - so we'll focus more on implementation decisions with regard to the compiler and OS versions difference.
+
+```swift
+extension AsyncSequence {
+
+#if compiler(>=6.0)
+    /// Converts any failure into a new error.
+    ///
+    /// - Parameter transform: A closure that takes the failure as a parameter and returns a new error.
+    /// - Returns: An asynchronous sequence that maps the error thrown into the one produced by the transform closure.
+    ///
+    /// Use the ``mapFailure(_:)`` operator when you need to replace one error type with another.
+    @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
+    public func mapFailure<MappedFailure: Error>(_ transform: @Sendable @escaping (Self.Failure) -> MappedFailure) -> some AsyncSequence<Self.Element, MappedFailure> {
+        AsyncMapFailureSequence(base: self, transform: transform)
+    }
+#endif
+
+    /// Converts any error into a new error.
+    ///
+    /// - Parameter transform: A closure that takes the error as a parameter and returns a new error.
+    /// - Returns: An asynchronous sequence that maps the error thrown into the one produced by the transform closure.
+    ///
+    /// Use the ``mapError(_:)`` operator when you need to replace one error type with another.
+    @available(macOS, deprecated: 15.0, renamed: "mapFailure")
+    @available(iOS, deprecated: 18.0, renamed: "mapFailure")
+    @available(watchOS, deprecated: 11.0, renamed: "mapFailure")
+    @available(tvOS, deprecated: 18.0, renamed: "mapFailure")
+    @available(visionOS, deprecated: 2.0, renamed: "mapFailure")
+    public func mapError<MappedError: Error>(_ transform: @Sendable @escaping (any Error) -> MappedError) -> AsyncMapErrorSequence<Self, MappedError> {
+        .init(base: self, transform: transform)
+    }
+}
+```
+
+The compiler check is needed to ensure the code can be built on older Xcode versions (15 and below). `AsyncSequence.Failure` is only available in new SDK that ships with Xcode 16 that has the 6.0 compiler, we'd get this error without the compiler check `'Failure' is not a member type of type 'Self'`.
+
+As to the naming `mapFailure` versus `mapError`, this is the trade off we have to make due to the lack of the ability to mark function as unavailable from certain OS version. The function signatures are the same, if the function names were the same, compiler will always choose the one with `any Error` instead of the one that has more specific error type.
+
+`mapError` function returns a concrete type instead of `some AsyncSequence<Self.Element, MappedError>` because `AsyncSequence.Failure` is only available in newer OS versions, we cannot specify it in old versions. And because using an opaque type would render typed throws feature ineffective by erasing the type, thereby preventing the compiler from ensuring that the returned sequence matches our intended new type. The benefits of using typed throws for this specific case outweigh the exposure of the internal types.
+
+```swift
+#if compiler(>=6.0)
+/// An asynchronous sequence that converts any failure into a new error.
+@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
+struct AsyncMapFailureSequence<Base: AsyncSequence, MappedFailure: Error>: AsyncSequence {
+
+    typealias AsyncIterator = Iterator
+    typealias Element = Base.Element
+    typealias Failure = Base.Failure
+
+    private let base: Base
+    private let transform: @Sendable (Failure) -> MappedFailure
+
+    init(
+        base: Base,
+        transform: @Sendable @escaping (Failure) -> MappedFailure
+    ) {
+        self.base = base
+        self.transform = transform
+    }
+
+    func makeAsyncIterator() -> Iterator {
+        Iterator(
+            base: base.makeAsyncIterator(),
+            transform: transform
+        )
+    }
+}
+
+@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
+extension AsyncMapFailureSequence {
+
+    /// The iterator that produces elements of the map sequence.
+    struct Iterator: AsyncIteratorProtocol {
+
+        typealias Element = Base.Element
+
+        private var base: Base.AsyncIterator
+
+        private let transform: @Sendable (Failure) -> MappedFailure
+
+        init(
+            base: Base.AsyncIterator,
+            transform: @Sendable @escaping (Failure) -> MappedFailure
+        ) {
+            self.base = base
+            self.transform = transform
+        }
+
+        mutating func next() async throws(MappedFailure) -> Element? {
+            do {
+                return try await base.next(isolation: nil)
+            } catch {
+                throw transform(error)
+            }
+        }
+
+        mutating func next(isolation actor: isolated (any Actor)?) async throws(MappedFailure) -> Element? {
+            do {
+                return try await base.next(isolation: actor)
+            } catch {
+                throw transform(error)
+            }
+        }
+    }
+}
+
+@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
+extension AsyncMapFailureSequence: Sendable where Base: Sendable, Base.Element: Sendable {}
+#endif
+```
+
+`AsyncMapErrorSequence` would have similar implementation except it uses `any Error` instead of the associated Failure type, and doesn't support typed throws if the compiler is less than 6.0.
+
+## Naming
+
+`mapError` follows to current method naming of the Combine [mapError](https://developer.apple.com/documentation/combine/publisher/mapError(_:)) method.
+
+Using `mapFailure` since `Failure` defines the type that can be thrown from an `AsyncSequence`.
diff --git a/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift b/Sources/AsyncAlgorithms/AsyncMapFailureSequence.swift
similarity index 62%
rename from Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
rename to Sources/AsyncAlgorithms/AsyncMapFailureSequence.swift
index 7245f7a1..19469899 100644
--- a/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
+++ b/Sources/AsyncAlgorithms/AsyncMapFailureSequence.swift
@@ -18,51 +18,52 @@ extension AsyncSequence {
     /// - Parameter transform: A closure that takes the failure as a parameter and returns a new error.
     /// - Returns: An asynchronous sequence that maps the error thrown into the one produced by the transform closure.
     ///
-    /// Use the ``mapError(_:)`` operator when you need to replace one error type with another.
+    /// Use the ``mapFailure(_:)`` operator when you need to replace one error type with another.
     @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-    public func mapError<ErrorType: Error>(_ transform: @Sendable @escaping (Self.Failure) -> ErrorType) -> AsyncMapErrorSequence<Self, ErrorType> {
-        .init(base: self, transform: transform)
+    public func mapFailure<MappedFailure: Error>(_ transform: @Sendable @escaping (Self.Failure) -> MappedFailure) -> some AsyncSequence<Self.Element, MappedFailure> {
+        AsyncMapFailureSequence(base: self, transform: transform)
     }
 #endif
 
-    /// Converts any failure into a new error.
+    /// Converts any error into a new error.
     ///
-    /// - Parameter transform: A closure that takes the failure as a parameter and returns a new error.
+    /// - Parameter transform: A closure that takes the error as a parameter and returns a new error.
     /// - Returns: An asynchronous sequence that maps the error thrown into the one produced by the transform closure.
     ///
-    /// Use the ``mapAnyError(_:)`` operator when you need to replace one error type with another.
-    @available(macOS, deprecated: 15.0, renamed: "mapError")
-    @available(iOS, deprecated: 18.0, renamed: "mapError")
-    @available(watchOS, deprecated: 11.0, renamed: "mapError")
-    @available(tvOS, deprecated: 18.0, renamed: "mapError")
-    @available(visionOS, deprecated: 2.0, renamed: "mapError")
-    public func mapAnyError<ErrorType: Error>(_ transform: @Sendable @escaping (any Error) -> ErrorType) -> AsyncMapAnyErrorSequence<Self, ErrorType> {
+    /// Use the ``mapError(_:)`` operator when you need to replace one error type with another.
+    @available(macOS, deprecated: 15.0, renamed: "mapFailure")
+    @available(iOS, deprecated: 18.0, renamed: "mapFailure")
+    @available(watchOS, deprecated: 11.0, renamed: "mapFailure")
+    @available(tvOS, deprecated: 18.0, renamed: "mapFailure")
+    @available(visionOS, deprecated: 2.0, renamed: "mapFailure")
+    public func mapError<MappedError: Error>(_ transform: @Sendable @escaping (any Error) -> MappedError) -> AsyncMapErrorSequence<Self, MappedError> {
         .init(base: self, transform: transform)
     }
 }
 
-// MARK: - AsyncMapErrorSequence
+// MARK: - AsyncMapFailureSequence
 
 #if compiler(>=6.0)
 /// An asynchronous sequence that converts any failure into a new error.
 @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-public struct AsyncMapErrorSequence<Base: AsyncSequence, ErrorType: Error>: AsyncSequence {
+fileprivate struct AsyncMapFailureSequence<Base: AsyncSequence, MappedFailure: Error>: AsyncSequence {
 
-    public typealias AsyncIterator = Iterator
-    public typealias Element = Base.Element
+    typealias AsyncIterator = Iterator
+    typealias Element = Base.Element
+    typealias Failure = Base.Failure
 
     private let base: Base
-    private let transform: @Sendable (Base.Failure) -> ErrorType
+    private let transform: @Sendable (Failure) -> MappedFailure
 
     init(
         base: Base,
-        transform: @Sendable @escaping (Base.Failure) -> ErrorType
+        transform: @Sendable @escaping (Failure) -> MappedFailure
     ) {
         self.base = base
         self.transform = transform
     }
 
-    public func makeAsyncIterator() -> Iterator {
+    func makeAsyncIterator() -> Iterator {
         Iterator(
             base: base.makeAsyncIterator(),
             transform: transform
@@ -71,26 +72,26 @@ public struct AsyncMapErrorSequence<Base: AsyncSequence, ErrorType: Error>: Asyn
 }
 
 @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-extension AsyncMapErrorSequence {
+extension AsyncMapFailureSequence {
 
     /// The iterator that produces elements of the map sequence.
-    public struct Iterator: AsyncIteratorProtocol {
+    fileprivate struct Iterator: AsyncIteratorProtocol {
 
-        public typealias Element = Base.Element
+        typealias Element = Base.Element
 
         private var base: Base.AsyncIterator
 
-        private let transform: @Sendable (Base.Failure) -> ErrorType
+        private let transform: @Sendable (Failure) -> MappedFailure
 
         init(
             base: Base.AsyncIterator,
-            transform: @Sendable @escaping (Base.Failure) -> ErrorType
+            transform: @Sendable @escaping (Failure) -> MappedFailure
         ) {
             self.base = base
             self.transform = transform
         }
 
-        public mutating func next() async throws(ErrorType) -> Element? {
+        mutating func next() async throws(MappedFailure) -> Element? {
             do {
                 return try await base.next(isolation: nil)
             } catch {
@@ -98,7 +99,7 @@ extension AsyncMapErrorSequence {
             }
         }
 
-        public mutating func next(isolation actor: isolated (any Actor)?) async throws(ErrorType) -> Element? {
+        mutating func next(isolation actor: isolated (any Actor)?) async throws(MappedFailure) -> Element? {
             do {
                 return try await base.next(isolation: actor)
             } catch {
@@ -109,23 +110,23 @@ extension AsyncMapErrorSequence {
 }
 
 @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-extension AsyncMapErrorSequence: Sendable where Base: Sendable, Base.Element: Sendable {}
+extension AsyncMapFailureSequence: Sendable where Base: Sendable, Base.Element: Sendable {}
 #endif
 
-// MARK: - AsyncMapAnyErrorSequence
+// MARK: - AsyncMapErrorSequence
 
 /// An asynchronous sequence that converts any failure into a new error.
-public struct AsyncMapAnyErrorSequence<Base: AsyncSequence, ErrorType: Error>: AsyncSequence {
+public struct AsyncMapErrorSequence<Base: AsyncSequence, MappedError: Error>: AsyncSequence {
 
     public typealias AsyncIterator = Iterator
     public typealias Element = Base.Element
 
     private let base: Base
-    private let transform: @Sendable (any Error) -> ErrorType
+    private let transform: @Sendable (any Error) -> MappedError
 
     init(
         base: Base,
-        transform: @Sendable @escaping (any Error) -> ErrorType
+        transform: @Sendable @escaping (any Error) -> MappedError
     ) {
         self.base = base
         self.transform = transform
@@ -139,7 +140,7 @@ public struct AsyncMapAnyErrorSequence<Base: AsyncSequence, ErrorType: Error>: A
     }
 }
 
-extension AsyncMapAnyErrorSequence {
+extension AsyncMapErrorSequence {
 
     /// The iterator that produces elements of the map sequence.
     public struct Iterator: AsyncIteratorProtocol {
@@ -148,18 +149,18 @@ extension AsyncMapAnyErrorSequence {
 
         private var base: Base.AsyncIterator
 
-        private let transform: @Sendable (any Error) -> ErrorType
+        private let transform: @Sendable (any Error) -> MappedError
 
         init(
             base: Base.AsyncIterator,
-            transform: @Sendable @escaping (any Error) -> ErrorType
+            transform: @Sendable @escaping (any Error) -> MappedError
         ) {
             self.base = base
             self.transform = transform
         }
 
 #if compiler(>=6.0)
-        public mutating func next() async throws(ErrorType) -> Element? {
+        public mutating func next() async throws(MappedError) -> Element? {
             do {
                 return try await base.next()
             } catch {
@@ -168,7 +169,7 @@ extension AsyncMapAnyErrorSequence {
         }
 
         @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-        public mutating func next(isolation actor: isolated (any Actor)?) async throws(ErrorType) -> Element? {
+        public mutating func next(isolation actor: isolated (any Actor)?) async throws(MappedError) -> Element? {
             do {
                 return try await base.next(isolation: actor)
             } catch {
@@ -187,4 +188,4 @@ extension AsyncMapAnyErrorSequence {
     }
 }
 
-extension AsyncMapAnyErrorSequence: Sendable where Base: Sendable, Base.Element: Sendable {}
+extension AsyncMapErrorSequence: Sendable where Base: Sendable, Base.Element: Sendable {}
diff --git a/Tests/AsyncAlgorithmsTests/TestMapError.swift b/Tests/AsyncAlgorithmsTests/TestMapError.swift
index 655717ff..d3d7ce10 100644
--- a/Tests/AsyncAlgorithmsTests/TestMapError.swift
+++ b/Tests/AsyncAlgorithmsTests/TestMapError.swift
@@ -3,11 +3,11 @@ import XCTest
 
 final class TestMapError: XCTestCase {
 
-    func test_mapAnyError() async throws {
+    func test_mapError() async throws {
         let array = [URLError(.badURL)]
         let sequence = array.async
             .map { throw $0 }
-            .mapAnyError { _ in
+            .mapError { _ in
                 MyAwesomeError()
             }
 
@@ -28,11 +28,11 @@ final class TestMapError: XCTestCase {
     }
 
     @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-    func test_mapError() async throws {
+    func test_mapFailure() async throws {
         let array = [URLError(.badURL)]
         let sequence = array.async
             .map { throw $0 }
-            .mapError { _ in
+            .mapFailure { _ in
                 MyAwesomeError()
             }
 
@@ -45,10 +45,10 @@ final class TestMapError: XCTestCase {
         }
     }
 
-    func test_mapAnyError_nonThrowing() async throws {
+    func test_mapError_nonThrowing() async throws {
         let array = [1, 2, 3, 4, 5]
         let sequence = array.async
-            .mapAnyError { _ in
+            .mapError { _ in
                 MyAwesomeError()
             }
 
@@ -59,9 +59,9 @@ final class TestMapError: XCTestCase {
         XCTAssertEqual(array, actual)
     }
 
-    func test_mapAnyError_cancellation() async throws {
+    func test_mapError_cancellation() async throws {
         let source = Indefinite(value: "test").async
-        let sequence = source.mapAnyError { _ in MyAwesomeError() }
+        let sequence = source.mapError { _ in MyAwesomeError() }
 
         let finished = expectation(description: "finished")
         let iterated = expectation(description: "iterated")
@@ -87,10 +87,10 @@ final class TestMapError: XCTestCase {
         await fulfillment(of: [finished], timeout: 1.0)
     }
 
-    func test_mapAnyError_empty() async throws {
+    func test_mapError_empty() async throws {
         let array: [Int] = []
         let sequence = array.async
-            .mapAnyError { _ in
+            .mapError { _ in
                 MyAwesomeError()
             }
 

From 28938ea8562d337007837f9746d7f0f2b692259d Mon Sep 17 00:00:00 2001
From: Clive <clive819@gmail.com>
Date: Fri, 18 Oct 2024 08:34:03 -0400
Subject: [PATCH 08/11] address comments

---
 Evolution/NNNN-map-failure.md                 |  68 +----------
 .../AsyncMapFailureSequence.swift             | 100 ++--------------
 Tests/AsyncAlgorithmsTests/TestMapError.swift | 111 ------------------
 .../AsyncAlgorithmsTests/TestMapFailure.swift | 105 +++++++++++++++++
 4 files changed, 116 insertions(+), 268 deletions(-)
 delete mode 100644 Tests/AsyncAlgorithmsTests/TestMapError.swift
 create mode 100644 Tests/AsyncAlgorithmsTests/TestMapFailure.swift

diff --git a/Evolution/NNNN-map-failure.md b/Evolution/NNNN-map-failure.md
index 95d06b5c..86c68ed8 100644
--- a/Evolution/NNNN-map-failure.md
+++ b/Evolution/NNNN-map-failure.md
@@ -21,73 +21,17 @@ extension AsyncSequence {
     public func mapFailure<MappedFailure: Error>(_ transform: @Sendable @escaping (Self.Failure) -> MappedFailure) -> some AsyncSequence<Self.Element, MappedFailure> {
         AsyncMapFailureSequence(base: self, transform: transform)
     }
-
 }
 ```
 
 ## Detailed design
 
-The actual implementation is quite simple actually - it's just simple do-catch block and invoking the transform closure inside the catch block - so we'll focus more on implementation decisions with regard to the compiler and OS versions difference.
+The function iterates through the elements of an `AsyncSequence` within a do-catch block. If an error is caught, it calls the `transform` closure to convert the error into a new type and then throws it.
 
 ```swift
-extension AsyncSequence {
-
-#if compiler(>=6.0)
-    /// Converts any failure into a new error.
-    ///
-    /// - Parameter transform: A closure that takes the failure as a parameter and returns a new error.
-    /// - Returns: An asynchronous sequence that maps the error thrown into the one produced by the transform closure.
-    ///
-    /// Use the ``mapFailure(_:)`` operator when you need to replace one error type with another.
-    @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-    public func mapFailure<MappedFailure: Error>(_ transform: @Sendable @escaping (Self.Failure) -> MappedFailure) -> some AsyncSequence<Self.Element, MappedFailure> {
-        AsyncMapFailureSequence(base: self, transform: transform)
-    }
-#endif
-
-    /// Converts any error into a new error.
-    ///
-    /// - Parameter transform: A closure that takes the error as a parameter and returns a new error.
-    /// - Returns: An asynchronous sequence that maps the error thrown into the one produced by the transform closure.
-    ///
-    /// Use the ``mapError(_:)`` operator when you need to replace one error type with another.
-    @available(macOS, deprecated: 15.0, renamed: "mapFailure")
-    @available(iOS, deprecated: 18.0, renamed: "mapFailure")
-    @available(watchOS, deprecated: 11.0, renamed: "mapFailure")
-    @available(tvOS, deprecated: 18.0, renamed: "mapFailure")
-    @available(visionOS, deprecated: 2.0, renamed: "mapFailure")
-    public func mapError<MappedError: Error>(_ transform: @Sendable @escaping (any Error) -> MappedError) -> AsyncMapErrorSequence<Self, MappedError> {
-        .init(base: self, transform: transform)
-    }
-}
-```
-
-The compiler check is needed to ensure the code can be built on older Xcode versions (15 and below). `AsyncSequence.Failure` is only available in new SDK that ships with Xcode 16 that has the 6.0 compiler, we'd get this error without the compiler check `'Failure' is not a member type of type 'Self'`.
-
-As to the naming `mapFailure` versus `mapError`, this is the trade off we have to make due to the lack of the ability to mark function as unavailable from certain OS version. The function signatures are the same, if the function names were the same, compiler will always choose the one with `any Error` instead of the one that has more specific error type.
-
-`mapError` function returns a concrete type instead of `some AsyncSequence<Self.Element, MappedError>` because `AsyncSequence.Failure` is only available in newer OS versions, we cannot specify it in old versions. And because using an opaque type would render typed throws feature ineffective by erasing the type, thereby preventing the compiler from ensuring that the returned sequence matches our intended new type. The benefits of using typed throws for this specific case outweigh the exposure of the internal types.
-
-```swift
-#if compiler(>=6.0)
-/// An asynchronous sequence that converts any failure into a new error.
-@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
 struct AsyncMapFailureSequence<Base: AsyncSequence, MappedFailure: Error>: AsyncSequence {
 
-    typealias AsyncIterator = Iterator
-    typealias Element = Base.Element
-    typealias Failure = Base.Failure
-
-    private let base: Base
-    private let transform: @Sendable (Failure) -> MappedFailure
-
-    init(
-        base: Base,
-        transform: @Sendable @escaping (Failure) -> MappedFailure
-    ) {
-        self.base = base
-        self.transform = transform
-    }
+    ...
 
     func makeAsyncIterator() -> Iterator {
         Iterator(
@@ -97,10 +41,8 @@ struct AsyncMapFailureSequence<Base: AsyncSequence, MappedFailure: Error>: Async
     }
 }
 
-@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
 extension AsyncMapFailureSequence {
 
-    /// The iterator that produces elements of the map sequence.
     struct Iterator: AsyncIteratorProtocol {
 
         typealias Element = Base.Element
@@ -135,15 +77,9 @@ extension AsyncMapFailureSequence {
     }
 }
 
-@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
 extension AsyncMapFailureSequence: Sendable where Base: Sendable, Base.Element: Sendable {}
-#endif
 ```
 
-`AsyncMapErrorSequence` would have similar implementation except it uses `any Error` instead of the associated Failure type, and doesn't support typed throws if the compiler is less than 6.0.
-
 ## Naming
 
-`mapError` follows to current method naming of the Combine [mapError](https://developer.apple.com/documentation/combine/publisher/mapError(_:)) method.
-
 Using `mapFailure` since `Failure` defines the type that can be thrown from an `AsyncSequence`.
diff --git a/Sources/AsyncAlgorithms/AsyncMapFailureSequence.swift b/Sources/AsyncAlgorithms/AsyncMapFailureSequence.swift
index 19469899..e48cea53 100644
--- a/Sources/AsyncAlgorithms/AsyncMapFailureSequence.swift
+++ b/Sources/AsyncAlgorithms/AsyncMapFailureSequence.swift
@@ -10,9 +10,9 @@
 //
 //===----------------------------------------------------------------------===//
 
+#if compiler(>=6.0)
 extension AsyncSequence {
 
-#if compiler(>=6.0)
     /// Converts any failure into a new error.
     ///
     /// - Parameter transform: A closure that takes the failure as a parameter and returns a new error.
@@ -23,27 +23,19 @@ extension AsyncSequence {
     public func mapFailure<MappedFailure: Error>(_ transform: @Sendable @escaping (Self.Failure) -> MappedFailure) -> some AsyncSequence<Self.Element, MappedFailure> {
         AsyncMapFailureSequence(base: self, transform: transform)
     }
-#endif
 
-    /// Converts any error into a new error.
+    /// Converts any failure into a new error.
     ///
-    /// - Parameter transform: A closure that takes the error as a parameter and returns a new error.
+    /// - Parameter transform: A closure that takes the failure as a parameter and returns a new error.
     /// - Returns: An asynchronous sequence that maps the error thrown into the one produced by the transform closure.
     ///
-    /// Use the ``mapError(_:)`` operator when you need to replace one error type with another.
-    @available(macOS, deprecated: 15.0, renamed: "mapFailure")
-    @available(iOS, deprecated: 18.0, renamed: "mapFailure")
-    @available(watchOS, deprecated: 11.0, renamed: "mapFailure")
-    @available(tvOS, deprecated: 18.0, renamed: "mapFailure")
-    @available(visionOS, deprecated: 2.0, renamed: "mapFailure")
-    public func mapError<MappedError: Error>(_ transform: @Sendable @escaping (any Error) -> MappedError) -> AsyncMapErrorSequence<Self, MappedError> {
-        .init(base: self, transform: transform)
+    /// Use the ``mapFailure(_:)`` operator when you need to replace one error type with another.
+    @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
+    public func mapFailure<MappedFailure: Error>(_ transform: @Sendable @escaping (Self.Failure) -> MappedFailure) -> (some AsyncSequence<Self.Element, MappedFailure> & Sendable) where Self: Sendable, Self.Element: Sendable {
+        AsyncMapFailureSequence(base: self, transform: transform)
     }
 }
 
-// MARK: - AsyncMapFailureSequence
-
-#if compiler(>=6.0)
 /// An asynchronous sequence that converts any failure into a new error.
 @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
 fileprivate struct AsyncMapFailureSequence<Base: AsyncSequence, MappedFailure: Error>: AsyncSequence {
@@ -111,81 +103,7 @@ extension AsyncMapFailureSequence {
 
 @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
 extension AsyncMapFailureSequence: Sendable where Base: Sendable, Base.Element: Sendable {}
-#endif
-
-// MARK: - AsyncMapErrorSequence
-
-/// An asynchronous sequence that converts any failure into a new error.
-public struct AsyncMapErrorSequence<Base: AsyncSequence, MappedError: Error>: AsyncSequence {
-
-    public typealias AsyncIterator = Iterator
-    public typealias Element = Base.Element
-
-    private let base: Base
-    private let transform: @Sendable (any Error) -> MappedError
-
-    init(
-        base: Base,
-        transform: @Sendable @escaping (any Error) -> MappedError
-    ) {
-        self.base = base
-        self.transform = transform
-    }
-
-    public func makeAsyncIterator() -> Iterator {
-        Iterator(
-            base: base.makeAsyncIterator(),
-            transform: transform
-        )
-    }
-}
-
-extension AsyncMapErrorSequence {
-
-    /// The iterator that produces elements of the map sequence.
-    public struct Iterator: AsyncIteratorProtocol {
-
-        public typealias Element = Base.Element
-
-        private var base: Base.AsyncIterator
-
-        private let transform: @Sendable (any Error) -> MappedError
 
-        init(
-            base: Base.AsyncIterator,
-            transform: @Sendable @escaping (any Error) -> MappedError
-        ) {
-            self.base = base
-            self.transform = transform
-        }
-
-#if compiler(>=6.0)
-        public mutating func next() async throws(MappedError) -> Element? {
-            do {
-                return try await base.next()
-            } catch {
-                throw transform(error)
-            }
-        }
-
-        @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-        public mutating func next(isolation actor: isolated (any Actor)?) async throws(MappedError) -> Element? {
-            do {
-                return try await base.next(isolation: actor)
-            } catch {
-                throw transform(error)
-            }
-        }
-#else
-        public mutating func next() async throws -> Element? {
-            do {
-                return try await base.next()
-            } catch {
-                throw transform(error)
-            }
-        }
+@available(*, unavailable)
+extension AsyncMapFailureSequence.Iterator: Sendable {}
 #endif
-    }
-}
-
-extension AsyncMapErrorSequence: Sendable where Base: Sendable, Base.Element: Sendable {}
diff --git a/Tests/AsyncAlgorithmsTests/TestMapError.swift b/Tests/AsyncAlgorithmsTests/TestMapError.swift
deleted file mode 100644
index d3d7ce10..00000000
--- a/Tests/AsyncAlgorithmsTests/TestMapError.swift
+++ /dev/null
@@ -1,111 +0,0 @@
-import AsyncAlgorithms
-import XCTest
-
-final class TestMapError: XCTestCase {
-
-    func test_mapError() async throws {
-        let array = [URLError(.badURL)]
-        let sequence = array.async
-            .map { throw $0 }
-            .mapError { _ in
-                MyAwesomeError()
-            }
-
-        do {
-            for try await _ in sequence {
-                XCTFail("sequence should throw")
-            }
-        } catch {
-#if compiler(>=6.0)
-            // NO-OP
-            // The compiler already checks that for us since we're using typed throws.
-            // Writing that assert will just give compiler warning.
-            error.hoorayTypedThrows()
-#else
-            XCTAssert(error is MyAwesomeError)
-#endif
-        }
-    }
-
-    @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-    func test_mapFailure() async throws {
-        let array = [URLError(.badURL)]
-        let sequence = array.async
-            .map { throw $0 }
-            .mapFailure { _ in
-                MyAwesomeError()
-            }
-
-        do {
-            for try await _ in sequence {
-                XCTFail("sequence should throw")
-            }
-        } catch {
-            error.hoorayTypedThrows()
-        }
-    }
-
-    func test_mapError_nonThrowing() async throws {
-        let array = [1, 2, 3, 4, 5]
-        let sequence = array.async
-            .mapError { _ in
-                MyAwesomeError()
-            }
-
-        var actual: [Int] = []
-        for try await value in sequence {
-            actual.append(value)
-        }
-        XCTAssertEqual(array, actual)
-    }
-
-    func test_mapError_cancellation() async throws {
-        let source = Indefinite(value: "test").async
-        let sequence = source.mapError { _ in MyAwesomeError() }
-
-        let finished = expectation(description: "finished")
-        let iterated = expectation(description: "iterated")
-
-        let task = Task {
-            var firstIteration = false
-            for try await el in sequence {
-                XCTAssertEqual(el, "test")
-
-                if !firstIteration {
-                    firstIteration = true
-                    iterated.fulfill()
-                }
-            }
-            finished.fulfill()
-        }
-
-        // ensure the other task actually starts
-        await fulfillment(of: [iterated], timeout: 1.0)
-        // cancellation should ensure the loop finishes
-        // without regards to the remaining underlying sequence
-        task.cancel()
-        await fulfillment(of: [finished], timeout: 1.0)
-    }
-
-    func test_mapError_empty() async throws {
-        let array: [Int] = []
-        let sequence = array.async
-            .mapError { _ in
-                MyAwesomeError()
-            }
-
-        var actual: [Int] = []
-        for try await value in sequence {
-            actual.append(value)
-        }
-        XCTAssert(actual.isEmpty)
-    }
-}
-
-private extension TestMapError {
-
-    struct MyAwesomeError: Error {
-
-        func hoorayTypedThrows() {}
-    }
-}
diff --git a/Tests/AsyncAlgorithmsTests/TestMapFailure.swift b/Tests/AsyncAlgorithmsTests/TestMapFailure.swift
new file mode 100644
index 00000000..3e428545
--- /dev/null
+++ b/Tests/AsyncAlgorithmsTests/TestMapFailure.swift
@@ -0,0 +1,105 @@
+import AsyncAlgorithms
+import XCTest
+
+#if compiler(>=6.0)
+@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
+final class TestMapFailure: XCTestCase {
+
+    func test_mapFailure() async throws {
+        let array: [Any] = [1, 2, 3, MyAwesomeError.originalError, 4, 5, 6]
+        let sequence = array.async
+            .map {
+                if let error = $0 as? Error {
+                    throw error
+                } else {
+                    $0 as! Int
+                }
+            }
+            .mapFailure { _ in
+                MyAwesomeError.mappedError
+            }
+
+        var results: [Int] = []
+
+        do {
+            for try await number in sequence {
+                results.append(number)
+            }
+            XCTFail("sequence should throw")
+        } catch {
+            XCTAssertEqual(error, .mappedError)
+        }
+
+        XCTAssertEqual(results, [1, 2, 3])
+    }
+
+    func test_mapFailure_cancellation() async throws {
+        let value = "test"
+        let source = Indefinite(value: value).async
+        let sequence = source
+            .map {
+                if $0 == "just to trick compiler that this may throw" {
+                    throw MyAwesomeError.originalError
+                } else {
+                    $0
+                }
+            }
+            .mapFailure { _ in
+                MyAwesomeError.mappedError
+            }
+
+        let finished = expectation(description: "finished")
+        let iterated = expectation(description: "iterated")
+
+        let task = Task {
+            var firstIteration = false
+            for try await el in sequence {
+                XCTAssertEqual(el, value)
+
+                if !firstIteration {
+                    firstIteration = true
+                    iterated.fulfill()
+                }
+            }
+            finished.fulfill()
+        }
+
+        // ensure the other task actually starts
+        await fulfillment(of: [iterated], timeout: 1.0)
+        // cancellation should ensure the loop finishes
+        // without regards to the remaining underlying sequence
+        task.cancel()
+        await fulfillment(of: [finished], timeout: 1.0)
+    }
+
+    func test_mapFailure_empty() async throws {
+        let array: [String] = []
+        let sequence = array.async
+            .map {
+                if $0 == "just to trick compiler that this may throw" {
+                    throw MyAwesomeError.originalError
+                } else {
+                    $0
+                }
+            }
+            .mapFailure { _ in
+                MyAwesomeError.mappedError
+            }
+
+        var results: [String] = []
+        for try await value in sequence {
+            results.append(value)
+        }
+        XCTAssert(results.isEmpty)
+    }
+}
+
+@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
+private extension TestMapFailure {
+
+    enum MyAwesomeError: Error {
+        case originalError
+        case mappedError
+    }
+}
+#endif

From cf62ea1047ab16dec00de15c41c3ca49e4b057b7 Mon Sep 17 00:00:00 2001
From: Clive <clive819@gmail.com>
Date: Fri, 18 Oct 2024 16:18:03 -0400
Subject: [PATCH 09/11] address comment

---
 Sources/AsyncAlgorithms/AsyncMapFailureSequence.swift | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/Sources/AsyncAlgorithms/AsyncMapFailureSequence.swift b/Sources/AsyncAlgorithms/AsyncMapFailureSequence.swift
index e48cea53..76f6df60 100644
--- a/Sources/AsyncAlgorithms/AsyncMapFailureSequence.swift
+++ b/Sources/AsyncAlgorithms/AsyncMapFailureSequence.swift
@@ -84,11 +84,7 @@ extension AsyncMapFailureSequence {
         }
 
         mutating func next() async throws(MappedFailure) -> Element? {
-            do {
-                return try await base.next(isolation: nil)
-            } catch {
-                throw transform(error)
-            }
+            try await self.next(isolation: nil)
         }
 
         mutating func next(isolation actor: isolated (any Actor)?) async throws(MappedFailure) -> Element? {

From e3a0e1b6699091565092eb15c52e2d299788ea27 Mon Sep 17 00:00:00 2001
From: Clive <clive819@gmail.com>
Date: Fri, 1 Nov 2024 22:10:22 -0400
Subject: [PATCH 10/11] rename

---
 ...{NNNN-map-failure.md => NNNN-map-error.md} | 18 ++++++++---------
 ...ence.swift => AsyncMapErrorSequence.swift} | 20 +++++++++----------
 ...estMapFailure.swift => TestMapError.swift} | 16 +++++++--------
 3 files changed, 27 insertions(+), 27 deletions(-)
 rename Evolution/{NNNN-map-failure.md => NNNN-map-error.md} (68%)
 rename Sources/AsyncAlgorithms/{AsyncMapFailureSequence.swift => AsyncMapErrorSequence.swift} (75%)
 rename Tests/AsyncAlgorithmsTests/{TestMapFailure.swift => TestMapError.swift} (89%)

diff --git a/Evolution/NNNN-map-failure.md b/Evolution/NNNN-map-error.md
similarity index 68%
rename from Evolution/NNNN-map-failure.md
rename to Evolution/NNNN-map-error.md
index 86c68ed8..2d4c344a 100644
--- a/Evolution/NNNN-map-failure.md
+++ b/Evolution/NNNN-map-error.md
@@ -1,6 +1,6 @@
-# Map Failure
+# Map Error
 
-* Proposal: [SAA-NNNN](NNNN-map-failure.md)
+* Proposal: [SAA-NNNN](NNNN-map-error.md)
 * Authors: [Clive Liu](https://github.com/clive819)
 * Review Manager: TBD
 * Status: **Awaiting review**
@@ -13,13 +13,13 @@
 
 ## Introduction
 
-The `mapFailure` function empowers developers to elegantly transform errors within asynchronous sequences, enhancing code readability and maintainability.
+The `mapError` function empowers developers to elegantly transform errors within asynchronous sequences, enhancing code readability and maintainability.
 
 ```swift
 extension AsyncSequence {
 
-    public func mapFailure<MappedFailure: Error>(_ transform: @Sendable @escaping (Self.Failure) -> MappedFailure) -> some AsyncSequence<Self.Element, MappedFailure> {
-        AsyncMapFailureSequence(base: self, transform: transform)
+    public func mapError<MappedFailure: Error>(_ transform: @Sendable @escaping (Self.Failure) -> MappedFailure) -> some AsyncSequence<Self.Element, MappedFailure> {
+        AsyncMapErrorSequence(base: self, transform: transform)
     }
 }
 ```
@@ -29,7 +29,7 @@ extension AsyncSequence {
 The function iterates through the elements of an `AsyncSequence` within a do-catch block. If an error is caught, it calls the `transform` closure to convert the error into a new type and then throws it.
 
 ```swift
-struct AsyncMapFailureSequence<Base: AsyncSequence, MappedFailure: Error>: AsyncSequence {
+struct AsyncMapErrorSequence<Base: AsyncSequence, MappedFailure: Error>: AsyncSequence {
 
     ...
 
@@ -41,7 +41,7 @@ struct AsyncMapFailureSequence<Base: AsyncSequence, MappedFailure: Error>: Async
     }
 }
 
-extension AsyncMapFailureSequence {
+extension AsyncMapErrorSequence {
 
     struct Iterator: AsyncIteratorProtocol {
 
@@ -77,9 +77,9 @@ extension AsyncMapFailureSequence {
     }
 }
 
-extension AsyncMapFailureSequence: Sendable where Base: Sendable, Base.Element: Sendable {}
+extension AsyncMapErrorSequence: Sendable where Base: Sendable, Base.Element: Sendable {}
 ```
 
 ## Naming
 
-Using `mapFailure` since `Failure` defines the type that can be thrown from an `AsyncSequence`.
+The naming follows to current method naming of the Combine [mapError](https://developer.apple.com/documentation/combine/publisher/maperror(_:)) method.
diff --git a/Sources/AsyncAlgorithms/AsyncMapFailureSequence.swift b/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
similarity index 75%
rename from Sources/AsyncAlgorithms/AsyncMapFailureSequence.swift
rename to Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
index 76f6df60..eb7e12f5 100644
--- a/Sources/AsyncAlgorithms/AsyncMapFailureSequence.swift
+++ b/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
@@ -18,10 +18,10 @@ extension AsyncSequence {
     /// - Parameter transform: A closure that takes the failure as a parameter and returns a new error.
     /// - Returns: An asynchronous sequence that maps the error thrown into the one produced by the transform closure.
     ///
-    /// Use the ``mapFailure(_:)`` operator when you need to replace one error type with another.
+    /// Use the ``mapError(_:)`` operator when you need to replace one error type with another.
     @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-    public func mapFailure<MappedFailure: Error>(_ transform: @Sendable @escaping (Self.Failure) -> MappedFailure) -> some AsyncSequence<Self.Element, MappedFailure> {
-        AsyncMapFailureSequence(base: self, transform: transform)
+    public func mapError<MappedFailure: Error>(_ transform: @Sendable @escaping (Self.Failure) -> MappedFailure) -> some AsyncSequence<Self.Element, MappedFailure> {
+        AsyncMapErrorSequence(base: self, transform: transform)
     }
 
     /// Converts any failure into a new error.
@@ -29,16 +29,16 @@ extension AsyncSequence {
     /// - Parameter transform: A closure that takes the failure as a parameter and returns a new error.
     /// - Returns: An asynchronous sequence that maps the error thrown into the one produced by the transform closure.
     ///
-    /// Use the ``mapFailure(_:)`` operator when you need to replace one error type with another.
+    /// Use the ``mapError(_:)`` operator when you need to replace one error type with another.
     @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-    public func mapFailure<MappedFailure: Error>(_ transform: @Sendable @escaping (Self.Failure) -> MappedFailure) -> (some AsyncSequence<Self.Element, MappedFailure> & Sendable) where Self: Sendable, Self.Element: Sendable {
-        AsyncMapFailureSequence(base: self, transform: transform)
+    public func mapError<MappedFailure: Error>(_ transform: @Sendable @escaping (Self.Failure) -> MappedFailure) -> (some AsyncSequence<Self.Element, MappedFailure> & Sendable) where Self: Sendable, Self.Element: Sendable {
+        AsyncMapErrorSequence(base: self, transform: transform)
     }
 }
 
 /// An asynchronous sequence that converts any failure into a new error.
 @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-fileprivate struct AsyncMapFailureSequence<Base: AsyncSequence, MappedFailure: Error>: AsyncSequence {
+fileprivate struct AsyncMapErrorSequence<Base: AsyncSequence, MappedFailure: Error>: AsyncSequence {
 
     typealias AsyncIterator = Iterator
     typealias Element = Base.Element
@@ -64,7 +64,7 @@ fileprivate struct AsyncMapFailureSequence<Base: AsyncSequence, MappedFailure: E
 }
 
 @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-extension AsyncMapFailureSequence {
+extension AsyncMapErrorSequence {
 
     /// The iterator that produces elements of the map sequence.
     fileprivate struct Iterator: AsyncIteratorProtocol {
@@ -98,8 +98,8 @@ extension AsyncMapFailureSequence {
 }
 
 @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-extension AsyncMapFailureSequence: Sendable where Base: Sendable, Base.Element: Sendable {}
+extension AsyncMapErrorSequence: Sendable where Base: Sendable, Base.Element: Sendable {}
 
 @available(*, unavailable)
-extension AsyncMapFailureSequence.Iterator: Sendable {}
+extension AsyncMapErrorSequence.Iterator: Sendable {}
 #endif
diff --git a/Tests/AsyncAlgorithmsTests/TestMapFailure.swift b/Tests/AsyncAlgorithmsTests/TestMapError.swift
similarity index 89%
rename from Tests/AsyncAlgorithmsTests/TestMapFailure.swift
rename to Tests/AsyncAlgorithmsTests/TestMapError.swift
index 3e428545..afe90e13 100644
--- a/Tests/AsyncAlgorithmsTests/TestMapFailure.swift
+++ b/Tests/AsyncAlgorithmsTests/TestMapError.swift
@@ -3,9 +3,9 @@ import XCTest
 
 #if compiler(>=6.0)
 @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-final class TestMapFailure: XCTestCase {
+final class TestMapError: XCTestCase {
 
-    func test_mapFailure() async throws {
+    func test_mapError() async throws {
         let array: [Any] = [1, 2, 3, MyAwesomeError.originalError, 4, 5, 6]
         let sequence = array.async
             .map {
@@ -15,7 +15,7 @@ final class TestMapFailure: XCTestCase {
                     $0 as! Int
                 }
             }
-            .mapFailure { _ in
+            .mapError { _ in
                 MyAwesomeError.mappedError
             }
 
@@ -33,7 +33,7 @@ final class TestMapFailure: XCTestCase {
         XCTAssertEqual(results, [1, 2, 3])
     }
 
-    func test_mapFailure_cancellation() async throws {
+    func test_mapError_cancellation() async throws {
         let value = "test"
         let source = Indefinite(value: value).async
         let sequence = source
@@ -44,7 +44,7 @@ final class TestMapFailure: XCTestCase {
                     $0
                 }
             }
-            .mapFailure { _ in
+            .mapError { _ in
                 MyAwesomeError.mappedError
             }
 
@@ -72,7 +72,7 @@ final class TestMapFailure: XCTestCase {
         await fulfillment(of: [finished], timeout: 1.0)
     }
 
-    func test_mapFailure_empty() async throws {
+    func test_mapError_empty() async throws {
         let array: [String] = []
         let sequence = array.async
             .map {
@@ -82,7 +82,7 @@ final class TestMapFailure: XCTestCase {
                     $0
                 }
             }
-            .mapFailure { _ in
+            .mapError { _ in
                 MyAwesomeError.mappedError
             }
 
@@ -95,7 +95,7 @@ final class TestMapFailure: XCTestCase {
 }
 
 @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-private extension TestMapFailure {
+private extension TestMapError {
 
     enum MyAwesomeError: Error {
         case originalError

From 8cb9ea82b32b22e3b2af424c40fdf877d4a8d038 Mon Sep 17 00:00:00 2001
From: Clive <clive819@gmail.com>
Date: Fri, 1 Nov 2024 22:12:31 -0400
Subject: [PATCH 11/11] clean up

---
 .../AsyncMapErrorSequence.swift                | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift b/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
index eb7e12f5..75008f41 100644
--- a/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
+++ b/Sources/AsyncAlgorithms/AsyncMapErrorSequence.swift
@@ -20,7 +20,7 @@ extension AsyncSequence {
     ///
     /// Use the ``mapError(_:)`` operator when you need to replace one error type with another.
     @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-    public func mapError<MappedFailure: Error>(_ transform: @Sendable @escaping (Self.Failure) -> MappedFailure) -> some AsyncSequence<Self.Element, MappedFailure> {
+    public func mapError<MappedError: Error>(_ transform: @Sendable @escaping (Self.Failure) -> MappedError) -> some AsyncSequence<Self.Element, MappedError> {
         AsyncMapErrorSequence(base: self, transform: transform)
     }
 
@@ -31,25 +31,25 @@ extension AsyncSequence {
     ///
     /// Use the ``mapError(_:)`` operator when you need to replace one error type with another.
     @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-    public func mapError<MappedFailure: Error>(_ transform: @Sendable @escaping (Self.Failure) -> MappedFailure) -> (some AsyncSequence<Self.Element, MappedFailure> & Sendable) where Self: Sendable, Self.Element: Sendable {
+    public func mapError<MappedError: Error>(_ transform: @Sendable @escaping (Self.Failure) -> MappedError) -> (some AsyncSequence<Self.Element, MappedError> & Sendable) where Self: Sendable, Self.Element: Sendable {
         AsyncMapErrorSequence(base: self, transform: transform)
     }
 }
 
 /// An asynchronous sequence that converts any failure into a new error.
 @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-fileprivate struct AsyncMapErrorSequence<Base: AsyncSequence, MappedFailure: Error>: AsyncSequence {
+fileprivate struct AsyncMapErrorSequence<Base: AsyncSequence, MappedError: Error>: AsyncSequence {
 
     typealias AsyncIterator = Iterator
     typealias Element = Base.Element
     typealias Failure = Base.Failure
 
     private let base: Base
-    private let transform: @Sendable (Failure) -> MappedFailure
+    private let transform: @Sendable (Failure) -> MappedError
 
     init(
         base: Base,
-        transform: @Sendable @escaping (Failure) -> MappedFailure
+        transform: @Sendable @escaping (Failure) -> MappedError
     ) {
         self.base = base
         self.transform = transform
@@ -73,21 +73,21 @@ extension AsyncMapErrorSequence {
 
         private var base: Base.AsyncIterator
 
-        private let transform: @Sendable (Failure) -> MappedFailure
+        private let transform: @Sendable (Failure) -> MappedError
 
         init(
             base: Base.AsyncIterator,
-            transform: @Sendable @escaping (Failure) -> MappedFailure
+            transform: @Sendable @escaping (Failure) -> MappedError
         ) {
             self.base = base
             self.transform = transform
         }
 
-        mutating func next() async throws(MappedFailure) -> Element? {
+        mutating func next() async throws(MappedError) -> Element? {
             try await self.next(isolation: nil)
         }
 
-        mutating func next(isolation actor: isolated (any Actor)?) async throws(MappedFailure) -> Element? {
+        mutating func next(isolation actor: isolated (any Actor)?) async throws(MappedError) -> Element? {
             do {
                 return try await base.next(isolation: actor)
             } catch {