1use crate::hlc::HlcState;
7
8#[derive(Debug, Clone, Copy)]
20#[repr(C, align(128))]
21pub struct ControlBlock {
22 pub is_active: u32,
25 pub should_terminate: u32,
27 pub has_terminated: u32,
29 pub _pad1: u32,
31
32 pub messages_processed: u64,
35 pub messages_in_flight: u64,
37
38 pub input_head: u64,
41 pub input_tail: u64,
43 pub output_head: u64,
45 pub output_tail: u64,
47
48 pub input_capacity: u32,
51 pub output_capacity: u32,
53 pub input_mask: u32,
55 pub output_mask: u32,
57
58 pub hlc_state: HlcState,
61
62 pub last_error: u32,
65 pub error_count: u32,
67
68 pub _reserved: [u8; 24],
71}
72
73const _: () = assert!(std::mem::size_of::<ControlBlock>() == 128);
75
76impl ControlBlock {
77 pub const fn new() -> Self {
79 Self {
80 is_active: 0,
81 should_terminate: 0,
82 has_terminated: 0,
83 _pad1: 0,
84 messages_processed: 0,
85 messages_in_flight: 0,
86 input_head: 0,
87 input_tail: 0,
88 output_head: 0,
89 output_tail: 0,
90 input_capacity: 0,
91 output_capacity: 0,
92 input_mask: 0,
93 output_mask: 0,
94 hlc_state: HlcState::new(0, 0),
95 last_error: 0,
96 error_count: 0,
97 _reserved: [0; 24],
98 }
99 }
100
101 pub fn with_capacities(input_capacity: u32, output_capacity: u32) -> Self {
105 debug_assert!(input_capacity.is_power_of_two());
106 debug_assert!(output_capacity.is_power_of_two());
107
108 Self {
109 is_active: 0,
110 should_terminate: 0,
111 has_terminated: 0,
112 _pad1: 0,
113 messages_processed: 0,
114 messages_in_flight: 0,
115 input_head: 0,
116 input_tail: 0,
117 output_head: 0,
118 output_tail: 0,
119 input_capacity,
120 output_capacity,
121 input_mask: input_capacity.saturating_sub(1),
122 output_mask: output_capacity.saturating_sub(1),
123 hlc_state: HlcState::new(0, 0),
124 last_error: 0,
125 error_count: 0,
126 _reserved: [0; 24],
127 }
128 }
129
130 #[inline]
132 pub fn is_active(&self) -> bool {
133 self.is_active != 0
134 }
135
136 #[inline]
138 pub fn should_terminate(&self) -> bool {
139 self.should_terminate != 0
140 }
141
142 #[inline]
144 pub fn has_terminated(&self) -> bool {
145 self.has_terminated != 0
146 }
147
148 #[inline]
150 pub fn input_queue_size(&self) -> u64 {
151 self.input_head.wrapping_sub(self.input_tail)
152 }
153
154 #[inline]
156 pub fn output_queue_size(&self) -> u64 {
157 self.output_head.wrapping_sub(self.output_tail)
158 }
159
160 #[inline]
162 pub fn input_queue_empty(&self) -> bool {
163 self.input_head == self.input_tail
164 }
165
166 #[inline]
168 pub fn output_queue_empty(&self) -> bool {
169 self.output_head == self.output_tail
170 }
171
172 #[inline]
174 pub fn input_queue_full(&self) -> bool {
175 self.input_queue_size() >= self.input_capacity as u64
176 }
177
178 #[inline]
180 pub fn output_queue_full(&self) -> bool {
181 self.output_queue_size() >= self.output_capacity as u64
182 }
183}
184
185impl Default for ControlBlock {
186 fn default() -> Self {
187 Self::new()
188 }
189}
190
191#[derive(Debug, Clone, Copy, PartialEq, Eq)]
193#[repr(u32)]
194pub enum ControlError {
195 None = 0,
197 InputOverflow = 1,
199 OutputOverflow = 2,
201 InvalidMessage = 3,
203 AllocationFailed = 4,
205 SerializationError = 5,
207 Timeout = 6,
209 InternalError = 7,
211}
212
213impl ControlError {
214 #[inline]
216 pub const fn from_u32(value: u32) -> Self {
217 match value {
218 0 => Self::None,
219 1 => Self::InputOverflow,
220 2 => Self::OutputOverflow,
221 3 => Self::InvalidMessage,
222 4 => Self::AllocationFailed,
223 5 => Self::SerializationError,
224 6 => Self::Timeout,
225 _ => Self::InternalError,
226 }
227 }
228}
229
230#[cfg(test)]
231mod tests {
232 use super::*;
233
234 #[test]
235 fn test_control_block_size() {
236 assert_eq!(std::mem::size_of::<ControlBlock>(), 128);
237 }
238
239 #[test]
240 fn test_control_block_alignment() {
241 assert_eq!(std::mem::align_of::<ControlBlock>(), 128);
242 }
243
244 #[test]
245 fn test_queue_size_calculation() {
246 let mut cb = ControlBlock::with_capacities(1024, 1024);
247
248 cb.input_head = 10;
249 cb.input_tail = 5;
250 assert_eq!(cb.input_queue_size(), 5);
251
252 cb.input_head = 2;
254 cb.input_tail = u64::MAX - 3;
255 assert_eq!(cb.input_queue_size(), 6);
256 }
257
258 #[test]
259 fn test_queue_full_empty() {
260 let mut cb = ControlBlock::with_capacities(16, 16);
261
262 assert!(cb.input_queue_empty());
263 assert!(!cb.input_queue_full());
264
265 cb.input_head = 16;
266 cb.input_tail = 0;
267 assert!(!cb.input_queue_empty());
268 assert!(cb.input_queue_full());
269 }
270
271 #[test]
272 fn test_lifecycle_flags() {
273 let mut cb = ControlBlock::new();
274
275 assert!(!cb.is_active());
276 assert!(!cb.should_terminate());
277 assert!(!cb.has_terminated());
278
279 cb.is_active = 1;
280 assert!(cb.is_active());
281
282 cb.should_terminate = 1;
283 assert!(cb.should_terminate());
284
285 cb.has_terminated = 1;
286 assert!(cb.has_terminated());
287 }
288}