Swift로 유한 오토매틱(상태기) 만들기

11363 단어 Swift
Swift의custom operator로 어떤 단락을 쓰려고 했는데 갑자기 상태기A => B가 생각나서 프로그램 라이브러리를 만들어 봤어요.
  • https://github.com/inamiy/SwiftState

  • 엔움으로 상태를 정의하여 여러 가지 비벼줍니다.

    코드 예

    
    enum MyState: StateType {
        case State0, State1, State2
        case AnyState   // create case=Any
    
        static func convertFromNilLiteral() -> MyState { return AnyState }
    }
    
    let machine = StateMachine<MyState, MyEvent>(state: .State0) { machine in
    
        machine.addRoute(.State0 => .State1)
        machine.addRoute(nil => .State2) { context in println("Any => 2, msg=\(context.userInfo!)") }
        machine.addRoute(.State2 => nil) { context in println("2 => Any, msg=\(context.userInfo!)") }
    
        // add handler (handlerContext = (event, transition, order, userInfo))
        machine.addHandler(.State0 => .State1) { context in
            println("0 => 1")
        }
    
        // add errorHandler
        machine.addErrorHandler { (event, transition, order, userInfo) in
            println("[ERROR] \(transition.fromState) => \(transition.toState)")
        }
    }
    
    // tryState 0 => 1 => 2 => 1 => 0
    machine <- .State1
    machine <- (.State2, "Hello")
    machine <- (.State1, "Bye")
    machine <- .State0  // fail: no 1 => 0
    
    println("machine.state = \(machine.state)")
    
    출력:
    0 => 1
    Any => 2, msg=Hello
    2 => Any, msg=Bye
    [ERROR] 1 => 0
    machine.state = 1
    

    변환의 연쇄


    비밀번호를 입력한 간이 버전.
    enum InputKey: StateType
    {
        case None
        // associated valueを使わないのは、それなりにワケあり
        case Key0, Key1, Key2, Key3, Key4, Key5, Key6, Key7, Key8, Key9
        case Any
    
        static func convertFromNilLiteral() -> InputKey { return Any }
    }
    
    var success = false
    
    let machine = StateMachine<InputKey, String>(state: .None) { machine in
    
        // connect all states
        machine.addRoute(nil => nil)
    
        // success = true only when transitionChain 2 => 3 => 5 => 7 is fulfilled
        machine.addRouteChain(.Key2 => .Key3 => .Key5 => .Key7) { context in
            success = true
            return
        }
    }
    
    // tryState
    machine <- .Key2
    machine <- .Key3
    machine <- .Key4
    machine <- .Key5
    machine <- .Key6
    machine <- .Key7
    
    XCTAssertFalse(success)
    
    machine <- .Key2
    machine <- .Key3
    machine <- .Key5
    machine <- .Key7
    
    XCTAssertTrue(success)
    
    이 외에도 transition 등록 및 Event 기반 트리거를 취소할 수 있습니다.
    OSX와 iOS 등 UI에 가까운 애플리케이션(=무제한 상태)이 얼마나 쓰일지 모르니 활용할 수 있는 방법이 있으면 or Pull Request를 알려주세요!

    좋은 웹페이지 즐겨찾기