Last active
March 18, 2016 17:11
-
-
Save paulofaria/1aa155987f5f1f905081 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Dispatch | |
import XCPlayground | |
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true | |
func delay(duration: Double, closure: Void -> Void) { | |
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(duration * Double(NSEC_PER_SEC))) | |
dispatch_after(delayTime, dispatch_get_main_queue(), closure) | |
} | |
func testResponder(responder: AsyncResponder) { | |
responder.respond(Request(body: "Foo")) { result in | |
do { | |
let response = try result() | |
print(response) | |
} catch { | |
print(error) | |
} | |
} | |
} | |
// Request/Response | |
struct Request { | |
let body: String | |
} | |
struct Response { | |
let body: String | |
} | |
// Sync Responder | |
protocol Responder: AsyncResponder { | |
func respond(request: Request) throws -> Response | |
} | |
extension Responder { | |
func respond(request: Request, asyncResponse: AsyncResponse) { | |
asyncResponse { | |
try self.respond(request) | |
} | |
} | |
} | |
// Async Responder | |
typealias AsyncResponse = (Void throws -> Response) -> Void | |
protocol AsyncResponder { | |
func respond(request: Request, asyncResponse: AsyncResponse) | |
} | |
// Result Responder | |
enum Result<T> { | |
case Success(T) | |
case Failure(ErrorType) | |
} | |
typealias ResultResponse = Result<Response> -> Void | |
protocol ResultResponder: AsyncResponder { | |
func respond(request: Request, resultResponse: ResultResponse) | |
} | |
extension ResultResponder { | |
func respond(request: Request, asyncResponse: AsyncResponse) { | |
self.respond(request) { result in | |
switch result { | |
case .Success(let response): | |
asyncResponse { | |
response | |
} | |
case .Failure(let error): | |
asyncResponse { | |
throw error | |
} | |
} | |
} | |
} | |
} | |
// Future Responder | |
final class Future<T> { | |
typealias Completion = Result<T> -> Void | |
typealias Success = T -> Void | |
typealias Failure = ErrorType -> Void | |
var completion: Completion? | |
var success: Success? | |
var failure: Failure? | |
var result: Result<T>? | |
init(future: Future<T> -> Void) { | |
future(self) | |
} | |
func succeed(value: T) { | |
result = Result.Success(value) | |
success?(value) | |
} | |
func onSuccess(success: Success) -> Future<T> { | |
if let result = result { | |
if case .Success(let value) = result { | |
success(value) | |
} | |
} else { | |
self.success = success | |
} | |
return self | |
} | |
func fail(error: ErrorType) { | |
result = Result.Failure(error) | |
failure?(error) | |
} | |
func onFailure(failure: Failure) -> Future<T> { | |
if let result = result { | |
if case .Failure(let error) = result { | |
failure(error) | |
} | |
} else { | |
self.failure = failure | |
} | |
return self | |
} | |
func complete(result: Result<T>) { | |
self.result = result | |
switch result { | |
case .Success(let value): | |
succeed(value) | |
case .Failure(let error): | |
fail(error) | |
} | |
complete(result) | |
} | |
func onCompletion(completion: Completion) -> Future<T> { | |
if let result = result { | |
completion(result) | |
} else { | |
self.completion = completion | |
} | |
return self | |
} | |
} | |
protocol FutureResponder: AsyncResponder { | |
func respond(request: Request) -> Future<Response> | |
} | |
extension FutureResponder { | |
func respond(request: Request, asyncResponse: AsyncResponse) { | |
self.respond(request) | |
.onSuccess { response in | |
asyncResponse { | |
response | |
} | |
}.onFailure { error in | |
asyncResponse { | |
throw error | |
} | |
} | |
} | |
} | |
// Responder Usage | |
struct ResponderExample: Responder { | |
func respond(request: Request) -> Response { | |
return Response(body: request.body) | |
} | |
} | |
testResponder(ResponderExample()) | |
// AsyncResponder Usage | |
struct AsyncResponderExample: AsyncResponder { | |
func respond(request: Request, asyncResponse: AsyncResponse) { | |
delay(1) { | |
asyncResponse { | |
Response(body: request.body + " Async") | |
} | |
} | |
} | |
} | |
testResponder(AsyncResponderExample()) | |
// ResultResponder Usage | |
struct ResultResponderExample: ResultResponder { | |
func respond(request: Request, resultResponse: ResultResponse) { | |
delay(2) { | |
let response = Response(body: request.body + " Result") | |
resultResponse(Result.Success(response)) | |
} | |
} | |
} | |
testResponder(ResultResponderExample()) | |
// FutureResponder Usage | |
struct FutureResponderExample: FutureResponder { | |
func respond(request: Request) -> Future<Response> { | |
return Future<Response> { future in | |
delay(3) { | |
let response = Response(body: request.body + " Future") | |
future.succeed(response) | |
} | |
} | |
} | |
} | |
testResponder(FutureResponderExample()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment