Skip to content

Instantly share code, notes, and snippets.

@seanlilmateus
Last active November 15, 2022 13:59
Show Gist options
  • Save seanlilmateus/5c7b158522c802b494c6 to your computer and use it in GitHub Desktop.
Save seanlilmateus/5c7b158522c802b494c6 to your computer and use it in GitHub Desktop.
Result in Swift, Error handling in swift rust inspired...
#!/usr/bin/env xcrun swift -i
import Foundation
enum Result<T, E> {
/*
We can't use this at the moment due to a LLVM Error:
error: unimplemented IR generation feature non-fixed multi-payload enum layout
LLVM ERROR: unimplemented IRGen feature! non-fixed multi-payload enum layout
case Success(T)
case Failure(E)
*/
case Success(@auto_closure() -> T)
case Failure(@auto_closure() -> E)
func isSuccess() -> Bool {
switch self {
case .Success: return true
default: return false
}
}
func isFailure() -> Bool {
return !self.isSuccess()
}
func success() -> T? {
switch self {
case .Success(let x): return Optional.Some(x())
default: return nil
}
}
func failure() -> E? {
switch self {
case .Failure(let e): return Optional.Some(e())
default: return nil
}
}
func map<U>(op: T -> U) -> Result<U, E> {
switch self {
case .Success(let x): return .Success(op(x()))
case .Failure(let x): return .Failure(x())
}
}
func mapFailure<F>(op: E -> F) -> Result<T,F> {
switch self {
case .Success(let t): return .Success(t)
case .Failure(let e): return .Failure(op(e()))
}
}
func and<U>(res: Result<U, E>) -> Result<U, E> {
switch self {
case .Success: return res
case .Failure(let e): return .Failure(e())
}
}
func andThen<U>(op: T -> Result<U, E>) -> Result<U, E> {
switch self {
case .Success(let t): return op(t())
case .Failure(let e): return .Failure(e)
}
}
func or(res: Result<T, E>) -> Result<T, E> {
switch self {
case .Success: return self
case .Failure: return res
}
}
func orElse<F>(op: E -> Result<T, F>) -> Result<T, F> {
switch self {
case .Success(let t): return .Success(t())
case .Failure(let e): return op(e())
}
}
func unwrapOr(optb: T) -> T {
switch self {
case .Success(let t): return t()
case .Failure: return optb
}
}
func unwrapOrElse(op: E -> T) -> T {
switch self {
case .Success(let t): return t()
case .Failure(let e): return op(e())
}
}
// Fails if the value is an `Failure`, with a custom failure message provided
// by the `Failure`'s value.
// caller line && file, otherwise would git the current line where the fatalError is called
func unwrap(file: StaticString = __FILE__, line: UWord = __LINE__) -> T {
switch self {
case .Success(let x): return x()
case .Failure(let e): fatalError("unexpectedly found a Failure while unwrapping a Result value", file:file, line:line)
}
}
// Fails if the value is an `Success`, with a custom failure message provided
// by the `Success`'s value.
// caller line && file, otherwise would git the current line where the fatalError is called
func unwrapError(file: StaticString = __FILE__, line: UWord = __LINE__) -> E {
switch self {
case .Failure(let e): return e()
case .Success(let x): fatalError("unexpectedly found a Success while unwrapping a Result value", file:file, line:line)
}
}
}
extension Result : Printable {
var description : String {
switch self {
case .Success(let x): return ".Success(\(x()))"
case .Failure(let e): return ".Failure(\(e()))"
}
}
}
extension Result : LogicValue {
func getLogicValue() -> Bool {
return self.isSuccess()
}
}
enum Version : Printable {
case Version1, Version2
var description : String {
switch self {
case .Version1: return "Version1"
case .Version2: return "Version2"
}
}
}
typealias IOResult = Result<NSData, NSError>
func readFile(path:String) -> IOResult {
var maybeError:NSError?
let url:NSURL = NSURL(string: path)
let handler:NSFileHandle? = NSFileHandle.fileHandleForReadingFromURL(url, error:&maybeError)
if let file = handler {
return .Success(file.availableData)
} else if let error = maybeError {
return .Failure(error)
} else { // should never happen, unless NSURL initialization fails...
let userInfo = ["reason":"An unknown error has occurred"]
return .Failure(NSError(domain: "SwiftIO", code: -2, userInfo: userInfo))
}
}
func parseVersion(header: [UInt8]) -> Result<Version, String> {
if header.count < 1 { return .Failure("invalid header length") }
switch header[0] {
case 1: return .Success(.Version1)
case 2: return .Success(.Version2)
default: return .Failure("invalid version")
}
}
// IOResult for reading files
let profile = readFile("\(NSHomeDirectory())/.profile")
let result:Result<String, NSError> = profile.map { x in NSString(data:x, encoding: NSUTF8StringEncoding) }
println(result.description)
// header parsing
let header = parseVersion([0, 2, 3, 4])
if let version = header.success() {
println("working with version: \(version)")
} else if let error = header.failure() {
println("error parsing header: \(error)")
}
@Spilly
Copy link

Spilly commented Aug 20, 2014

Nice work. FYI, they got rid of the underscore in autoclosure now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment