I have read lot of messages that it is impossible to have different return types for same function, but this is possible as you see here :)
Based on Jessy's code :
CAUTION:
- this code is the wrong way to work with Enum Associated Value's(!!!). Better to use standard syntax.
- this code works slower than standard syntax.
- this code will not work in case of you have few enum cases with the same name, but different associated value types.
SO NEVER USE SUCH CODE IN PRODUCTION
This was useless, but still, this was a really interesting experiment. Thanks a lot, Jessy & Sweeper.
usage sample:
enum Line: isAble {
case horizontal(CGFloat)
case vertical(CGFloat)
case diagonal(CGFloat, CGFloat)
}
let lineD = Line.diagonal(10, 20)
// will print "lineDiagonalValue: (10, 20)"
if let (val1, val2) = lineD.is(Line.diagonal) {
print("lineDiagonalValue: (\(val1), \(val2))")
}
if let val = lineH.is(Line.horizontal) {
print("this code will never work")
}
import Foundation
/* usage sample
enum Line: isAble {
case horizontal(CGFloat)
case vertical(CGFloat)
}
let lineH = Line.horizontal(10)
// will print "lineHorizontalValue: 10"
if let val = lineH.is(Line.horizontal) {
print("lineHorizontalValue: \(val)")
}
if let val = lineH.is(Line.horizontal) {
print("this code will never work")
}
*/
protocol isAble { }
extension isAble {
public func `is`<T>( _ val: (T) -> isAble) -> T? {
return Mirror.associatedValue(of: self, ifCase: val)
}
public func haveValue<T>( ofCase val: (T) -> isAble) -> Bool {
return Mirror.associatedValue(of: self, ifCase: val) != nil
}
}
/// Match `enum` cases with associated values, while disregarding the values themselves.
/// - Parameter case: Looks like `Enum.case`.
public func ~= <Enum: Equatable, AssociatedValue>(
case: (AssociatedValue) -> Enum,
instance: Enum
) -> Bool {
Mirror.associatedValue(of: instance, ifCase: `case`) != nil
}
/// Match `enum` cases with associated values, while disregarding the values themselves.
/// - Parameter case: Looks like `Enum.case`.
public func ~= <Enum, AssociatedValue>(
case: (AssociatedValue) -> Enum,
instance: Enum
) -> Bool {
Mirror.associatedValue(of: instance, ifCase: `case`) != nil
}
/// Match non-`Equatable` `enum` cases without associated values.
public func ~= <Enum>(pattern: Enum, instance: Enum) -> Bool {
guard (
[pattern, instance].allSatisfy {
let mirror = Mirror(reflecting: $0)
return mirror.displayStyle == .enum && mirror.children.isEmpty
}
) else { return false }
return .equate(pattern, to: instance) { "\($0)" }
}
public extension Mirror {
/// Get an `enum` case's `associatedValue`.
static func associatedValue<AssociatedValue>(
of subject: Any,
_: AssociatedValue.Type = AssociatedValue.self
) -> AssociatedValue? {
guard let childValue = Self(reflecting: subject).children.first?.value
else { return nil }
if let associatedValue = childValue as? AssociatedValue {
return associatedValue
}
let labeledAssociatedValue = Self(reflecting: childValue).children.first
return labeledAssociatedValue?.value as? AssociatedValue
}
/// Get an `enum` case's `associatedValue`.
/// - Parameter case: Looks like `Enum.case`.
static func associatedValue<Enum: Equatable, AssociatedValue>(
of instance: Enum,
ifCase case: (AssociatedValue) throws -> Enum
) rethrows -> AssociatedValue? {
try associatedValue(of: instance)
.filter { try `case`($0) == instance }
}
/// Get an `enum` case's `associatedValue`.
/// - Parameter case: Looks like `Enum.case`.
static func associatedValue<Enum, AssociatedValue>(
of instance: Enum,
ifCase case: (AssociatedValue) throws -> Enum
) rethrows -> AssociatedValue? {
try associatedValue(of: instance).filter {
.equate(try `case`($0), to: instance) {
Self(reflecting: $0).children.first?.label
}
}
}
}
public extension Optional {
/// Transform `.some` into `.none`, if a condition fails.
/// - Parameters:
/// - isSome: The condition that will result in `nil`, when evaluated to `false`.
func filter(_ isSome: (Wrapped) throws -> Bool) rethrows -> Self {
try flatMap { try isSome($0) ? $0 : nil }
}
}
public extension Equatable {
/// Equate two values using a closure.
static func equate<Wrapped, Equatable: Swift.Equatable>(
_ optional0: Wrapped?, to optional1: Wrapped?,
using transform: (Wrapped) throws -> Equatable
) rethrows -> Bool {
try optional0.map(transform) == optional1.map(transform)
}
}