Skip to content

Commit

Permalink
Split Task into multiple files.
Browse files Browse the repository at this point in the history
This helps for readability, and keeping every file concerned with a
single aspect of 'Task'.
  • Loading branch information
richardjrossiii committed Jun 1, 2016
1 parent 4e08f7e commit a8d4526
Show file tree
Hide file tree
Showing 6 changed files with 469 additions and 364 deletions.
40 changes: 40 additions & 0 deletions BoltsSwift.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,22 @@
81D3007F1C93AF9F00E1A1ED /* TaskTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300781C93AF9F00E1A1ED /* TaskTests.swift */; };
81D300801C93AF9F00E1A1ED /* TaskTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300781C93AF9F00E1A1ED /* TaskTests.swift */; };
87FEF3721A9085FA00C60678 /* BoltsSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 87FEF3661A9085FA00C60678 /* BoltsSwift.framework */; };
F569C0C11CFF6A07000749B6 /* Task+ContinueWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0C01CFF6A07000749B6 /* Task+ContinueWith.swift */; };
F569C0C21CFF6A07000749B6 /* Task+ContinueWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0C01CFF6A07000749B6 /* Task+ContinueWith.swift */; };
F569C0C31CFF6A07000749B6 /* Task+ContinueWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0C01CFF6A07000749B6 /* Task+ContinueWith.swift */; };
F569C0C41CFF6A07000749B6 /* Task+ContinueWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0C01CFF6A07000749B6 /* Task+ContinueWith.swift */; };
F569C0CC1CFF6AEE000749B6 /* Task+Delay.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0CB1CFF6AEE000749B6 /* Task+Delay.swift */; };
F569C0CD1CFF6AEE000749B6 /* Task+Delay.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0CB1CFF6AEE000749B6 /* Task+Delay.swift */; };
F569C0CE1CFF6AEE000749B6 /* Task+Delay.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0CB1CFF6AEE000749B6 /* Task+Delay.swift */; };
F569C0CF1CFF6AEE000749B6 /* Task+Delay.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0CB1CFF6AEE000749B6 /* Task+Delay.swift */; };
F569C0D71CFF6B18000749B6 /* Task+WhenAll.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0D61CFF6B18000749B6 /* Task+WhenAll.swift */; };
F569C0D81CFF6B18000749B6 /* Task+WhenAll.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0D61CFF6B18000749B6 /* Task+WhenAll.swift */; };
F569C0D91CFF6B18000749B6 /* Task+WhenAll.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0D61CFF6B18000749B6 /* Task+WhenAll.swift */; };
F569C0DA1CFF6B18000749B6 /* Task+WhenAll.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0D61CFF6B18000749B6 /* Task+WhenAll.swift */; };
F569C0E11CFF6B1F000749B6 /* Task+WhenAny.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0E01CFF6B1F000749B6 /* Task+WhenAny.swift */; };
F569C0E21CFF6B1F000749B6 /* Task+WhenAny.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0E01CFF6B1F000749B6 /* Task+WhenAny.swift */; };
F569C0E31CFF6B1F000749B6 /* Task+WhenAny.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0E01CFF6B1F000749B6 /* Task+WhenAny.swift */; };
F569C0E41CFF6B1F000749B6 /* Task+WhenAny.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0E01CFF6B1F000749B6 /* Task+WhenAny.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -82,6 +98,10 @@
81D300781C93AF9F00E1A1ED /* TaskTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TaskTests.swift; sourceTree = "<group>"; };
87FEF3661A9085FA00C60678 /* BoltsSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BoltsSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
87FEF3711A9085FA00C60678 /* BoltsSwiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BoltsSwiftTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
F569C0C01CFF6A07000749B6 /* Task+ContinueWith.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Task+ContinueWith.swift"; sourceTree = "<group>"; };
F569C0CB1CFF6AEE000749B6 /* Task+Delay.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Task+Delay.swift"; sourceTree = "<group>"; };
F569C0D61CFF6B18000749B6 /* Task+WhenAll.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Task+WhenAll.swift"; sourceTree = "<group>"; };
F569C0E01CFF6B1F000749B6 /* Task+WhenAny.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Task+WhenAny.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -154,6 +174,10 @@
children = (
81D300651C93AF7300E1A1ED /* Task.swift */,
81D300661C93AF7300E1A1ED /* TaskCompletionSource.swift */,
F569C0C01CFF6A07000749B6 /* Task+ContinueWith.swift */,
F569C0CB1CFF6AEE000749B6 /* Task+Delay.swift */,
F569C0D61CFF6B18000749B6 /* Task+WhenAll.swift */,
F569C0E01CFF6B1F000749B6 /* Task+WhenAny.swift */,
81D300641C93AF7300E1A1ED /* Executor.swift */,
81D300631C93AF7300E1A1ED /* Errors.swift */,
);
Expand Down Expand Up @@ -482,7 +506,11 @@
buildActionMask = 2147483647;
files = (
065894F21C9A9391000FDDA6 /* Errors.swift in Sources */,
F569C0DA1CFF6B18000749B6 /* Task+WhenAll.swift in Sources */,
065894EF1C9A9391000FDDA6 /* Task.swift in Sources */,
F569C0CF1CFF6AEE000749B6 /* Task+Delay.swift in Sources */,
F569C0C41CFF6A07000749B6 /* Task+ContinueWith.swift in Sources */,
F569C0E41CFF6B1F000749B6 /* Task+WhenAny.swift in Sources */,
065894F11C9A9391000FDDA6 /* Executor.swift in Sources */,
065894F01C9A9391000FDDA6 /* TaskCompletionSource.swift in Sources */,
);
Expand All @@ -493,7 +521,11 @@
buildActionMask = 2147483647;
files = (
065894F51C9A93B7000FDDA6 /* Executor.swift in Sources */,
F569C0D91CFF6B18000749B6 /* Task+WhenAll.swift in Sources */,
065894F61C9A93B7000FDDA6 /* Task.swift in Sources */,
F569C0CE1CFF6AEE000749B6 /* Task+Delay.swift in Sources */,
F569C0C31CFF6A07000749B6 /* Task+ContinueWith.swift in Sources */,
F569C0E31CFF6B1F000749B6 /* Task+WhenAny.swift in Sources */,
065894F71C9A93B7000FDDA6 /* Errors.swift in Sources */,
065894F81C9A93B7000FDDA6 /* TaskCompletionSource.swift in Sources */,
);
Expand All @@ -515,7 +547,11 @@
buildActionMask = 2147483647;
files = (
81D3006B1C93AF7300E1A1ED /* Executor.swift in Sources */,
F569C0D81CFF6B18000749B6 /* Task+WhenAll.swift in Sources */,
81D3006D1C93AF7300E1A1ED /* Task.swift in Sources */,
F569C0CD1CFF6AEE000749B6 /* Task+Delay.swift in Sources */,
F569C0C21CFF6A07000749B6 /* Task+ContinueWith.swift in Sources */,
F569C0E21CFF6B1F000749B6 /* Task+WhenAny.swift in Sources */,
81D300691C93AF7300E1A1ED /* Errors.swift in Sources */,
81D3006F1C93AF7300E1A1ED /* TaskCompletionSource.swift in Sources */,
);
Expand All @@ -537,7 +573,11 @@
buildActionMask = 2147483647;
files = (
81D3006A1C93AF7300E1A1ED /* Executor.swift in Sources */,
F569C0D71CFF6B18000749B6 /* Task+WhenAll.swift in Sources */,
81D3006C1C93AF7300E1A1ED /* Task.swift in Sources */,
F569C0CC1CFF6AEE000749B6 /* Task+Delay.swift in Sources */,
F569C0C11CFF6A07000749B6 /* Task+ContinueWith.swift in Sources */,
F569C0E11CFF6B1F000749B6 /* Task+WhenAny.swift in Sources */,
81D300681C93AF7300E1A1ED /* Errors.swift in Sources */,
81D3006E1C93AF7300E1A1ED /* TaskCompletionSource.swift in Sources */,
);
Expand Down
209 changes: 209 additions & 0 deletions Sources/BoltsSwift/Task+ContinueWith.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/*
* Copyright (c) 2016, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

import Foundation

//--------------------------------------
// MARK: - ContinueWith
//--------------------------------------

extension Task {
/**
Internal continueWithTask. This is the method that all other continuations must go through.

- parameter executor: The executor to invoke the closure on.
- parameter options: The options to run the closure with
- parameter continuation: The closure to execute.

- returns: The task resulting from the continuation
*/
private func continueWithTask<S>(executor: Executor, options: TaskContinuationOptions, continuation: (Task throws -> Task<S>)) -> Task<S> {
let taskCompletionSource = TaskCompletionSource<S>()
let wrapperContinuation = {
switch self.state {
case .Success where options.contains(.RunOnSuccess): fallthrough
case .Error where options.contains(.RunOnError): fallthrough
case .Cancelled where options.contains(.RunOnCancelled):
executor.execute {
let wrappedState = TaskState<Task<S>>.fromClosure {
try continuation(self)
}
switch wrappedState {
case .Success(let nextTask):
switch nextTask.state {
case .Pending:
nextTask.continueWith { nextTask in
taskCompletionSource.setState(nextTask.state)
}
default:
taskCompletionSource.setState(nextTask.state)
}
case .Error(let error):
taskCompletionSource.setError(error)
case .Cancelled:
taskCompletionSource.cancel()
default: abort() // This should never happen.
}
}

case .Success(let result as S):
// This is for continueOnErrorWith - the type of the result doesn't change, so we can pass it through
taskCompletionSource.setResult(result)

case .Error(let error):
taskCompletionSource.setError(error)

case .Cancelled:
taskCompletionSource.cancel()

default:
fatalError("Task was in an invalid state \(self.state)")
}
}
appendOrRunContinuation(wrapperContinuation)
return taskCompletionSource.task
}

