Result.swift 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  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. switch self {
  50. case .success:
  51. return true
  52. case .failure:
  53. return false
  54. }
  55. }
  56. /// Returns `true` if the result is a failure, `false` otherwise.
  57. public var isFailure: Bool {
  58. return !isSuccess
  59. }
  60. /// Returns the associated value if the result is a success, `nil` otherwise.
  61. public var value: Value? {
  62. switch self {
  63. case .success(let value):
  64. return value
  65. case .failure:
  66. return nil
  67. }
  68. }
  69. /// Returns the associated error value if the result is a failure, `nil` otherwise.
  70. public var error: Error? {
  71. switch self {
  72. case .success:
  73. return nil
  74. case .failure(let error):
  75. return error
  76. }
  77. }
  78. }
  79. // MARK: - CustomStringConvertible
  80. extension Result: CustomStringConvertible {
  81. /// The textual representation used when written to an output stream, which includes whether the result was a
  82. /// success or failure.
  83. public var description: String {
  84. switch self {
  85. case .success:
  86. return "SUCCESS"
  87. case .failure:
  88. return "FAILURE"
  89. }
  90. }
  91. }
  92. // MARK: - CustomDebugStringConvertible
  93. extension Result: CustomDebugStringConvertible {
  94. /// The debug textual representation used when written to an output stream, which includes whether the result was a
  95. /// success or failure in addition to the value or error.
  96. public var debugDescription: String {
  97. switch self {
  98. case .success(let value):
  99. return "SUCCESS: \(value)"
  100. case .failure(let error):
  101. return "FAILURE: \(error)"
  102. }
  103. }
  104. }
  105. // MARK: - Functional APIs
  106. extension Result {
  107. /// Creates a `Result` instance from the result of a closure.
  108. ///
  109. /// A failure result is created when the closure throws, and a success result is created when the closure
  110. /// succeeds without throwing an error.
  111. ///
  112. /// func someString() throws -> String { ... }
  113. ///
  114. /// let result = Result(value: {
  115. /// return try someString()
  116. /// })
  117. ///
  118. /// // The type of result is Result<String>
  119. ///
  120. /// The trailing closure syntax is also supported:
  121. ///
  122. /// let result = Result { try someString() }
  123. ///
  124. /// - parameter value: The closure to execute and create the result for.
  125. public init(value: () throws -> Value) {
  126. do {
  127. self = try .success(value())
  128. } catch {
  129. self = .failure(error)
  130. }
  131. }
  132. /// Returns the success value, or throws the failure error.
  133. ///
  134. /// let possibleString: Result<String> = .success("success")
  135. /// try print(possibleString.unwrap())
  136. /// // Prints "success"
  137. ///
  138. /// let noString: Result<String> = .failure(error)
  139. /// try print(noString.unwrap())
  140. /// // Throws error
  141. public func unwrap() throws -> Value {
  142. switch self {
  143. case .success(let value):
  144. return value
  145. case .failure(let error):
  146. throw error
  147. }
  148. }
  149. /// Evaluates the specified closure when the `Result` is a success, passing the unwrapped value as a parameter.
  150. ///
  151. /// Use the `map` method with a closure that does not throw. For example:
  152. ///
  153. /// let possibleData: Result<Data> = .success(Data())
  154. /// let possibleInt = possibleData.map { $0.count }
  155. /// try print(possibleInt.unwrap())
  156. /// // Prints "0"
  157. ///
  158. /// let noData: Result<Data> = .failure(error)
  159. /// let noInt = noData.map { $0.count }
  160. /// try print(noInt.unwrap())
  161. /// // Throws error
  162. ///
  163. /// - parameter transform: A closure that takes the success value of the `Result` instance.
  164. ///
  165. /// - returns: A `Result` containing the result of the given closure. If this instance is a failure, returns the
  166. /// same failure.
  167. public func map<T>(_ transform: (Value) -> T) -> Result<T> {
  168. switch self {
  169. case .success(let value):
  170. return .success(transform(value))
  171. case .failure(let error):
  172. return .failure(error)
  173. }
  174. }
  175. /// Evaluates the specified closure when the `Result` is a success, passing the unwrapped value as a parameter.
  176. ///
  177. /// Use the `flatMap` method with a closure that may throw an error. For example:
  178. ///
  179. /// let possibleData: Result<Data> = .success(Data(...))
  180. /// let possibleObject = possibleData.flatMap {
  181. /// try JSONSerialization.jsonObject(with: $0)
  182. /// }
  183. ///
  184. /// - parameter transform: A closure that takes the success value of the instance.
  185. ///
  186. /// - returns: A `Result` containing the result of the given closure. If this instance is a failure, returns the
  187. /// same failure.
  188. public func flatMap<T>(_ transform: (Value) throws -> T) -> Result<T> {
  189. switch self {
  190. case .success(let value):
  191. do {
  192. return try .success(transform(value))
  193. } catch {
  194. return .failure(error)
  195. }
  196. case .failure(let error):
  197. return .failure(error)
  198. }
  199. }
  200. /// Evaluates the specified closure when the `Result` is a failure, passing the unwrapped error as a parameter.
  201. ///
  202. /// Use the `mapError` function with a closure that does not throw. For example:
  203. ///
  204. /// let possibleData: Result<Data> = .failure(someError)
  205. /// let withMyError: Result<Data> = possibleData.mapError { MyError.error($0) }
  206. ///
  207. /// - Parameter transform: A closure that takes the error of the instance.
  208. /// - Returns: A `Result` instance containing the result of the transform. If this instance is a success, returns
  209. /// the same instance.
  210. public func mapError<T: Error>(_ transform: (Error) -> T) -> Result {
  211. switch self {
  212. case .failure(let error):
  213. return .failure(transform(error))
  214. case .success:
  215. return self
  216. }
  217. }
  218. /// Evaluates the specified closure when the `Result` is a failure, passing the unwrapped error as a parameter.
  219. ///
  220. /// Use the `flatMapError` function with a closure that may throw an error. For example:
  221. ///
  222. /// let possibleData: Result<Data> = .success(Data(...))
  223. /// let possibleObject = possibleData.flatMapError {
  224. /// try someFailableFunction(taking: $0)
  225. /// }
  226. ///
  227. /// - Parameter transform: A throwing closure that takes the error of the instance.
  228. ///
  229. /// - Returns: A `Result` instance containing the result of the transform. If this instance is a success, returns
  230. /// the same instance.
  231. public func flatMapError<T: Error>(_ transform: (Error) throws -> T) -> Result {
  232. switch self {
  233. case .failure(let error):
  234. do {
  235. return try .failure(transform(error))
  236. } catch {
  237. return .failure(error)
  238. }
  239. case .success:
  240. return self
  241. }
  242. }
  243. /// Evaluates the specified closure when the `Result` is a success, passing the unwrapped value as a parameter.
  244. ///
  245. /// Use the `withValue` function to evaluate the passed closure without modifying the `Result` instance.
  246. ///
  247. /// - Parameter closure: A closure that takes the success value of this instance.
  248. /// - Returns: This `Result` instance, unmodified.
  249. @discardableResult
  250. public func withValue(_ closure: (Value) throws -> Void) rethrows -> Result {
  251. if case let .success(value) = self { try closure(value) }
  252. return self
  253. }
  254. /// Evaluates the specified closure when the `Result` is a failure, passing the unwrapped error as a parameter.
  255. ///
  256. /// Use the `withError` function to evaluate the passed closure without modifying the `Result` instance.
  257. ///
  258. /// - Parameter closure: A closure that takes the success value of this instance.
  259. /// - Returns: This `Result` instance, unmodified.
  260. @discardableResult
  261. public func withError(_ closure: (Error) throws -> Void) rethrows -> Result {
  262. if case let .failure(error) = self { try closure(error) }
  263. return self
  264. }
  265. /// Evaluates the specified closure when the `Result` is a success.
  266. ///
  267. /// Use the `ifSuccess` function to evaluate the passed closure without modifying the `Result` instance.
  268. ///
  269. /// - Parameter closure: A `Void` closure.
  270. /// - Returns: This `Result` instance, unmodified.
  271. @discardableResult
  272. public func ifSuccess(_ closure: () throws -> Void) rethrows -> Result {
  273. if isSuccess { try closure() }
  274. return self
  275. }
  276. /// Evaluates the specified closure when the `Result` is a failure.
  277. ///
  278. /// Use the `ifFailure` function to evaluate the passed closure without modifying the `Result` instance.
  279. ///
  280. /// - Parameter closure: A `Void` closure.
  281. /// - Returns: This `Result` instance, unmodified.
  282. @discardableResult
  283. public func ifFailure(_ closure: () throws -> Void) rethrows -> Result {
  284. if isFailure { try closure() }
  285. return self
  286. }
  287. }