Last active
November 15, 2022 13:59
-
-
Save seanlilmateus/5c7b158522c802b494c6 to your computer and use it in GitHub Desktop.
Result in Swift, Error handling in swift rust inspired...
This file contains 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
#!/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)") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nice work. FYI, they got rid of the underscore in autoclosure now