1111// SPDX-License-Identifier: Apache-2.0
1212// *******************************************************************************
1313
14- #[ cfg( not( loom) ) ]
15- use core:: sync:: atomic:: { AtomicU64 , Ordering } ;
16- #[ cfg( loom) ]
17- use loom:: sync:: atomic:: { AtomicU64 , Ordering } ;
14+ use crate :: common:: { AtomicU64 , Ordering } ;
15+ use crate :: logic:: logic_monitor:: OK_STATE ;
16+ use crate :: logic:: LogicEvaluationError ;
1817
1918/// Snapshot of a logic state.
2019/// Layout (u64) = | current state index: 56 bits | monitor status: u8 |
@@ -53,12 +52,17 @@ impl LogicStateSnapshot {
5352 /// Monitor status.
5453 /// - zero if healthy.
5554 /// - `LogicEvaluationError` if not.
56- pub fn monitor_status ( & self ) -> u8 {
57- ( self . 0 & STATUS_MASK ) as u8
55+ pub fn monitor_status ( & self ) -> Result < ( ) , LogicEvaluationError > {
56+ let value = ( self . 0 & STATUS_MASK ) as u8 ;
57+ if value == OK_STATE {
58+ Ok ( ( ) )
59+ } else {
60+ Err ( value. try_into ( ) . map_err ( |_| LogicEvaluationError :: UnmappedError ) ?)
61+ }
5862 }
5963
6064 /// Set monitor status.
61- pub fn set_monitor_status ( & mut self , value : u8 ) {
65+ pub fn set_monitor_status ( & mut self , value : LogicEvaluationError ) {
6266 self . 0 = ( value as u64 ) | ( self . 0 & !STATUS_MASK ) ;
6367 }
6468}
@@ -85,26 +89,16 @@ impl LogicState {
8589 LogicStateSnapshot :: from ( self . 0 . load ( Ordering :: Acquire ) )
8690 }
8791
88- /// Update the logic state using the provided closure.
89- /// Closure receives the current state and should return an [`Option`] containing a new state.
90- /// If [`None`] is returned then the state was not updated.
91- pub fn update < F : FnMut ( LogicStateSnapshot ) -> Option < LogicStateSnapshot > > (
92- & self ,
93- mut f : F ,
94- ) -> Result < LogicStateSnapshot , LogicStateSnapshot > {
95- self . 0
96- . fetch_update ( Ordering :: AcqRel , Ordering :: Acquire , |prev| {
97- let snapshot = LogicStateSnapshot :: from ( prev) ;
98- f ( snapshot) . map ( |new_snapshot : LogicStateSnapshot | new_snapshot. as_u64 ( ) )
99- } )
100- . map ( LogicStateSnapshot :: from)
101- . map_err ( LogicStateSnapshot :: from)
92+ /// Store a new [`LogicStateSnapshot`] and return the previous one.
93+ pub fn swap ( & self , new : LogicStateSnapshot ) -> LogicStateSnapshot {
94+ self . 0 . swap ( new. as_u64 ( ) , Ordering :: AcqRel ) . into ( )
10295 }
10396}
10497
10598#[ cfg( all( test, not( loom) ) ) ]
10699mod tests {
107100 use crate :: logic:: logic_state:: { LogicState , LogicStateSnapshot } ;
101+ use crate :: logic:: LogicEvaluationError ;
108102 use core:: sync:: atomic:: Ordering ;
109103
110104 #[ test]
@@ -114,7 +108,7 @@ mod tests {
114108
115109 assert_eq ! ( state. as_u64( ) , ( initial_state_index as u64 ) << u8 :: BITS ) ;
116110 assert_eq ! ( state. current_state_index( ) , initial_state_index) ;
117- assert_eq ! ( state. monitor_status( ) , 0 ) ;
111+ assert ! ( state. monitor_status( ) . is_ok ( ) ) ;
118112 }
119113
120114 #[ test]
@@ -123,16 +117,18 @@ mod tests {
123117
124118 assert_eq ! ( state. as_u64( ) , 0x00 ) ;
125119 assert_eq ! ( state. current_state_index( ) , 0 ) ;
126- assert_eq ! ( state. monitor_status( ) , 0 ) ;
120+ assert ! ( state. monitor_status( ) . is_ok ( ) ) ;
127121 }
128122
129123 #[ test]
130124 fn snapshot_from_u64_valid ( ) {
131- let state = LogicStateSnapshot :: from ( 0xDEADBEEF_DEADBEEF ) ;
125+ let state = LogicStateSnapshot :: from ( 0xDEADBEEF_DEADBE01 ) ;
132126
133- assert_eq ! ( state. as_u64( ) , 0xDEADBEEF_DEADBEEF ) ;
134- assert_eq ! ( state. current_state_index( ) , 0xDEADBEEF_DEADBEEF >> u8 :: BITS ) ;
135- assert_eq ! ( state. monitor_status( ) , 0xEF ) ;
127+ assert_eq ! ( state. as_u64( ) , 0xDEADBEEF_DEADBE01 ) ;
128+ assert_eq ! ( state. current_state_index( ) , 0xDEADBEEF_DEADBE01 >> u8 :: BITS ) ;
129+ assert ! ( state
130+ . monitor_status( )
131+ . is_err_and( |e| e == LogicEvaluationError :: InvalidState ) ) ;
136132 }
137133
138134 #[ test]
@@ -141,18 +137,20 @@ mod tests {
141137
142138 assert_eq ! ( state. as_u64( ) , u64 :: MAX ) ;
143139 assert_eq ! ( state. current_state_index( ) , ( u64 :: MAX >> u8 :: BITS ) as usize ) ;
144- assert_eq ! ( state. monitor_status( ) , u8 :: MAX ) ;
140+ assert ! ( state
141+ . monitor_status( )
142+ . is_err_and( |e| e == LogicEvaluationError :: UnmappedError ) ) ;
145143 }
146144
147145 #[ test]
148146 fn snapshot_set_current_state_index_valid ( ) {
149- let mut state = LogicStateSnapshot :: from ( 0xDEADBEEF_DEADBEEF ) ;
147+ let mut state = LogicStateSnapshot :: from ( 0xDEADBEEF_DEADBE00 ) ;
150148 state. set_current_state_index ( 0x00CAFEBA_DCAFEBAD ) ;
151149
152150 assert_eq ! ( state. current_state_index( ) , 0x00CAFEBA_DCAFEBAD ) ;
153151
154152 // Check other parameters unchanged.
155- assert_eq ! ( state. monitor_status( ) , 0xEF ) ;
153+ assert ! ( state. monitor_status( ) . is_ok ( ) ) ;
156154 }
157155
158156 #[ test]
@@ -165,9 +163,11 @@ mod tests {
165163 #[ test]
166164 fn snapshot_set_monitor_status_valid ( ) {
167165 let mut state = LogicStateSnapshot :: from ( 0xDEADBEEF_DEADBEEF ) ;
168- state. set_monitor_status ( 0xFA ) ;
166+ state. set_monitor_status ( LogicEvaluationError :: InvalidTransition ) ;
169167
170- assert_eq ! ( state. monitor_status( ) , 0xFA ) ;
168+ assert ! ( state
169+ . monitor_status( )
170+ . is_err_and( |e| e == LogicEvaluationError :: InvalidTransition ) ) ;
171171
172172 // Check other parameters unchanged.
173173 assert_eq ! ( state. current_state_index( ) , 0xDEADBEEF_DEADBEEF >> u8 :: BITS ) ;
@@ -191,35 +191,19 @@ mod tests {
191191 }
192192
193193 #[ test]
194- fn state_update_some ( ) {
194+ fn state_swap ( ) {
195195 let state = LogicState :: new ( 0 ) ;
196- let _ = state. update ( |prev_snapshot| {
197- // Make sure state is as expected.
198- assert_eq ! ( prev_snapshot. as_u64( ) , 0x00 ) ;
199- assert_eq ! ( prev_snapshot. current_state_index( ) , 0 ) ;
200- assert_eq ! ( prev_snapshot. monitor_status( ) , 0 ) ;
201-
202- Some ( LogicStateSnapshot :: from ( 0xDEADBEEF_DEADBEEF ) )
203- } ) ;
204-
205- let _ = state. update ( |prev_snapshot| {
206- // Make sure state is as expected.
207- assert_eq ! ( prev_snapshot. as_u64( ) , 0xDEADBEEF_DEADBEEF ) ;
208- assert_eq ! ( prev_snapshot. current_state_index( ) , 0xDEADBEEF_DEADBEEF >> u8 :: BITS ) ;
209- assert_eq ! ( prev_snapshot. monitor_status( ) , 0xEF ) ;
210-
211- Some ( LogicStateSnapshot :: from ( 0 ) )
212- } ) ;
213-
214- assert_eq ! ( state. snapshot( ) . as_u64( ) , 0 ) ;
215- }
216-
217- #[ test]
218- fn state_update_none ( ) {
219- let state = LogicState :: new ( 4321 ) ;
220- let _ = state. update ( |_| Some ( LogicStateSnapshot :: from ( 0xDEADBEEF_DEADBEEF ) ) ) ;
221- let _ = state. update ( |_| None ) ;
222-
223- assert_eq ! ( state. snapshot( ) . as_u64( ) , 0xDEADBEEF_DEADBEEF ) ;
196+ let prev_snapshot = state. swap ( LogicStateSnapshot :: from ( 0xDEADBEEF_DEADBE02 ) ) ;
197+
198+ assert_eq ! ( prev_snapshot. as_u64( ) , 0x00 ) ;
199+ assert_eq ! ( prev_snapshot. current_state_index( ) , 0 ) ;
200+ assert ! ( prev_snapshot. monitor_status( ) . is_ok( ) ) ;
201+
202+ let curr_snapshot = state. snapshot ( ) ;
203+ assert_eq ! ( curr_snapshot. as_u64( ) , 0xDEADBEEF_DEADBE02 ) ;
204+ assert_eq ! ( curr_snapshot. current_state_index( ) , 0xDEADBEEF_DEADBE02 >> u8 :: BITS ) ;
205+ assert ! ( curr_snapshot
206+ . monitor_status( )
207+ . is_err_and( |e| e == LogicEvaluationError :: InvalidTransition ) ) ;
224208 }
225209}
0 commit comments