/**
Enqueues a given closure to be run once this task is complete.

- parameter executor: Determines how the the closure is called. The default is to call the closure immediately.
- parameter continuation: The closure that returns the result of the task.

- returns: A task that will be completed with a result from a given closure.
*/
public func continueWith<S>(executor: Executor = .Default, continuation: (Task throws -> S)) -> Task<S> {
return continueWithTask(executor) { task in
let state = TaskState.fromClosure({
try continuation(task)
})
return Task<S>(state: state)
}
}

/**
Enqueues a given closure to be run once this task is complete.

- parameter executor: Determines how the the closure is called. The default is to call the closure immediately.
- parameter continuation: The closure that returns a task to chain on.

- returns: A task that will be completed when a task returned from a closure is completed.
*/
public func continueWithTask<S>(executor: Executor = .Default, continuation: (Task throws -> Task<S>)) -> Task<S> {
return continueWithTask(executor, options: .RunAlways, continuation: continuation)
}
}

//--------------------------------------
// MARK: - ContinueOnSuccessWith
//--------------------------------------

extension Task {
/**
Enqueues a given closure to be run once this task completes with success (has intended result).

- parameter executor: Determines how the the closure is called. The default is to call the closure immediately.
- parameter continuation: The closure that returns a task to chain on.

- returns: A task that will be completed when a task returned from a closure is completed.
*/
public func continueOnSuccessWith<S>(executor: Executor = .Default, continuation: (TResult throws -> S)) -> Task<S> {
return continueOnSuccessWithTask(executor) { taskResult in
let state = TaskState.fromClosure({
try continuation(taskResult)
})
return Task<S>(state: state)
}
}

/**
Enqueues a given closure to be run once this task completes with success (has intended result).

- parameter executor: Determines how the the closure is called. The default is to call the closure immediately.
- parameter continuation: The closure that returns a task to chain on.

- returns: A task that will be completed when a task returned from a closure is completed.
*/
public func continueOnSuccessWithTask<S>(executor: Executor = .Default, continuation: (TResult throws -> Task<S>)) -> Task<S> {
return continueWithTask(executor, options: .RunOnSuccess) { task in
return try continuation(task.result!)
}
}
}

