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  }