Last active
August 29, 2015 14:17
-
-
Save finestructure/2f427934e171a8ab13af to your computer and use it in GitHub Desktop.
Attempt at a wrapper for NSError** parameter calls (as typically seen when calling objc APIs)
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
// https://gist.github.com/feinstruktur/2f427934e171a8ab13af | |
import Foundation | |
public class Box<T> { | |
let unbox: T | |
init(_ value: T) { self.unbox = value } | |
} | |
public enum Result<T> { | |
case Success(Box<T>) | |
case Failure(NSError) | |
public init(_ value: T) { self = .Success(Box(value)) } | |
public init(_ error: NSError) { self = .Failure(error) } | |
public var succeeded: Bool { | |
switch self { | |
case .Success: | |
return true | |
default: | |
return false | |
} | |
} | |
public var failed: Bool { | |
return !self.succeeded | |
} | |
public var value: T? { | |
switch self { | |
case .Success(let value): | |
return value.unbox | |
default: | |
return nil | |
} | |
} | |
public var error: NSError? { | |
switch self { | |
case .Failure(let error): | |
return error | |
default: | |
return nil | |
} | |
} | |
} | |
func try(block: NSErrorPointer -> Void) -> NSError? { | |
var error: NSError? | |
block(&error) | |
return error | |
} | |
func try<T>(block: NSErrorPointer -> T) -> Result<T> { | |
var error: NSError? | |
let res = block(&error) | |
if error == nil { | |
return Result(res) | |
} else { | |
return Result(error!) | |
} | |
} | |
// specialisation for Bool, because Bool return values signal stronger than NSError (for example in Core Data) | |
public func try(block: NSErrorPointer -> Bool) -> Result<Bool> { | |
var error: NSError? | |
let res = block(&error) | |
if res { | |
return Result(res) | |
} else { | |
return Result(error!) | |
} | |
} | |
// ----------------------------------------------------------- | |
// Usage | |
// ----------------------------------------------------------- | |
// - Helpers to create test cases | |
enum Param { | |
case Good, Bad | |
} | |
func doSomething(param: Param, error: NSErrorPointer) -> Bool { | |
switch param { | |
case .Good: | |
error.memory = nil | |
return true | |
case .Bad: | |
error.memory = NSError(domain: "Test", code: 42, userInfo: ["Key": "Value"]) | |
return false | |
} | |
} | |
func doSomething2(param: Param, error: NSErrorPointer) -> String { | |
switch param { | |
case .Good: | |
error.memory = nil | |
return "Success" | |
case .Bad: | |
error.memory = NSError(domain: "Test", code: 42, userInfo: ["Key": "Value"]) | |
return "Failure" | |
} | |
} | |
// - end of test helpers | |
// first version | |
if let error = try({ error in | |
let res = doSomething(.Good, error) | |
"above should be true" | |
}) { | |
"should not be reached" | |
} | |
if let error = try({ error in | |
let res = doSomething(.Bad, error) | |
}) { | |
error.code | |
"above should be 42" | |
} | |
// second version | |
// short circuit | |
if let res = try({ error in doSomething2(.Good, error) }).value { | |
res | |
"above should be 'Success'" | |
} else { | |
"should not be reached" | |
} | |
if let res = try({ error in doSomething2(.Bad, error) }).value { | |
"should not be reached" | |
} else { | |
"ok" | |
} | |
// long form | |
switch try({ error in doSomething(.Good, error) }) { | |
case .Success(let value): | |
value.unbox | |
"above should be true" | |
case .Failure(let error): | |
"should not be reached" | |
} | |
switch try({ error in doSomething(.Bad, error) }) { | |
case .Success(let value): | |
"should not be reached" | |
case .Failure(let error): | |
error.code | |
"above should be 42" | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment