// Copyright © 2024 Ryan Booker. All rights reserved.
import ArgumentParser
import Foundation
public enum Either<First, Second> {
case first(First)
case second(Second)
public func reduce<T>(
first firstResult: (First) -> T,
second secondResult: (Second) -> T
) -> T {
switch self {
case let .first(value):
firstResult(value)
case let .second(error):
secondResult(error)
}
}
}
extension Either: CustomStringConvertible
where First: CustomStringConvertible, Second: CustomStringConvertible {
public var description: String {
reduce(first: \.description, second: \.description)
}
}
extension Either: Decodable
where First: Decodable, Second: Decodable {
public init(from decoder: Decoder) throws {
self = try tryBoth(decoder, first: First.init, second: Second.init)
}
}
extension Either: ExpressibleByArgument
where First: ExpressibleByArgument, Second: ExpressibleByArgument {
public init?(argument: String) {
if let value = First(argument: argument) {
self = .first(value)
} else if let value = Second(argument: argument) {
self = .second(value)
} else {
return nil
}
}
}
public func tryBoth<A, First, Second>(
_ value: A,
first: (A) throws -> First,
second: (A) throws -> Second
) throws -> Either<First, Second> {
do {
return try .first(first(value))
} catch let firstError {
do {
return try .second(second(value))
} catch let secondError {
throw [firstError, secondError]
}
}
}
extension Array: Error where Element: Error {}