Result.swift 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. //
  2. // Result.swift
  3. // Kingfisher
  4. //
  5. // Created by onevcat on 2018/09/22.
  6. //
  7. // Copyright (c) 2019 Wei Wang <onevcat@gmail.com>
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining a copy
  10. // of this software and associated documentation files (the "Software"), to deal
  11. // in the Software without restriction, including without limitation the rights
  12. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. // copies of the Software, and to permit persons to whom the Software is
  14. // furnished to do so, subject to the following conditions:
  15. //
  16. // The above copyright notice and this permission notice shall be included in
  17. // all copies or substantial portions of the Software.
  18. //
  19. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. // THE SOFTWARE.
  26. import Foundation
  27. /// A value that represents either a success or failure, capturing associated
  28. /// values in both cases.
  29. public enum Result<Success, Failure> {
  30. /// A success, storing a `Value`.
  31. case success(Success)
  32. /// A failure, storing an `Error`.
  33. case failure(Failure)
  34. /// Evaluates the given transform closure when this `Result` instance is
  35. /// `.success`, passing the value as a parameter.
  36. ///
  37. /// Use the `map` method with a closure that returns a non-`Result` value.
  38. ///
  39. /// - Parameter transform: A closure that takes the successful value of the
  40. /// instance.
  41. /// - Returns: A new `Result` instance with the result of the transform, if
  42. /// it was applied.
  43. public func map<NewSuccess>(
  44. _ transform: (Success) -> NewSuccess
  45. ) -> Result<NewSuccess, Failure> {
  46. switch self {
  47. case let .success(success):
  48. return .success(transform(success))
  49. case let .failure(failure):
  50. return .failure(failure)
  51. }
  52. }
  53. /// Evaluates the given transform closure when this `Result` instance is
  54. /// `.failure`, passing the error as a parameter.
  55. ///
  56. /// Use the `mapError` method with a closure that returns a non-`Result`
  57. /// value.
  58. ///
  59. /// - Parameter transform: A closure that takes the failure value of the
  60. /// instance.
  61. /// - Returns: A new `Result` instance with the result of the transform, if
  62. /// it was applied.
  63. public func mapError<NewFailure>(
  64. _ transform: (Failure) -> NewFailure
  65. ) -> Result<Success, NewFailure> {
  66. switch self {
  67. case let .success(success):
  68. return .success(success)
  69. case let .failure(failure):
  70. return .failure(transform(failure))
  71. }
  72. }
  73. /// Evaluates the given transform closure when this `Result` instance is
  74. /// `.success`, passing the value as a parameter and flattening the result.
  75. ///
  76. /// - Parameter transform: A closure that takes the successful value of the
  77. /// instance.
  78. /// - Returns: A new `Result` instance, either from the transform or from
  79. /// the previous error value.
  80. public func flatMap<NewSuccess>(
  81. _ transform: (Success) -> Result<NewSuccess, Failure>
  82. ) -> Result<NewSuccess, Failure> {
  83. switch self {
  84. case let .success(success):
  85. return transform(success)
  86. case let .failure(failure):
  87. return .failure(failure)
  88. }
  89. }
  90. /// Evaluates the given transform closure when this `Result` instance is
  91. /// `.failure`, passing the error as a parameter and flattening the result.
  92. ///
  93. /// - Parameter transform: A closure that takes the error value of the
  94. /// instance.
  95. /// - Returns: A new `Result` instance, either from the transform or from
  96. /// the previous success value.
  97. public func flatMapError<NewFailure>(
  98. _ transform: (Failure) -> Result<Success, NewFailure>
  99. ) -> Result<Success, NewFailure> {
  100. switch self {
  101. case let .success(success):
  102. return .success(success)
  103. case let .failure(failure):
  104. return transform(failure)
  105. }
  106. }
  107. }
  108. extension Result where Failure: Error {
  109. /// Returns the success value as a throwing expression.
  110. ///
  111. /// Use this method to retrieve the value of this result if it represents a
  112. /// success, or to catch the value if it represents a failure.
  113. ///
  114. /// let integerResult: Result<Int, Error> = .success(5)
  115. /// do {
  116. /// let value = try integerResult.get()
  117. /// print("The value is \(value).")
  118. /// } catch error {
  119. /// print("Error retrieving the value: \(error)")
  120. /// }
  121. /// // Prints "The value is 5."
  122. ///
  123. /// - Returns: The success value, if the instance represents a success.
  124. /// - Throws: The failure value, if the instance represents a failure.
  125. public func get() throws -> Success {
  126. switch self {
  127. case let .success(success):
  128. return success
  129. case let .failure(failure):
  130. throw failure
  131. }
  132. }
  133. /// Unwraps the `Result` into a throwing expression.
  134. ///
  135. /// - Returns: The success value, if the instance is a success.
  136. /// - Throws: The error value, if the instance is a failure.
  137. @available(*, deprecated, message: "This method will be removed soon. Use `get() throws -> Success` instead.")
  138. public func unwrapped() throws -> Success {
  139. switch self {
  140. case let .success(value):
  141. return value
  142. case let .failure(error):
  143. throw error
  144. }
  145. }
  146. }
  147. extension Result where Failure == Swift.Error {
  148. /// Creates a new result by evaluating a throwing closure, capturing the
  149. /// returned value as a success, or any thrown error as a failure.
  150. ///
  151. /// - Parameter body: A throwing closure to evaluate.
  152. @_transparent
  153. public init(catching body: () throws -> Success) {
  154. do {
  155. self = .success(try body())
  156. } catch {
  157. self = .failure(error)
  158. }
  159. }
  160. }
  161. extension Result : Equatable where Success : Equatable, Failure: Equatable { }
  162. extension Result : Hashable where Success : Hashable, Failure : Hashable { }
  163. extension Result : CustomDebugStringConvertible {
  164. public var debugDescription: String {
  165. var output = "Result."
  166. switch self {
  167. case let .success(value):
  168. output += "success("
  169. debugPrint(value, terminator: "", to: &output)
  170. case let .failure(error):
  171. output += "failure("
  172. debugPrint(error, terminator: "", to: &output)
  173. }
  174. output += ")"
  175. return output
  176. }
  177. }
  178. // Deprecated
  179. extension Result {
  180. /// The stored value of a successful `Result`. `nil` if the `Result` was a failure.
  181. @available(*, deprecated, message: "This method will be removed soon. Use `get() throws -> Success` instead.")
  182. public var value: Success? {
  183. switch self {
  184. case let .success(value):
  185. return value
  186. case .failure:
  187. return nil
  188. }
  189. }
  190. /// The stored value of a failure `Result`. `nil` if the `Result` was a success.
  191. @available(*, deprecated, message: "This method will be removed soon. Use `get() throws -> Success` instead.")
  192. public var error: Failure? {
  193. switch self {
  194. case let .failure(error):
  195. return error
  196. case .success:
  197. return nil
  198. }
  199. }
  200. /// A Boolean value indicating whether the `Result` as a success.
  201. @available(*, deprecated, message: "This method will be removed soon. Use methods defined in `Swift.Result`.")
  202. public var isSuccess: Bool {
  203. switch self {
  204. case .success:
  205. return true
  206. case .failure:
  207. return false
  208. }
  209. }
  210. }
  211. // These helper methods are not public since we do not want them to be exposed or cause any conflicting.
  212. // However, they are just wrapper of `ResultUtil` static methods.
  213. extension Result where Failure: Error {
  214. /// Evaluates the given transform closures to create a single output value.
  215. ///
  216. /// - Parameters:
  217. /// - onSuccess: A closure that transforms the success value.
  218. /// - onFailure: A closure that transforms the error value.
  219. /// - Returns: A single `Output` value.
  220. func match<Output>(
  221. onSuccess: (Success) -> Output,
  222. onFailure: (Failure) -> Output) -> Output
  223. {
  224. switch self {
  225. case let .success(value):
  226. return onSuccess(value)
  227. case let .failure(error):
  228. return onFailure(error)
  229. }
  230. }
  231. func matchSuccess<Output>(with folder: (Success?) -> Output) -> Output {
  232. return match(
  233. onSuccess: { value in return folder(value) },
  234. onFailure: { _ in return folder(nil) }
  235. )
  236. }
  237. func matchFailure<Output>(with folder: (Error?) -> Output) -> Output {
  238. return match(
  239. onSuccess: { _ in return folder(nil) },
  240. onFailure: { error in return folder(error) }
  241. )
  242. }
  243. func match<Output>(with folder: (Success?, Error?) -> Output) -> Output {
  244. return match(
  245. onSuccess: { return folder($0, nil) },
  246. onFailure: { return folder(nil, $0) }
  247. )
  248. }
  249. }