Result.swift 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. //
  2. // Result.swift
  3. // Kingfisher
  4. //
  5. // Created by onevcat on 2018/09/22.
  6. //
  7. // Copyright (c) 2018 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. // This is a copy from https://github.com/apple/swift/pull/19982
  28. // If this PR is merged to stblib later, we may need to remove these content by a Swift version flag.
  29. /// A value that represents either a success or failure, capturing associated
  30. /// values in both cases.
  31. public enum Result<Value, Error> {
  32. /// A success, storing a `Value`.
  33. case success(Value)
  34. /// A failure, storing an `Error`.
  35. case failure(Error)
  36. /// The stored value of a successful `Result`. `nil` if the `Result` was a
  37. /// failure.
  38. public var value: Value? {
  39. switch self {
  40. case let .success(value):
  41. return value
  42. case .failure:
  43. return nil
  44. }
  45. }
  46. /// The stored value of a failure `Result`. `nil` if the `Result` was a
  47. /// success.
  48. public var error: Error? {
  49. switch self {
  50. case let .failure(error):
  51. return error
  52. case .success:
  53. return nil
  54. }
  55. }
  56. /// A Boolean value indicating whether the `Result` as a success.
  57. public var isSuccess: Bool {
  58. switch self {
  59. case .success:
  60. return true
  61. case .failure:
  62. return false
  63. }
  64. }
  65. /// Evaluates the given transform closure when this `Result` instance is
  66. /// `.success`, passing the value as a parameter.
  67. ///
  68. /// Use the `map` method with a closure that returns a non-`Result` value.
  69. ///
  70. /// - Parameter transform: A closure that takes the successful value of the
  71. /// instance.
  72. /// - Returns: A new `Result` instance with the result of the transform, if
  73. /// it was applied.
  74. public func map<NewValue>(
  75. _ transform: (Value) -> NewValue
  76. ) -> Result<NewValue, Error> {
  77. switch self {
  78. case let .success(value):
  79. return .success(transform(value))
  80. case let .failure(error):
  81. return .failure(error)
  82. }
  83. }
  84. /// Evaluates the given transform closure when this `Result` instance is
  85. /// `.failure`, passing the error as a parameter.
  86. ///
  87. /// Use the `mapError` method with a closure that returns a non-`Result`
  88. /// value.
  89. ///
  90. /// - Parameter transform: A closure that takes the failure value of the
  91. /// instance.
  92. /// - Returns: A new `Result` instance with the result of the transform, if
  93. /// it was applied.
  94. public func mapError<NewError>(
  95. _ transform: (Error) -> NewError
  96. ) -> Result<Value, NewError> {
  97. switch self {
  98. case let .success(value):
  99. return .success(value)
  100. case let .failure(error):
  101. return .failure(transform(error))
  102. }
  103. }
  104. /// Evaluates the given transform closure when this `Result` instance is
  105. /// `.success`, passing the value as a parameter and flattening the result.
  106. ///
  107. /// - Parameter transform: A closure that takes the successful value of the
  108. /// instance.
  109. /// - Returns: A new `Result` instance, either from the transform or from
  110. /// the previous error value.
  111. public func flatMap<NewValue>(
  112. _ transform: (Value) -> Result<NewValue, Error>
  113. ) -> Result<NewValue, Error> {
  114. switch self {
  115. case let .success(value):
  116. return transform(value)
  117. case let .failure(error):
  118. return .failure(error)
  119. }
  120. }
  121. /// Evaluates the given transform closure when this `Result` instance is
  122. /// `.failure`, passing the error as a parameter and flattening the result.
  123. ///
  124. /// - Parameter transform: A closure that takes the error value of the
  125. /// instance.
  126. /// - Returns: A new `Result` instance, either from the transform or from
  127. /// the previous success value.
  128. public func flatMapError<NewError>(
  129. _ transform: (Error) -> Result<Value, NewError>
  130. ) -> Result<Value, NewError> {
  131. switch self {
  132. case let .success(value):
  133. return .success(value)
  134. case let .failure(error):
  135. return transform(error)
  136. }
  137. }
  138. /// Evaluates the given transform closures to create a single output value.
  139. ///
  140. /// - Parameters:
  141. /// - onSuccess: A closure that transforms the success value.
  142. /// - onFailure: A closure that transforms the error value.
  143. /// - Returns: A single `Output` value.
  144. public func fold<Output>(
  145. onSuccess: (Value) -> Output,
  146. onFailure: (Error) -> Output
  147. ) -> Output {
  148. switch self {
  149. case let .success(value):
  150. return onSuccess(value)
  151. case let .failure(error):
  152. return onFailure(error)
  153. }
  154. }
  155. }
  156. extension Result where Error : Swift.Error {
  157. /// Unwraps the `Result` into a throwing expression.
  158. ///
  159. /// - Returns: The success value, if the instance is a success.
  160. /// - Throws: The error value, if the instance is a failure.
  161. public func unwrapped() throws -> Value {
  162. switch self {
  163. case let .success(value):
  164. return value
  165. case let .failure(error):
  166. throw error
  167. }
  168. }
  169. }
  170. extension Result where Error == Swift.Error {
  171. /// Create an instance by capturing the output of a throwing closure.
  172. ///
  173. /// - Parameter throwing: A throwing closure to evaluate.
  174. @_transparent
  175. public init(_ throwing: () throws -> Value) {
  176. do {
  177. let value = try throwing()
  178. self = .success(value)
  179. } catch {
  180. self = .failure(error)
  181. }
  182. }
  183. /// Unwraps the `Result` into a throwing expression.
  184. ///
  185. /// - Returns: The success value, if the instance is a success.
  186. /// - Throws: The error value, if the instance is a failure.
  187. public func unwrapped() throws -> Value {
  188. switch self {
  189. case let .success(value):
  190. return value
  191. case let .failure(error):
  192. throw error
  193. }
  194. }
  195. /// Evaluates the given transform closure when this `Result` instance is
  196. /// `.success`, passing the value as a parameter and flattening the result.
  197. ///
  198. /// - Parameter transform: A closure that takes the successful value of the
  199. /// instance.
  200. /// - Returns: A new `Result` instance, either from the transform or from
  201. /// the previous error value.
  202. public func flatMap<NewValue>(
  203. _ transform: (Value) throws -> NewValue
  204. ) -> Result<NewValue, Error> {
  205. switch self {
  206. case let .success(value):
  207. do {
  208. return .success(try transform(value))
  209. } catch {
  210. return .failure(error)
  211. }
  212. case let .failure(error):
  213. return .failure(error)
  214. }
  215. }
  216. }
  217. extension Result : Equatable where Value : Equatable, Error : Equatable { }
  218. extension Result : Hashable where Value : Hashable, Error : Hashable {
  219. public func hash(into hasher: inout Hasher) {
  220. hasher.combine(value)
  221. hasher.combine(error)
  222. }
  223. }
  224. extension Result : CustomDebugStringConvertible {
  225. public var debugDescription: String {
  226. var output = "Result."
  227. switch self {
  228. case let .success(value):
  229. output += "success("
  230. debugPrint(value, terminator: "", to: &output)
  231. case let .failure(error):
  232. output += "failure("
  233. debugPrint(error, terminator: "", to: &output)
  234. }
  235. output += ")"
  236. return output
  237. }
  238. }