 //
 //  Created by Wyatt McBain on 10/21/16.
 //  Copyright © 2016 ZX Ventures. All rights reserved.
+//
+// Borrows heavily from: https://github.com/antitypical/Result
+//
+// However have amended to use `Swift.Error` exclusively as opposed to NSError
+// with a generic type constraint on Result in order to streamline declarations.
+// Since we use 100% Swift there's really no need to account for NSError types.
 //
 
 import Foundation

    
    case success(Value)
    case failure(Error)
    
    /// Creates a succesful result with an associated value.
    public init(_ value: Value) { self = .success(value) }
    
    /// Creates a result with an associated error.
    public init(_ error: Error) { self = .failure(error) }
    
    /// Optional value, returned when Self is .success.
    public var value: Value? {
     
        switch self {
        case .success(let value): return value
        case .failure:            return nil

        }
    }
}

extension Result {
    
    /// Returns a new Result by mapping success values using a transform
    /// or re-wraps error into failure.
    @discardableResult
    public func map<T>(_ transform: (Value) -> T) -> Result<T> {
        
        return flatMap { .success(transform($0)) }
    }
    
    /// Returns the Result of applying a transform to a success value or
    /// the re-wrapped error into failure.
    @discardableResult
    public func flatMap<T>(_ transform: (Value) -> Result<T>) -> Result<T> {
        
        switch self {
        case .success(let value): return transform(value)
        case .failure(let error): return .failure(error)
        }
    }
    
    /// Returns a new Result by mapping failure errors using a transform
    /// or re-wraps values into success.
    @discardableResult
    public func mapError(_ transform: (Error) -> Error) -> Result<Value> {
        
        return flatMapError { .failure(transform($0)) }
    }
    
    /// Returns the Result of applying a transform to a failure error or
    /// the re-wrapped value into success.
    @discardableResult
    public func flatMapError(_ transform: (Error) -> Result<Value>) -> Result<Value> {
        
        switch self {
        case .success(let value): return .success(value)
        case .failure(let error): return transform(error)
        }
    }
}
