github.com/aretext/aretext@v1.3.0/input/engine/serialize.go (about) 1 package engine 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "io" 7 "slices" 8 ) 9 10 // Serialize encodes the state machine as binary. 11 func Serialize(sm *StateMachine) []byte { 12 var data []byte 13 writeInt := func(i uint64) { 14 data = binary.AppendUvarint(data, i) 15 } 16 17 writeInt(uint64(sm.numStates)) 18 writeInt(uint64(sm.startState)) 19 writeInt(uint64(len(sm.acceptCmd))) 20 for _, stateId := range sortedAcceptCmdKeys(sm) { 21 cmdId := sm.acceptCmd[stateId] 22 writeInt(uint64(stateId)) 23 writeInt(uint64(cmdId)) 24 } 25 26 writeInt(uint64(len(sm.transitions))) 27 for _, stateId := range sortedTransitionKeys(sm) { 28 transitions := sm.transitions[stateId] 29 writeInt(uint64(stateId)) 30 writeInt(uint64(len(transitions))) 31 for _, t := range transitions { 32 writeInt(uint64(t.eventRange.start)) 33 writeInt(uint64(t.eventRange.end)) 34 writeInt(uint64(t.nextState)) 35 36 writeInt(uint64(len(t.captures))) 37 for _, cmdId := range sortedCaptureKeys(t) { 38 captureId := t.captures[cmdId] 39 writeInt(uint64(cmdId)) 40 writeInt(uint64(captureId)) 41 } 42 } 43 } 44 45 return data 46 } 47 48 // Deserialize constructs a state machine from serialized binary. 49 func Deserialize(data []byte) (*StateMachine, error) { 50 var i int 51 readInt := func() (uint64, error) { 52 if i >= len(data) { 53 return 0, io.EOF 54 } 55 x, n := binary.Uvarint(data[i:]) 56 if n <= 0 { 57 return 0, fmt.Errorf("varint decode error") 58 } 59 i += n 60 return x, nil 61 } 62 63 sm := &StateMachine{} 64 65 numStates, err := readInt() 66 if err != nil { 67 return nil, fmt.Errorf("deserialize numStates: %w", err) 68 } 69 sm.numStates = numStates 70 71 startState, err := readInt() 72 if err != nil { 73 return nil, fmt.Errorf("deserialize startState: %w", err) 74 } 75 sm.startState = stateId(startState) 76 77 numAcceptCmd, err := readInt() 78 if err != nil { 79 return nil, fmt.Errorf("deserialize numAcceptCmd: %w", err) 80 } 81 82 sm.acceptCmd = make(map[stateId]CmdId, numAcceptCmd) 83 for i := uint64(0); i < numAcceptCmd; i++ { 84 stateKey, err := readInt() 85 if err != nil { 86 return nil, fmt.Errorf("deserialize acceptCmd stateKey: %w", err) 87 } 88 cmdVal, err := readInt() 89 if err != nil { 90 return nil, fmt.Errorf("deserialize acceptCmd cmdVal: %w", err) 91 } 92 sm.acceptCmd[stateId(stateKey)] = CmdId(cmdVal) 93 } 94 95 numTransitions, err := readInt() 96 if err != nil { 97 return nil, fmt.Errorf("deserialize numTransitions: %w", err) 98 } 99 100 sm.transitions = make(map[stateId][]transition, numTransitions) 101 for i := uint64(0); i < numTransitions; i++ { 102 stateKey, err := readInt() 103 if err != nil { 104 return nil, fmt.Errorf("deserialize transition stateKey: %w", err) 105 } 106 107 numTransitionsForState, err := readInt() 108 if err != nil { 109 return nil, fmt.Errorf("deserialize transition numTransitionsForState: %w", err) 110 } 111 112 sm.transitions[stateId(stateKey)] = make([]transition, 0, numTransitionsForState) 113 for j := uint64(0); j < numTransitionsForState; j++ { 114 eventStartVal, err := readInt() 115 if err != nil { 116 return nil, fmt.Errorf("deserialize transition eventStartVal: %w", err) 117 } 118 119 eventEndVal, err := readInt() 120 if err != nil { 121 return nil, fmt.Errorf("deserialize transition eventEndVal: %w", err) 122 } 123 124 nextStateVal, err := readInt() 125 if err != nil { 126 return nil, fmt.Errorf("deserialize transition nextStateVal: %w", err) 127 } 128 129 numCaptures, err := readInt() 130 if err != nil { 131 return nil, fmt.Errorf("deserialize transition numCaptures: %w", err) 132 } 133 134 t := transition{ 135 eventRange: eventRange{ 136 start: Event(eventStartVal), 137 end: Event(eventEndVal), 138 }, 139 nextState: stateId(nextStateVal), 140 } 141 142 if numCaptures > 0 { 143 t.captures = make(map[CmdId]CaptureId, numCaptures) 144 for k := uint64(0); k < numCaptures; k++ { 145 captureCmdKey, err := readInt() 146 if err != nil { 147 return nil, fmt.Errorf("deserialize capture cmdKey: %w", err) 148 } 149 150 captureIdVal, err := readInt() 151 if err != nil { 152 return nil, fmt.Errorf("deserialize capture captureIdVal: %w", err) 153 } 154 155 t.captures[CmdId(captureCmdKey)] = CaptureId(captureIdVal) 156 } 157 } 158 159 sm.transitions[stateId(stateKey)] = append(sm.transitions[stateId(stateKey)], t) 160 } 161 } 162 163 return sm, nil 164 } 165 166 func sortedAcceptCmdKeys(sm *StateMachine) []stateId { 167 keys := make([]stateId, 0, len(sm.acceptCmd)) 168 for stateId := range sm.acceptCmd { 169 keys = append(keys, stateId) 170 } 171 slices.Sort(keys) 172 return keys 173 } 174 175 func sortedTransitionKeys(sm *StateMachine) []stateId { 176 keys := make([]stateId, 0, len(sm.transitions)) 177 for stateId := range sm.transitions { 178 keys = append(keys, stateId) 179 } 180 slices.Sort(keys) 181 return keys 182 } 183 184 func sortedCaptureKeys(t transition) []CmdId { 185 keys := make([]CmdId, 0, len(t.captures)) 186 for cmdId := range t.captures { 187 keys = append(keys, cmdId) 188 } 189 slices.Sort(keys) 190 return keys 191 }