//--------------------------------------
// MARK: - ContinueOnErrorWith
//--------------------------------------

extension Task {
/**
Enqueues a given closure to be run once this task completes with error.

- parameter executor: Determines how the the closure is called. The default is to call the closure immediately.
- parameter continuation: The closure that returns a task to chain on.

- returns: A task that will be completed when a task returned from a closure is completed.
*/
public func continueOnErrorWith<E: ErrorType>(executor: Executor = .Default, continuation: (E throws -> TResult)) -> Task {
return continueOnErrorWithTask(executor) { (error: E) in
let state = TaskState.fromClosure({
try continuation(error)
})
return Task(state: state)
}
}

/**
Enqueues a given closure to be run once this task completes with error.

- parameter executor: Determines how the the closure is called. The default is to call the closure immediately.
- parameter continuation: The closure that returns a task to chain on.

- returns: A task that will be completed when a task returned from a closure is completed.
*/
public func continueOnErrorWith(executor: Executor = .Default, continuation: (ErrorType throws -> TResult)) -> Task {
return continueOnErrorWithTask(executor) { (error: ErrorType) in
let state = TaskState.fromClosure({
try continuation(error)
})
return Task(state: state)
}
}

/**
Enqueues a given closure to be run once this task completes with error.

- parameter executor: Determines how the the closure is called. The default is to call the closure immediately.
- parameter continuation: The closure that returns a task to chain on.

- returns: A task that will be completed when a task returned from a closure is completed.
*/
public func continueOnErrorWithTask<E: ErrorType>(executor: Executor = .Default, continuation: (E throws -> Task)) -> Task {
return continueOnErrorWithTask(executor) { (error: ErrorType) in
if let error = error as? E {
return try continuation(error)
}
return Task(state: .Error(error))
}
}

/**
Enqueues a given closure to be run once this task completes with error.

- parameter executor: Determines how the the closure is called. The default is to call the closure immediately.
- parameter continuation: The closure that returns a task to chain on.

- returns: A task that will be completed when a task returned from a closure is completed.
*/
public func continueOnErrorWithTask(executor: Executor = .Default, continuation: (ErrorType throws -> Task)) -> Task {
return continueWithTask(executor, options: .RunOnError) { task in
return try continuation(task.error!)
}
}
}
32 changes: 32 additions & 0 deletions Sources/BoltsSwift/Task+Delay.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2016, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

import Foundation

//--------------------------------------
// MARK: - Task with Delay
//--------------------------------------

extension Task {
/**
Creates a task that will complete after the given delay.

- parameter delay: The delay for the task to completes.

- returns: A task that will complete after the given delay.
*/
public class func withDelay(delay: NSTimeInterval) -> Task<Void> {
let taskCompletionSource = TaskCompletionSource<Void>()
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * NSTimeInterval(NSEC_PER_SEC)))
dispatch_after(time, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
taskCompletionSource.trySetResult()
}
return taskCompletionSource.task
}
}
Loading

0 comments on commit a8d4526

Please sign in to comment.