Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Hyeonjae Park committed Jul 9, 2020
1 parent de1ffd7 commit ec20a75
Show file tree
Hide file tree
Showing 6 changed files with 293 additions and 0 deletions.
67 changes: 67 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# fsm

## Install

```
go get github.com/hyeonjae/fsm
```

## Usage

```go
package main

import "github.com/hyeonjae/fsm"

func main() {
s1 := fsm.State{State: "s1"}
s2 := fsm.State{State: "s2"}
s3 := fsm.State{State: "s3"}

a1 := fsm.Action{Action: "a"}
a2 := fsm.Action{Action: "b"}

t1 := fsm.Transition{
Tuple: fsm.StateActionTuple{State: s1, Action: a1},
State: s2,
}
t2 := fsm.Transition{
Tuple: fsm.StateActionTuple{State: s1, Action: a2},
State: s1,
}
t3 := fsm.Transition{
Tuple: fsm.StateActionTuple{State: s2, Action: a1},
State: s1,
}
t4 := fsm.Transition{
Tuple: fsm.StateActionTuple{State: s2, Action: a2},
State: s3,
}

builder := fsm.Builder().
States([]fsm.State{s1, s2, s3}).
Actions([]fsm.Action{a1, a2}).
Start(s1).
Accepts([]fsm.State{s3}).
Transitions([]fsm.Transition{t1, t2, t3, t4})

statemachine := fsm.New(builder)

statemachine.Start()

statemachine.Transit(a1)
statemachine.Transit(a1)
statemachine.Transit(a1)
statemachine.Transit(a2)

statemachine.Current() // s3
statemachine.Accepted() // true
}
```

## Test

```shell
$ go test ./...
ok github.com/hyeonjae/fsm 0.758s
```
71 changes: 71 additions & 0 deletions builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package fsm

type StateMachineBuilder interface {
States([]State) StateMachineBuilder
Actions([]Action) StateMachineBuilder
Start(State) StateMachineBuilder
Accepts([]State) StateMachineBuilder
Transitions([]Transition) StateMachineBuilder

Build() stateMachineComprehension
}

type stateMachineBuilder struct {
states []State
actions []Action
start State
accepts []State
transitions []Transition
}

func Builder() *stateMachineBuilder {
return &stateMachineBuilder{}
}

type stateMachineComprehension struct {
states []State
actions []Action
start State
accepts []State
transitions map[StateActionTuple]State
}

func (builder *stateMachineBuilder) States(states []State) StateMachineBuilder {
builder.states = states
return builder
}

func (builder *stateMachineBuilder) Actions(actions []Action) StateMachineBuilder {
builder.actions = actions
return builder
}

func (builder *stateMachineBuilder) Start(start State) StateMachineBuilder {
builder.start = start
return builder
}

func (builder *stateMachineBuilder) Accepts(accepts []State) StateMachineBuilder {
builder.accepts = accepts
return builder
}

func (builder *stateMachineBuilder) Transitions(transitions []Transition) StateMachineBuilder {
builder.transitions = transitions
return builder
}

func (builder *stateMachineBuilder) Build() stateMachineComprehension {
transitions := map[StateActionTuple]State{}
for _, transition := range builder.transitions {
transitions[transition.Tuple] = transition.State
}

return stateMachineComprehension{
states: builder.states,
actions: builder.actions,
start: builder.start,
accepts: builder.accepts,
transitions: transitions,
}
}
51 changes: 51 additions & 0 deletions fsm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package fsm

import "errors"

type StateMachine interface {
Start()
Transit(Action) error

Current() State
Accepted() bool
}

type stateMachine struct {
StateMachine stateMachineComprehension
CurrentState State
}

func (machine *stateMachine) Start() {
machine.CurrentState = machine.StateMachine.start
}

func (machine *stateMachine) Transit(a Action) error {
s := machine.CurrentState
next, exists := machine.StateMachine.transitions[StateActionTuple{s, a}]
if !exists {
return errors.New("No transition")
}

machine.CurrentState = next
return nil
}

func (machine stateMachine) Current() State {
return machine.CurrentState
}

func (machine stateMachine) Accepted() bool {
for _, accept := range machine.StateMachine.accepts {
if machine.CurrentState == accept {
return true
}
}
return false
}

func New(builder StateMachineBuilder) StateMachine {
return &stateMachine{
StateMachine: builder.Build(),
CurrentState: State{},
}
}
82 changes: 82 additions & 0 deletions fsm_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package fsm_test

import (
"testing"

fsm "github.com/hyeonjae/fsm"
)

func TestFSM(t *testing.T) {
s1 := fsm.State{State: "s1"}
s2 := fsm.State{State: "s2"}
s3 := fsm.State{State: "s3"}

a1 := fsm.Action{Action: "a"}
a2 := fsm.Action{Action: "b"}

t1 := fsm.Transition{
Tuple: fsm.StateActionTuple{State: s1, Action: a1},
State: s2,
}
t2 := fsm.Transition{
Tuple: fsm.StateActionTuple{State: s1, Action: a2},
State: s1,
}
t3 := fsm.Transition{
Tuple: fsm.StateActionTuple{State: s2, Action: a1},
State: s1,
}
t4 := fsm.Transition{
Tuple: fsm.StateActionTuple{State: s2, Action: a2},
State: s3,
}

builder := fsm.Builder().
States([]fsm.State{s1, s2, s3}).
Actions([]fsm.Action{a1, a2}).
Start(s1).
Accepts([]fsm.State{s3}).
Transitions([]fsm.Transition{t1, t2, t3, t4})

statemachine := fsm.New(builder)

statemachine.Start()
if statemachine.Current() != s1 {
t.Error("Wrong result")
}
if statemachine.Accepted() != false {
t.Error("Wrong result")
}

statemachine.Transit(a1)
if statemachine.Current() != s2 {
t.Error("Wrong result")
}
if statemachine.Accepted() != false {
t.Error("Wrong result")
}

statemachine.Transit(a1)
if statemachine.Current() != s1 {
t.Error("Wrong result")
}
if statemachine.Accepted() != false {
t.Error("Wrong result")
}

statemachine.Transit(a1)
if statemachine.Current() != s2 {
t.Error("Wrong result")
}
if statemachine.Accepted() != false {
t.Error("Wrong result")
}

statemachine.Transit(a2)
if statemachine.Current() != s3 {
t.Error("Wrong result")
}
if statemachine.Accepted() != true {
t.Error("Wrong result")
}
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/hyeonjae/fsm

go 1.14
19 changes: 19 additions & 0 deletions type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package fsm

type State struct {
State string
}

type Action struct {
Action string
}

type StateActionTuple struct {
State State
Action Action
}

type Transition struct {
Tuple StateActionTuple
State State
}

0 comments on commit ec20a75

Please sign in to comment.