1
1
import { useCallback , useReducer , useRef , useState } from "react" ;
2
2
import { RUST } from "../rust_functions.js" ;
3
3
4
- const STATE = {
5
- IDLE : 1 ,
6
- LOADING : 2 ,
7
- LOADED : 3 ,
8
- RUNNING : 4 ,
9
- PAUSED : 5 ,
10
- STOPPED : 6 ,
11
- } ;
4
+ enum STATE {
5
+ IDLE = 1 ,
6
+ LOADING = 2 ,
7
+ LOADED = 3 ,
8
+ RUNNING = 4 ,
9
+ PAUSED = 5 ,
10
+ STOPPED = 6 ,
11
+ }
12
12
13
13
const CALLBACKS_TRIGGERS = {
14
14
RESET : "RESET" ,
15
15
STEP : "STEP"
16
- } ;
16
+ } as const ;
17
+
18
+ type ValidCallbackTriggers = keyof typeof CALLBACKS_TRIGGERS ;
17
19
18
20
const CALLBACK_TYPES = {
19
21
CONSOLE : "CONSOLE" ,
20
22
MEMORY : "MEMORY" ,
21
23
REGISTRY : "REGISTRY" ,
22
- } ;
24
+ } as const ;
25
+
26
+ type ValidCallbackTypes = keyof typeof CALLBACK_TYPES ;
27
+
23
28
24
- let initialCallbacks = { } ;
25
- Object . values ( CALLBACKS_TRIGGERS ) . map ( x => initialCallbacks [ x ] = { } ) ;
29
+ type CallbackTriggerObject = Partial < Record < ValidCallbackTypes , ( ) => unknown > > ;
30
+ type CallbackObject = Record < ValidCallbackTriggers , CallbackTriggerObject > ;
31
+ const initialCallbacks : CallbackObject = Object . values ( CALLBACKS_TRIGGERS ) . reduce ( ( callbacks , x ) => {
32
+ callbacks [ x ] = { } ;
33
+ return callbacks ;
34
+ } , { } as Partial < CallbackObject > ) as CallbackObject ;
26
35
27
36
export const useSimulator = ( ) => {
28
37
const state = useRef ( STATE . IDLE ) ;
29
38
const error = useRef ( "" ) ;
30
39
const [ exitCode , setExitCode ] = useState ( "" ) ;
31
40
const [ code , setCode ] = useState ( "" ) ;
32
41
33
- const timerId = useRef ( null ) ;
42
+ const timerId = useRef < number | null > ( null ) ;
34
43
const [ instructionDelay , setInstructionDelay ] = useState ( 5 ) ;
35
44
const callbacks = useRef ( initialCallbacks ) ;
36
45
37
46
//Still kind of a hack
38
- const [ , forceUpdate ] = useReducer ( ( ) => Date . now ( ) ) ;
47
+ const [ , forceUpdate ] = useReducer ( ( ) => Date . now ( ) , 0 ) ;
39
48
40
- const setState = ( newState ) => {
49
+ const setState = useCallback ( ( newState : STATE ) => {
41
50
state . current = newState ;
42
51
forceUpdate ( ) ;
43
- } ;
52
+ } , [ ] ) ;
44
53
45
- const setError = ( newError ) => {
54
+ const setError = useCallback ( ( newError : string ) => {
46
55
error . current = newError ;
47
56
forceUpdate ( ) ;
48
- } ;
57
+ } , [ ] ) ;
49
58
50
- const registerCallback = ( trigger , type , callback ) => {
59
+ const registerCallback = ( trigger : ValidCallbackTriggers , type : ValidCallbackTypes , callback : ( ) => unknown ) => {
51
60
callbacks . current [ trigger ] [ type ] = callback ;
52
61
} ;
53
62
54
- const callStepCallbacks = ( ) => {
63
+ const callStepCallbacks = useCallback ( ( ) => {
55
64
Object . values ( callbacks . current [ CALLBACKS_TRIGGERS . STEP ] ) . map ( callback => callback ( ) ) ;
56
- } ;
65
+ } , [ callbacks ] ) ;
57
66
58
- const callResetCallbacks = ( ) => {
67
+ const callResetCallbacks = useCallback ( ( ) => {
59
68
Object . values ( callbacks . current [ CALLBACKS_TRIGGERS . RESET ] ) . map ( callback => callback ( ) ) ;
60
- } ;
69
+ } , [ callbacks ] ) ;
61
70
62
- const haltExecution = ( newState ) => {
71
+ const haltExecution = useCallback ( ( newState : STATE ) => {
63
72
setState ( newState ?? STATE . STOPPED ) ;
64
73
if ( timerId . current !== null ) {
65
74
clearTimeout ( timerId . current ) ;
66
75
timerId . current = null ;
67
76
}
68
- } ;
77
+ } , [ timerId ] ) ;
69
78
70
79
const isError = ( ) => {
71
80
return error . current !== "" ;
@@ -138,20 +147,20 @@ export const useSimulator = () => {
138
147
} , [ checkProgramCompletion , handleStepCall , load , reset , state ] ) ;
139
148
140
149
const stepBack = useCallback ( async ( ) => {
141
- if ( state . current > STATE . RUNNING || state . current == STATE . AWAITING ) {
150
+ if ( state . current > STATE . RUNNING ) {
142
151
console . log ( state . current ) ;
143
152
RUST . STEP_BACK ( { } )
144
- . catch ( ( error ) => {
145
- setError ( error ) ;
146
- setState ( STATE . STOPPED )
147
- } )
148
- . finally ( ( ) => {
149
- callStepCallbacks ( ) ;
150
- } )
153
+ . catch ( ( error ) => {
154
+ setError ( error ) ;
155
+ setState ( STATE . STOPPED ) ;
156
+ } )
157
+ . finally ( ( ) => {
158
+ callStepCallbacks ( ) ;
159
+ } ) ;
151
160
152
161
}
153
162
}
154
- , [ setError , setState , callStepCallbacks ] )
163
+ , [ setError , setState , callStepCallbacks ] ) ;
155
164
156
165
const recursiveStep = useCallback ( async ( ) => {
157
166
if ( state . current === STATE . STOPPED ) {
@@ -160,6 +169,8 @@ export const useSimulator = () => {
160
169
checkProgramCompletion ( ) . then ( async completed => {
161
170
if ( ! completed && state . current === STATE . RUNNING ) {
162
171
handleStepCall ( ) . then ( ( ) => {
172
+ // @ts -expect-error -- It assumes that setTimeout returns a NodeJS.Timeout object,
173
+ // which does not exist in the browser
163
174
timerId . current = setTimeout ( recursiveStep , instructionDelay ) ;
164
175
} ) . catch ( ( e ) => {
165
176
timerId . current = null ;
0 commit comments