123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- //
- // Result.swift
- // Kingfisher
- //
- // Created by onevcat on 2018/09/22.
- //
- // Copyright (c) 2019 Wei Wang <onevcat@gmail.com>
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- import Foundation
- #if swift(>=4.3)
- /// Result type already built-in
- #else
- /// A value that represents either a success or failure, capturing associated
- /// values in both cases.
- public enum Result<Success, Failure> {
- /// A success, storing a `Value`.
- case success(Success)
- /// A failure, storing an `Error`.
- case failure(Failure)
- /// Evaluates the given transform closure when this `Result` instance is
- /// `.success`, passing the value as a parameter.
- ///
- /// Use the `map` method with a closure that returns a non-`Result` value.
- ///
- /// - Parameter transform: A closure that takes the successful value of the
- /// instance.
- /// - Returns: A new `Result` instance with the result of the transform, if
- /// it was applied.
- public func map<NewSuccess>(
- _ transform: (Success) -> NewSuccess
- ) -> Result<NewSuccess, Failure> {
- switch self {
- case let .success(success):
- return .success(transform(success))
- case let .failure(failure):
- return .failure(failure)
- }
- }
- /// Evaluates the given transform closure when this `Result` instance is
- /// `.failure`, passing the error as a parameter.
- ///
- /// Use the `mapError` method with a closure that returns a non-`Result`
- /// value.
- ///
- /// - Parameter transform: A closure that takes the failure value of the
- /// instance.
- /// - Returns: A new `Result` instance with the result of the transform, if
- /// it was applied.
- public func mapError<NewFailure>(
- _ transform: (Failure) -> NewFailure
- ) -> Result<Success, NewFailure> {
- switch self {
- case let .success(success):
- return .success(success)
- case let .failure(failure):
- return .failure(transform(failure))
- }
- }
- /// Evaluates the given transform closure when this `Result` instance is
- /// `.success`, passing the value as a parameter and flattening the result.
- ///
- /// - Parameter transform: A closure that takes the successful value of the
- /// instance.
- /// - Returns: A new `Result` instance, either from the transform or from
- /// the previous error value.
- public func flatMap<NewSuccess>(
- _ transform: (Success) -> Result<NewSuccess, Failure>
- ) -> Result<NewSuccess, Failure> {
- switch self {
- case let .success(success):
- return transform(success)
- case let .failure(failure):
- return .failure(failure)
- }
- }
- /// Evaluates the given transform closure when this `Result` instance is
- /// `.failure`, passing the error as a parameter and flattening the result.
- ///
- /// - Parameter transform: A closure that takes the error value of the
- /// instance.
- /// - Returns: A new `Result` instance, either from the transform or from
- /// the previous success value.
- public func flatMapError<NewFailure>(
- _ transform: (Failure) -> Result<Success, NewFailure>
- ) -> Result<Success, NewFailure> {
- switch self {
- case let .success(success):
- return .success(success)
- case let .failure(failure):
- return transform(failure)
- }
- }
- }
- extension Result where Failure: Error {
- /// Returns the success value as a throwing expression.
- ///
- /// Use this method to retrieve the value of this result if it represents a
- /// success, or to catch the value if it represents a failure.
- ///
- /// let integerResult: Result<Int, Error> = .success(5)
- /// do {
- /// let value = try integerResult.get()
- /// print("The value is \(value).")
- /// } catch error {
- /// print("Error retrieving the value: \(error)")
- /// }
- /// // Prints "The value is 5."
- ///
- /// - Returns: The success value, if the instance represents a success.
- /// - Throws: The failure value, if the instance represents a failure.
- public func get() throws -> Success {
- switch self {
- case let .success(success):
- return success
- case let .failure(failure):
- throw failure
- }
- }
- /// Unwraps the `Result` into a throwing expression.
- ///
- /// - Returns: The success value, if the instance is a success.
- /// - Throws: The error value, if the instance is a failure.
- @available(*, deprecated, message: "This method will be removed soon. Use `get() throws -> Success` instead.")
- public func unwrapped() throws -> Success {
- switch self {
- case let .success(value):
- return value
- case let .failure(error):
- throw error
- }
- }
- }
- extension Result where Failure == Swift.Error {
- /// Creates a new result by evaluating a throwing closure, capturing the
- /// returned value as a success, or any thrown error as a failure.
- ///
- /// - Parameter body: A throwing closure to evaluate.
- @_transparent
- public init(catching body: () throws -> Success) {
- do {
- self = .success(try body())
- } catch {
- self = .failure(error)
- }
- }
- }
- extension Result : Equatable where Success : Equatable, Failure: Equatable { }
- extension Result : Hashable where Success : Hashable, Failure : Hashable { }
- extension Result : CustomDebugStringConvertible {
- public var debugDescription: String {
- var output = "Result."
- switch self {
- case let .success(value):
- output += "success("
- debugPrint(value, terminator: "", to: &output)
- case let .failure(error):
- output += "failure("
- debugPrint(error, terminator: "", to: &output)
- }
- output += ")"
- return output
- }
- }
- #endif
- // These helper methods are not public since we do not want them to be exposed or cause any conflicting.
- // However, they are just wrapper of `ResultUtil` static methods.
- extension Result where Failure: Error {
- /// Evaluates the given transform closures to create a single output value.
- ///
- /// - Parameters:
- /// - onSuccess: A closure that transforms the success value.
- /// - onFailure: A closure that transforms the error value.
- /// - Returns: A single `Output` value.
- func match<Output>(
- onSuccess: (Success) -> Output,
- onFailure: (Failure) -> Output) -> Output
- {
- switch self {
- case let .success(value):
- return onSuccess(value)
- case let .failure(error):
- return onFailure(error)
- }
- }
- func matchSuccess<Output>(with folder: (Success?) -> Output) -> Output {
- return match(
- onSuccess: { value in return folder(value) },
- onFailure: { _ in return folder(nil) }
- )
- }
- func matchFailure<Output>(with folder: (Error?) -> Output) -> Output {
- return match(
- onSuccess: { _ in return folder(nil) },
- onFailure: { error in return folder(error) }
- )
- }
- func match<Output>(with folder: (Success?, Error?) -> Output) -> Output {
- return match(
- onSuccess: { return folder($0, nil) },
- onFailure: { return folder(nil, $0) }
- )
- }
- }
|