Skip to content

Instantly share code, notes, and snippets.

@muescha
Created January 13, 2017 05:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save muescha/0a6101329f3473cedaf202b33b4e3dc5 to your computer and use it in GitHub Desktop.
Save muescha/0a6101329f3473cedaf202b33b4e3dc5 to your computer and use it in GitHub Desktop.
Castable

https://github.com/idapgroup/IDPCastable

i like the idea of Castable. but i don't like to have too much public functions without an "Namespace" aka Class flying around like cast, castable, match.

i prefer it more encapsulated in one class and also to prefix the first closure also with match to get it uniform with the other matches

i rewrite the class like this:

/**
 Chainable type representing the value matching different types
 */
public enum Castable<Wrapped> {
    case value(Wrapped)
    
    /**
     Wraps a value in Castable.
     - Parameter x:    Value to wrap.
     - Returns:        Value wrapped by Castable
     */
    init(_ data: Wrapped){
        self = .value(data)
    }
    
    /**
     Casts a value from Type to Result?
     
     - Parameter value:     Value to be casted
     - Returns:             *.some(value: Result)* if the value could be casted, *.none* otherwise
     */
    private func cast<Type, Result>(_ value: Type) -> Result? {
        return value as? Result
    }
    
    /**
     Casts a value to function argument type and calls a function, if the cast was successfull.
     - Parameter f:     Function to call, if the *.value* in can be be casted to function argument
     - Returns:         Castable wrapping the same value
     */
    @discardableResult
    public func match<Subject>(f: (Subject) -> ()) -> Castable<Wrapped> {
        switch self {
        case let .value(x):
            cast(x).map { f($0) }
            return .value(x)
        }
    }
    
    /**
     Extracts a value from Castable
     
     - Returns:     Value wrapped by Castable
     */
    public func extract() -> Wrapped {
        switch self {
        case let .value(x):
            return x
        }
    }
}

to test it in Playground

class RedCell{}
class GreenCell{}
class ColorCell{}

class RedColorCell: ColorCell{}
class GreenColorCell: ColorCell{}
class LightRedColorCell: RedColorCell{}

[ RedCell(), GreenCell(), ColorCell(), 
RedColorCell(),GreenColorCell(),
LightRedColorCell()].map{

    print("\nTest for : \($0)")
    
    let u = Castable($0)
        .match{ (x:RedCell)  in
            print("Tested   : RedCell")
        }
        .match{ (x:GreenCell)  in
            print("Tested   : GreenCell")
        }
        .match{ (x:ColorCell)  in
            print("Tested   : ColorCell")
        }
        .match{ (x:RedColorCell)  in
            print("Tested   : RedColorCell")
        }
        .match{ (x:GreenColorCell)  in
            print("Tested   : GreenColorCell")
        }
        .match{ (x:LightRedColorCell)  in
            print("Tested   : LightRedColorCell")
        }
        .extract()

    print("Extracted: \(u)")

}

Output:

Test for : RedCell
Tested   : RedCell
Extracted: RedCell

Test for : GreenCell
Tested   : GreenCell
Extracted: GreenCell

Test for : ColorCell
Tested   : ColorCell
Extracted: ColorCell

Test for : RedColorCell
Tested   : ColorCell
Tested   : RedColorCell
Extracted: RedColorCell

Test for : GreenColorCell
Tested   : ColorCell
Tested   : GreenColorCell
Extracted: GreenColorCell

Test for : LightRedColorCell
Tested   : ColorCell
Tested   : RedColorCell
Tested   : LightRedColorCell
Extracted: LightRedColorCell
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment