+
Skip to content
This repository was archived by the owner on Jun 27, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 10 additions & 48 deletions Sources/Async/Future+Map.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,7 @@ extension Future {
///
/// See `flatMap(to:_:)` for mapping `Future` results to other `Future` types.
public func map<T>(to type: T.Type = T.self, _ callback: @escaping (Expectation) throws -> T) -> Future<T> {
let promise = eventLoop.newPromise(T.self)

self.do { expectation in
do {
let mapped = try callback(expectation)
promise.succeed(result: mapped)
} catch {
promise.fail(error: error)
}
}.catch { error in
promise.fail(error: error)
}

return promise.futureResult
return self.thenThrowing(callback)
}

/// Maps a `Future` to a `Future` of a different type.
Expand All @@ -43,20 +30,13 @@ extension Future {
///
/// See `map(to:_:)` for mapping `Future` results to non-`Future` types.
public func flatMap<T>(to type: T.Type = T.self, _ callback: @escaping (Expectation) throws -> Future<T>) -> Future<T> {
let promise = eventLoop.newPromise(T.self)

self.do { expectation in
return self.then { input in
do {
let mapped = try callback(expectation)
mapped.cascade(promise: promise)
return try callback(input)
} catch {
promise.fail(error: error)
return self.eventLoop.newFailedFuture(error: error)
}
}.catch { error in
promise.fail(error: error)
}

return promise.futureResult
}

/// Calls the supplied closure if the chained Future resolves to an Error.
Expand All @@ -66,19 +46,7 @@ extension Future {
///
/// The callback expects a non-Future return (if not throwing instead). See `catchFlatMap` for a Future return.
public func catchMap(_ callback: @escaping (Error) throws -> (Expectation)) -> Future<Expectation> {
let promise = eventLoop.newPromise(T.self)
addAwaiter { result in
switch result {
case .error(let error):
do {
try promise.succeed(result: callback(error))
} catch {
promise.fail(error: error)
}
case .success(let e): promise.succeed(result: e)
}
}
return promise.futureResult
return self.thenIfErrorThrowing(callback)
}


Expand All @@ -100,18 +68,12 @@ extension Future {
/// }
///
public func catchFlatMap(_ callback: @escaping (Error) throws -> (Future<Expectation>)) -> Future<Expectation> {
let promise = eventLoop.newPromise(T.self)
addAwaiter { result in
switch result {
case .error(let error):
do {
try callback(error).cascade(promise: promise)
} catch {
promise.fail(error: error)
}
case .success(let e): promise.succeed(result: e)
return self.thenIfError { inputError in
do {
return try callback(inputError)
} catch {
return self.eventLoop.newFailedFuture(error: error)
}
}
return promise.futureResult
}
}
30 changes: 29 additions & 1 deletion Tests/AsyncTests/AsyncTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,32 @@ final class AsyncTests: XCTestCase {
let arr: [Future<String>] = []
try XCTAssertEqual(arr.flatten(on: loop).wait().count, 0)
}

func doRecursive(n: Int, eventLoop: EventLoop) -> EventLoopFuture<Void> {
guard n != 0 else {
return eventLoop.newSucceededFuture(result: ())
}
return eventLoop.submit { }
.flatMap {
self.doRecursive(n: n - 1, eventLoop: eventLoop)
}
}

func testFlatMapDoesNotCauseStackOverflowWhenFinishing() throws {
let loopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
try doRecursive(n: 10_000, eventLoop: loopGroup.next()).wait()
try loopGroup.syncShutdownGracefully()
}

func testFlatMapPerformance() throws {
let loopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
measure {
for _ in 0..<1000 {
try! doRecursive(n: 100, eventLoop: loopGroup.next()).wait()
}
}
try loopGroup.syncShutdownGracefully()
}

static let allTests = [
("testVariadicMap", testVariadicMap),
Expand All @@ -142,7 +168,9 @@ final class AsyncTests: XCTestCase {
("testFlattenFail", testFlattenFail),
("testFlattenEmpty", testFlattenEmpty),
("testFlattenStress", testFlattenStress),
("testFlattenPerformance", testFlattenPerformance)
("testFlattenPerformance", testFlattenPerformance),
("testFlatMapPerformance", testFlatMapPerformance),
("testFlatMapDoesNotCauseStackOverflowWhenFinishing", testFlatMapDoesNotCauseStackOverflowWhenFinishing)
]
}

Expand Down
4 changes: 2 additions & 2 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ jobs:
steps:
- run:
name: Clone Redis
command: git clone -b master https://github.com/vapor/redis.git
command: git clone -b support-3 https://github.com/vapor/redis.git
working_directory: ~/
- run:
name: Switch Redis to this Core revision
Expand All @@ -128,7 +128,7 @@ jobs:
steps:
- run:
name: Clone JWT
command: git clone -b master https://github.com/vapor/jwt.git
command: git clone -b 3 https://github.com/vapor/jwt.git
working_directory: ~/
- run:
name: Switch JWT to this Core revision
Expand Down
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载