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 pub const fn from_u32(value: u32) -> Self {
216 match value {
217 0 => Self::None,
218 1 => Self::InputOverflow,
219 2 => Self::OutputOverflow,
220 3 => Self::InvalidMessage,
221 4 => Self::AllocationFailed,
222 5 => Self::SerializationError,
223 6 => Self::Timeout,
224 _ => Self::InternalError,
225 }
226 }
227}
228
229#[cfg(test)]
230mod tests {
231 use super::*;
232
233 #[test]
234 fn test_control_block_size() {
235 assert_eq!(std::mem::size_of::<ControlBlock>(), 128);
236 }
237
238 #[test]
239 fn test_control_block_alignment() {
240 assert_eq!(std::mem::align_of::<ControlBlock>(), 128);
241 }
242
243 #[test]
244 fn test_queue_size_calculation() {
245 let mut cb = ControlBlock::with_capacities(1024, 1024);
246
247 cb.input_head = 10;
248 cb.input_tail = 5;
249 assert_eq!(cb.input_queue_size(), 5);
250
251 cb.input_head = 2;
253 cb.input_tail = u64::MAX - 3;
254 assert_eq!(cb.input_queue_size(), 6);
255 }
256
257 #[test]
258 fn test_queue_full_empty() {
259 let mut cb = ControlBlock::with_capacities(16, 16);
260
261 assert!(cb.input_queue_empty());
262 assert!(!cb.input_queue_full());
263
264 cb.input_head = 16;
265 cb.input_tail = 0;
266 assert!(!cb.input_queue_empty());
267 assert!(cb.input_queue_full());
268 }
269
270 #[test]
271 fn test_lifecycle_flags() {
272 let mut cb = ControlBlock::new();
273
274 assert!(!cb.is_active());
275 assert!(!cb.should_terminate());
276 assert!(!cb.has_terminated());
277
278 cb.is_active = 1;
279 assert!(cb.is_active());
280
281 cb.should_terminate = 1;
282 assert!(cb.should_terminate());
283
284 cb.has_terminated = 1;
285 assert!(cb.has_terminated());
286 }
287}