Result.swift 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. //
  2. // Result.swift
  3. //
  4. // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/)
  5. //
  6. // Permission is hereby granted, free of charge, to any person obtaining a copy
  7. // of this software and associated documentation files (the "Software"), to deal
  8. // in the Software without restriction, including without limitation the rights
  9. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. // copies of the Software, and to permit persons to whom the Software is
  11. // furnished to do so, subject to the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included in
  14. // all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. // THE SOFTWARE.
  23. //
  24. import Foundation
  25. /// Used to represent whether a request was successful or encountered an error.
  26. ///
  27. /// - success: The request and all post processing operations were successful resulting in the serialization of the
  28. /// provided associated value.
  29. ///
  30. /// - failure: The request encountered an error resulting in a failure. The associated values are the original data
  31. /// provided by the server as well as the error that caused the failure.
  32. public enum Result<Value> {
  33. case success(Value)
  34. case failure(Error)
  35. /// Initializes a `Result` from value or error. Returns `.failure` if the error is non-nil, `.success` otherwise.
  36. ///
  37. /// - Parameters:
  38. /// - value: A value.
  39. /// - error: An `Error`.
  40. init(value: Value, error: Error?) {
  41. if let error = error {
  42. self = .failure(error)
  43. } else {
  44. self = .success(value)
  45. }
  46. }
  47. /// Returns `true` if the result is a success, `false` otherwise.
  48. public var isSuccess: Bool {
  49. guard case .success = self else { return false }
  50. return true
  51. }
  52. /// Returns `true` if the result is a failure, `false` otherwise.
  53. public var isFailure: Bool {
  54. return !isSuccess
  55. }
  56. /// Returns the associated value if the result is a success, `nil` otherwise.
  57. public var value: Value? {
  58. guard case .success(let value) = self else { return nil }
  59. return value
  60. }
  61. /// Returns the associated error value if the result is a failure, `nil` otherwise.
  62. public var error: Error? {
  63. guard case .failure(let error) = self else { return nil }
  64. return error
  65. }
  66. }
  67. // MARK: - CustomStringConvertible
  68. extension Result: CustomStringConvertible {
  69. /// The textual representation used when written to an output stream, which includes whether the result was a
  70. /// success or failure.
  71. public var description: String {
  72. switch self {
  73. case .success:
  74. return "SUCCESS"
  75. case .failure:
  76. return "FAILURE"
  77. }
  78. }
  79. }
  80. // MARK: - CustomDebugStringConvertible
  81. extension Result: CustomDebugStringConvertible {
  82. /// The debug textual representation used when written to an output stream, which includes whether the result was a
  83. /// success or failure in addition to the value or error.
  84. public var debugDescription: String {
  85. switch self {
  86. case .success(let value):
  87. return "SUCCESS: \(value)"
  88. case .failure(let error):
  89. return "FAILURE: \(error)"
  90. }
  91. }
  92. }
  93. // MARK: - Functional APIs
  94. extension Result {
  95. /// Creates a `Result` instance from the result of a closure.
  96. ///
  97. /// A failure result is created when the closure throws, and a success result is created when the closure
  98. /// succeeds without throwing an error.
  99. ///
  100. /// func someString() throws -> String { ... }
  101. ///
  102. /// let result = Result(value: {
  103. /// return try someString()
  104. /// })
  105. ///
  106. /// // The type of result is Result<String>
  107. ///
  108. /// The trailing closure syntax is also supported:
  109. ///
  110. /// let result = Result { try someString() }
  111. ///
  112. /// - parameter value: The closure to execute and create the result for.
  113. public init(value: () throws -> Value) {
  114. do {
  115. self = try .success(value())
  116. } catch {
  117. self = .failure(error)
  118. }
  119. }
  120. /// Returns the success value, or throws the failure error.
  121. ///
  122. /// let possibleString: Result<String> = .success("success")
  123. /// try print(possibleString.unwrap())
  124. /// // Prints "success"
  125. ///
  126. /// let noString: Result<String> = .failure(error)
  127. /// try print(noString.unwrap())
  128. /// // Throws error
  129. public func unwrap() throws -> Value {
  130. switch self {
  131. case .success(let value):
  132. return value
  133. case .failure(let error):
  134. throw error
  135. }
  136. }
  137. /// Evaluates the specified closure when the `Result` is a success, passing the unwrapped value as a parameter.
  138. ///
  139. /// Use the `map` method with a closure that does not throw. For example:
  140. ///
  141. /// let possibleData: Result<Data> = .success(Data())
  142. /// let possibleInt = possibleData.map { $0.count }
  143. /// try print(possibleInt.unwrap())
  144. /// // Prints "0"
  145. ///
  146. /// let noData: Result<Data> = .failure(error)
  147. /// let noInt = noData.map { $0.count }
  148. /// try print(noInt.unwrap())
  149. /// // Throws error
  150. ///
  151. /// - parameter transform: A closure that takes the success value of the `Result` instance.
  152. ///
  153. /// - returns: A `Result` containing the result of the given closure. If this instance is a failure, returns the
  154. /// same failure.
  155. public func map<T>(_ transform: (Value) -> T) -> Result<T> {
  156. switch self {
  157. case .success(let value):
  158. return .success(transform(value))
  159. case .failure(let error):
  160. return .failure(error)
  161. }
  162. }
  163. /// Evaluates the specified closure when the `Result` is a success, passing the unwrapped value as a parameter.
  164. ///
  165. /// Use the `flatMap` method with a closure that may throw an error. For example:
  166. ///
  167. /// let possibleData: Result<Data> = .success(Data(...))
  168. /// let possibleObject = possibleData.flatMap {
  169. /// try JSONSerialization.jsonObject(with: $0)
  170. /// }
  171. ///
  172. /// - parameter transform: A closure that takes the success value of the instance.
  173. ///
  174. /// - returns: A `Result` containing the result of the given closure. If this instance is a failure, returns the
  175. /// same failure.
  176. public func flatMap<T>(_ transform: (Value) throws -> T) -> Result<T> {
  177. switch self {
  178. case .success(let value):
  179. do {
  180. return try .success(transform(value))
  181. } catch {
  182. return .failure(error)
  183. }
  184. case .failure(let error):
  185. return .failure(error)
  186. }
  187. }
  188. /// Evaluates the specified closure when the `Result` is a failure, passing the unwrapped error as a parameter.
  189. ///
  190. /// Use the `mapError` function with a closure that does not throw. For example:
  191. ///
  192. /// let possibleData: Result<Data> = .failure(someError)
  193. /// let withMyError: Result<Data> = possibleData.mapError { MyError.error($0) }
  194. ///
  195. /// - Parameter transform: A closure that takes the error of the instance.
  196. /// - Returns: A `Result` instance containing the result of the transform. If this instance is a success, returns
  197. /// the same instance.
  198. public func mapError<T: Error>(_ transform: (Error) -> T) -> Result {
  199. guard case .failure(let error) = self else { return self }
  200. return .failure(transform(error))
  201. }
  202. /// Evaluates the specified closure when the `Result` is a failure, passing the unwrapped error as a parameter.
  203. ///
  204. /// Use the `flatMapError` function with a closure that may throw an error. For example:
  205. ///
  206. /// let possibleData: Result<Data> = .success(Data(...))
  207. /// let possibleObject = possibleData.flatMapError {
  208. /// try someFailableFunction(taking: $0)
  209. /// }
  210. ///
  211. /// - Parameter transform: A throwing closure that takes the error of the instance.
  212. ///
  213. /// - Returns: A `Result` instance containing the result of the transform. If this instance is a success, returns
  214. /// the same instance.
  215. public func flatMapError<T: Error>(_ transform: (Error) throws -> T) -> Result {
  216. switch self {
  217. case .failure(let error):
  218. do {
  219. return try .failure(transform(error))
  220. } catch {
  221. return .failure(error)
  222. }
  223. case .success:
  224. return self
  225. }
  226. }
  227. /// Evaluates the specified closure when the `Result` is a success, passing the unwrapped value as a parameter.
  228. ///
  229. /// Use the `withValue` function to evaluate the passed closure without modifying the `Result` instance.
  230. ///
  231. /// - Parameter closure: A closure that takes the success value of this instance.
  232. /// - Returns: This `Result` instance, unmodified.
  233. @discardableResult
  234. public func withValue(_ closure: (Value) throws -> Void) rethrows -> Result {
  235. if case let .success(value) = self { try closure(value) }
  236. return self
  237. }
  238. /// Evaluates the specified closure when the `Result` is a failure, passing the unwrapped error as a parameter.
  239. ///
  240. /// Use the `withError` function to evaluate the passed closure without modifying the `Result` instance.
  241. ///
  242. /// - Parameter closure: A closure that takes the success value of this instance.
  243. /// - Returns: This `Result` instance, unmodified.
  244. @discardableResult
  245. public func withError(_ closure: (Error) throws -> Void) rethrows -> Result {
  246. if case let .failure(error) = self { try closure(error) }
  247. return self
  248. }
  249. /// Evaluates the specified closure when the `Result` is a success.
  250. ///
  251. /// Use the `ifSuccess` function to evaluate the passed closure without modifying the `Result` instance.
  252. ///
  253. /// - Parameter closure: A `Void` closure.
  254. /// - Returns: This `Result` instance, unmodified.
  255. @discardableResult
  256. public func ifSuccess(_ closure: () throws -> Void) rethrows -> Result {
  257. if isSuccess { try closure() }
  258. return self
  259. }
  260. /// Evaluates the specified closure when the `Result` is a failure.
  261. ///
  262. /// Use the `ifFailure` function to evaluate the passed closure without modifying the `Result` instance.
  263. ///
  264. /// - Parameter closure: A `Void` closure.
  265. /// - Returns: This `Result` instance, unmodified.
  266. @discardableResult
  267. public func ifFailure(_ closure: () throws -> Void) rethrows -> Result {
  268. if isFailure { try closure() }
  269. return self
  270. }
  271. }