procwire_client/protocol/
header_pool.rs1use super::wire_format::{Header, HEADER_POOL_SIZE, HEADER_SIZE};
30
31pub struct HeaderPool {
36 buffers: [[u8; HEADER_SIZE]; HEADER_POOL_SIZE],
38 index: usize,
40}
41
42impl HeaderPool {
43 #[inline]
45 pub const fn new() -> Self {
46 Self {
47 buffers: [[0u8; HEADER_SIZE]; HEADER_POOL_SIZE],
48 index: 0,
49 }
50 }
51
52 #[inline]
57 pub fn acquire(&mut self) -> &mut [u8; HEADER_SIZE] {
58 let buf = &mut self.buffers[self.index];
59 self.index = (self.index + 1) % HEADER_POOL_SIZE;
60 buf
61 }
62
63 #[inline]
67 pub fn encode(&mut self, header: &Header) -> &[u8; HEADER_SIZE] {
68 let buf = self.acquire();
69 header.encode_into(buf);
70 buf
71 }
72
73 #[inline]
75 pub fn current_index(&self) -> usize {
76 self.index
77 }
78
79 #[inline]
81 pub fn reset(&mut self) {
82 self.index = 0;
83 }
84}
85
86impl Default for HeaderPool {
87 fn default() -> Self {
88 Self::new()
89 }
90}
91
92thread_local! {
94 static THREAD_LOCAL_POOL: std::cell::RefCell<HeaderPool> =
95 const { std::cell::RefCell::new(HeaderPool::new()) };
96}
97
98#[inline]
106pub fn encode_header_pooled(header: &Header) -> [u8; HEADER_SIZE] {
107 THREAD_LOCAL_POOL.with(|pool| {
108 let mut pool = pool.borrow_mut();
109 let buf = pool.acquire();
110 header.encode_into(buf);
111 *buf
112 })
113}
114
115pub fn with_header_pool<F, R>(f: F) -> R
130where
131 F: FnOnce(&mut HeaderPool) -> R,
132{
133 THREAD_LOCAL_POOL.with(|pool| {
134 let mut pool = pool.borrow_mut();
135 f(&mut pool)
136 })
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142
143 #[test]
144 fn test_pool_creation() {
145 let pool = HeaderPool::new();
146 assert_eq!(pool.current_index(), 0);
147 }
148
149 #[test]
150 fn test_pool_acquire_round_robin() {
151 let mut pool = HeaderPool::new();
152
153 for i in 0..HEADER_POOL_SIZE {
154 let _buf = pool.acquire();
155 assert_eq!(pool.current_index(), (i + 1) % HEADER_POOL_SIZE);
156 }
157
158 assert_eq!(pool.current_index(), 0);
160 }
161
162 #[test]
163 fn test_pool_acquire_returns_different_buffers() {
164 let mut pool = HeaderPool::new();
165
166 let buf1_ptr = pool.acquire().as_ptr();
167 let buf2_ptr = pool.acquire().as_ptr();
168 let buf3_ptr = pool.acquire().as_ptr();
169
170 assert_ne!(buf1_ptr, buf2_ptr);
171 assert_ne!(buf2_ptr, buf3_ptr);
172 assert_ne!(buf1_ptr, buf3_ptr);
173 }
174
175 #[test]
176 fn test_pool_encode() {
177 let mut pool = HeaderPool::new();
178 let header = Header::new(1, 0x03, 42, 100);
179
180 let encoded = pool.encode(&header);
181
182 assert_eq!(&encoded[0..2], &[0x00, 0x01]); assert_eq!(encoded[2], 0x03); assert_eq!(&encoded[3..7], &[0x00, 0x00, 0x00, 0x2A]); assert_eq!(&encoded[7..11], &[0x00, 0x00, 0x00, 0x64]); }
188
189 #[test]
190 fn test_pool_reset() {
191 let mut pool = HeaderPool::new();
192
193 pool.acquire();
194 pool.acquire();
195 pool.acquire();
196 assert_eq!(pool.current_index(), 3);
197
198 pool.reset();
199 assert_eq!(pool.current_index(), 0);
200 }
201
202 #[test]
203 fn test_encode_header_pooled() {
204 let header = Header::new(5, 0x07, 1000, 50);
205
206 let encoded = encode_header_pooled(&header);
207
208 assert_eq!(&encoded[0..2], &[0x00, 0x05]); assert_eq!(encoded[2], 0x07); assert_eq!(&encoded[3..7], &[0x00, 0x00, 0x03, 0xE8]); assert_eq!(&encoded[7..11], &[0x00, 0x00, 0x00, 0x32]); }
213
214 #[test]
215 fn test_with_header_pool() {
216 let header1 = Header::new(1, 0x00, 1, 10);
217 let header2 = Header::new(2, 0x00, 2, 20);
218
219 let (enc1, enc2) = with_header_pool(|pool| {
220 let e1 = *pool.encode(&header1);
221 let e2 = *pool.encode(&header2);
222 (e1, e2)
223 });
224
225 assert_eq!(&enc1[0..2], &[0x00, 0x01]);
227 assert_eq!(&enc2[0..2], &[0x00, 0x02]);
228 }
229
230 #[test]
231 fn test_pool_default() {
232 let pool = HeaderPool::default();
233 assert_eq!(pool.current_index(), 0);
234 }
235
236 #[test]
237 fn test_pool_buffers_are_mutable() {
238 let mut pool = HeaderPool::new();
239
240 let buf = pool.acquire();
241 buf[0] = 0xFF;
242 buf[10] = 0xAA;
243
244 assert_eq!(buf[0], 0xFF);
246 assert_eq!(buf[10], 0xAA);
247 }
248
249 #[test]
250 fn test_pool_wrap_around_overwrites() {
251 let mut pool = HeaderPool::new();
252
253 {
255 let buf = pool.acquire();
256 for b in buf.iter_mut() {
257 *b = 0xAB;
258 }
259 }
260
261 for _ in 0..(HEADER_POOL_SIZE - 1) {
263 pool.acquire();
264 }
265
266 let buf = pool.acquire();
268 assert_eq!(buf[0], 0xAB);
270 }
271}