diff --git a/Result/Result.swift b/Result/Result.swift index 81aaf05..6608ae8 100644 --- a/Result/Result.swift +++ b/Result/Result.swift @@ -1,14 +1,14 @@ // Copyright (c) 2015 Rob Rix. All rights reserved. /// An enum representing either a failure with an explanatory error, or a success with a result value. -public enum Result: ResultProtocol, CustomStringConvertible, CustomDebugStringConvertible { - case success(T) +public enum Result: ResultProtocol, CustomStringConvertible, CustomDebugStringConvertible { + case success(Value) case failure(Error) // MARK: Constructors /// Constructs a success wrapping a `value`. - public init(value: T) { + public init(value: Value) { self = .success(value) } @@ -18,17 +18,17 @@ public enum Result: ResultProtocol, CustomStringConvertib } /// Constructs a result from an `Optional`, failing with `Error` if `nil`. - public init(_ value: T?, failWith: @autoclosure () -> Error) { + public init(_ value: Value?, failWith: @autoclosure () -> Error) { self = value.map(Result.success) ?? .failure(failWith()) } /// Constructs a result from a function that uses `throw`, failing with `Error` if throws. - public init(_ f: @autoclosure () throws -> T) { + public init(_ f: @autoclosure () throws -> Value) { self.init(attempt: f) } /// Constructs a result from a function that uses `throw`, failing with `Error` if throws. - public init(attempt f: () throws -> T) { + public init(attempt f: () throws -> Value) { do { self = .success(try f()) } catch var error { @@ -42,7 +42,7 @@ public enum Result: ResultProtocol, CustomStringConvertib // MARK: Deconstruction /// Returns the value from `success` Results or `throw`s the error. - public func dematerialize() throws -> T { + public func dematerialize() throws -> Value { switch self { case let .success(value): return value @@ -54,7 +54,7 @@ public enum Result: ResultProtocol, CustomStringConvertib /// Case analysis for Result. /// /// Returns the value produced by applying `ifFailure` to `failure` Results, or `ifSuccess` to `success` Results. - public func analysis(ifSuccess: (T) -> Result, ifFailure: (Error) -> Result) -> Result { + public func analysis(ifSuccess: (Value) -> Result, ifFailure: (Error) -> Result) -> Result { switch self { case let .success(value): return ifSuccess(value) @@ -107,6 +107,11 @@ public enum Result: ResultProtocol, CustomStringConvertib public var debugDescription: String { return description } + + // MARK: ResultProtocol + public var result: Result { + return self + } } // MARK: - Derive result from failable closure diff --git a/Result/ResultProtocol.swift b/Result/ResultProtocol.swift index fac8ce2..5fb90af 100644 --- a/Result/ResultProtocol.swift +++ b/Result/ResultProtocol.swift @@ -1,34 +1,14 @@ // Copyright (c) 2015 Rob Rix. All rights reserved. -/// A type that can represent either failure with an error or success with a result value. +/// A protocol that can be used to constrain associated types as `Result`. public protocol ResultProtocol { associatedtype Value associatedtype Error: Swift.Error - - /// Constructs a successful result wrapping a `value`. - init(value: Value) - - /// Constructs a failed result wrapping an `error`. - init(error: Error) - - /// Case analysis for ResultProtocol. - /// - /// Returns the value produced by appliying `ifFailure` to the error if self represents a failure, or `ifSuccess` to the result value if self represents a success. - func analysis(ifSuccess: (Value) -> U, ifFailure: (Error) -> U) -> U - /// Returns the value if self represents a success, `nil` otherwise. - /// - /// A default implementation is provided by a protocol extension. Conforming types may specialize it. - var value: Value? { get } - - /// Returns the error if self represents a failure, `nil` otherwise. - /// - /// A default implementation is provided by a protocol extension. Conforming types may specialize it. - var error: Error? { get } + var result: Result { get } } -public extension ResultProtocol { - +public extension Result { /// Returns the value if self represents a success, `nil` otherwise. public var value: Value? { return analysis(ifSuccess: { $0 }, ifFailure: { _ in nil }) @@ -53,9 +33,7 @@ public extension ResultProtocol { /// Returns a Result with a tuple of the receiver and `other` values if both /// are `Success`es, or re-wrapping the error of the earlier `Failure`. - public func fanout(_ other: @autoclosure () -> R) -> Result<(Value, R.Value), Error> - where Error == R.Error - { + public func fanout(_ other: @autoclosure () -> Result) -> Result<(Value, U), Error> { return self.flatMap { left in other().map { right in (left, right) } } } @@ -80,7 +58,7 @@ public extension ResultProtocol { } } -public extension ResultProtocol { +public extension Result { // MARK: Higher-order functions @@ -90,7 +68,7 @@ public extension ResultProtocol { } /// Returns this result if it is a .Success, or the given result otherwise. Equivalent with `??` - public func recover(with result: @autoclosure () -> Self) -> Self { + public func recover(with result: @autoclosure () -> Result) -> Result { return analysis( ifSuccess: { _ in self }, ifFailure: { _ in result() }) @@ -102,7 +80,7 @@ public protocol ErrorConvertible: Swift.Error { static func error(from error: Swift.Error) -> Self } -public extension ResultProtocol where Error: ErrorConvertible { +public extension Result where Error: ErrorConvertible { /// Returns the result of applying `transform` to `Success`es’ values, or wrapping thrown errors. public func tryMap(_ transform: (Value) throws -> U) -> Result { @@ -121,9 +99,9 @@ public extension ResultProtocol where Error: ErrorConvertible { // MARK: - Operators -extension ResultProtocol where Value: Equatable, Error: Equatable { +extension Result where Value: Equatable, Error: Equatable { /// Returns `true` if `left` and `right` are both `Success`es and their values are equal, or if `left` and `right` are both `Failure`s and their errors are equal. - public static func ==(left: Self, right: Self) -> Bool { + public static func ==(left: Result, right: Result) -> Bool { if let left = left.value, let right = right.value { return left == right } else if let left = left.error, let right = right.error { @@ -133,19 +111,19 @@ extension ResultProtocol where Value: Equatable, Error: Equatable { } /// Returns `true` if `left` and `right` represent different cases, or if they represent the same case but different values. - public static func !=(left: Self, right: Self) -> Bool { + public static func !=(left: Result, right: Result) -> Bool { return !(left == right) } } -extension ResultProtocol { +extension Result { /// Returns the value of `left` if it is a `Success`, or `right` otherwise. Short-circuits. - public static func ??(left: Self, right: @autoclosure () -> Value) -> Value { + public static func ??(left: Result, right: @autoclosure () -> Value) -> Value { return left.recover(right()) } /// Returns `left` if it is a `Success`es, or `right` otherwise. Short-circuits. - public static func ??(left: Self, right: @autoclosure () -> Self) -> Self { + public static func ??(left: Result, right: @autoclosure () -> Result) -> Result { return left.recover(with: right()) } }