code wiki / (root) / nx_state_machine.nx

nx_state_machine.nx source

↩ module page · 119 lines · 4492 B

1// nx_state_machine.nx -- generic state-transition primitive. 2// 3// Many primitives have sealed-state-machine shapes (nx_cell.state, 4// nx_yield.state, nx_treaty.state, nx_recovery.phase). This is the 5// shared substrate for that pattern: caller declares N states + a 6// transition table, gets atomic transitions + queries. 7// 8// Composes with anything that has lifecycle states; useful for app- 9// level state machines beyond the substrate primitives. 10 11import "nx_syscalls.nx" 12import "nx_tier.nx" 13 14const NX_SM_OK: nx_int = 0 15const NX_SM_ERR_BAD_FROM: nx_int = 1 16const NX_SM_ERR_BAD_TO: nx_int = 2 17const NX_SM_ERR_BAD_TRANSITION: nx_int = 3 18const NX_SM_ERR_TABLE_FULL: nx_int = 4 19 20// ===== Struct: NxStateMachine ====================================== 21// 22// states_count: how many sealed states this machine has (1..63 typical) 23// transition_table: bitmask matrix; bit (from*states_count + to) is 24// set if the transition is allowed 25// current_state: where we are now 26// transition_count: monotonic across all moves 27 28struct NxStateMachine { 29 states_count: nx_int, 30 current_state: nx_int, 31 initial_state: nx_int, 32 transition_count: nx_int, 33 transition_table: *u8, // states_count * states_count bytes (1 byte per cell) 34 table_bytes: nx_size, 35} 36 37func nx_state_machine_new(states_count: nx_int, initial_state: nx_int) -> *NxStateMachine { 38 if states_count <= 0 { return (0 as i64) as *NxStateMachine } 39 if states_count > 64 { return (0 as i64) as *NxStateMachine } 40 if initial_state < 0 { return (0 as i64) as *NxStateMachine } 41 if initial_state >= states_count { return (0 as i64) as *NxStateMachine } 42 let sm: *NxStateMachine = (sys_mmap(40)) as *NxStateMachine 43 sm.states_count = states_count 44 sm.current_state = initial_state 45 sm.initial_state = initial_state 46 sm.transition_count = 0 47 sm.table_bytes = (states_count as nx_size) * (states_count as nx_size) 48 sm.transition_table = (sys_mmap(sm.table_bytes)) as *u8 49 // Initialize: all transitions disallowed by default 50 var i: nx_size = 0 51 while i < sm.table_bytes { 52 sm.transition_table[i] = 0 as u8 53 i = i + 1 54 } 55 // Self-transition always allowed (idempotent) 56 var k: nx_int = 0 57 while k < states_count { 58 let idx: nx_size = (k as nx_size) * (states_count as nx_size) + (k as nx_size) 59 sm.transition_table[idx] = 1 as u8 60 k = k + 1 61 } 62 return sm 63} 64 65// ===== nx_state_machine_allow ====================================== 66// 67// Allow transition from -> to. Caller builds the table once at 68// instantiation; runtime transitions just consult it. 69 70func nx_state_machine_allow(sm: *NxStateMachine, from: nx_int, to: nx_int) -> nx_int { 71 if from < 0 { return NX_SM_ERR_BAD_FROM } 72 if from >= sm.states_count { return NX_SM_ERR_BAD_FROM } 73 if to < 0 { return NX_SM_ERR_BAD_TO } 74 if to >= sm.states_count { return NX_SM_ERR_BAD_TO } 75 let idx: nx_size = (from as nx_size) * (sm.states_count as nx_size) + (to as nx_size) 76 sm.transition_table[idx] = 1 as u8 77 return NX_SM_OK 78} 79 80// ===== nx_state_machine_is_allowed ================================= 81 82func nx_state_machine_is_allowed(sm: *NxStateMachine, from: nx_int, to: nx_int) -> nx_int { 83 if from < 0 { return 0 } 84 if from >= sm.states_count { return 0 } 85 if to < 0 { return 0 } 86 if to >= sm.states_count { return 0 } 87 let idx: nx_size = (from as nx_size) * (sm.states_count as nx_size) + (to as nx_size) 88 if (sm.transition_table[idx] as i64) & 255 != 0 { return 1 } 89 return 0 90} 91 92// ===== nx_state_machine_transition ================================ 93// 94// Atomic state change. Returns NX_SM_OK or NX_SM_ERR_BAD_TRANSITION. 95// current_state -> to_state must be in the allow-table. 96 97func nx_state_machine_transition(sm: *NxStateMachine, to_state: nx_int) -> nx_int { 98 if nx_state_machine_is_allowed(sm, sm.current_state, to_state) == 0 { 99 return NX_SM_ERR_BAD_TRANSITION 100 } 101 sm.current_state = to_state 102 sm.transition_count = sm.transition_count + 1 103 return NX_SM_OK 104} 105 106func nx_state_machine_current(sm: *NxStateMachine) -> nx_int { 107 return sm.current_state 108} 109 110func nx_state_machine_transitions(sm: *NxStateMachine) -> nx_int { 111 return sm.transition_count 112} 113 114// ===== nx_state_machine_reset ====================================== 115 116func nx_state_machine_reset(sm: *NxStateMachine) -> nx_int { 117 sm.current_state = sm.initial_state 118 return NX_SM_OK 119}