openigtlink_rust/protocol/
extended_header.rs1use crate::error::{IgtlError, Result};
7use bytes::{Buf, BufMut};
8
9#[derive(Debug, Clone, PartialEq, Eq)]
25pub struct ExtendedHeader {
26 pub extended_header_size: u16,
30
31 pub metadata_header_size: u16,
34
35 pub metadata_size: u32,
38
39 pub message_id: u32,
45
46 pub additional_fields: Vec<u8>,
49}
50
51impl ExtendedHeader {
52 pub const MIN_SIZE: usize = 12;
54
55 pub fn new() -> Self {
65 ExtendedHeader {
66 extended_header_size: Self::MIN_SIZE as u16,
67 metadata_header_size: 0,
68 metadata_size: 0,
69 message_id: 0,
70 additional_fields: Vec::new(),
71 }
72 }
73
74 pub fn with_metadata(metadata_count: u16, metadata_size: u32) -> Self {
83 ExtendedHeader {
84 extended_header_size: Self::MIN_SIZE as u16,
85 metadata_header_size: metadata_count,
86 metadata_size,
87 message_id: 0,
88 additional_fields: Vec::new(),
89 }
90 }
91
92 pub fn with_message_id(message_id: u32) -> Self {
100 ExtendedHeader {
101 extended_header_size: Self::MIN_SIZE as u16,
102 metadata_header_size: 0,
103 metadata_size: 0,
104 message_id,
105 additional_fields: Vec::new(),
106 }
107 }
108
109 pub fn set_additional_fields(&mut self, data: Vec<u8>) {
117 self.extended_header_size = (Self::MIN_SIZE + data.len()) as u16;
118 self.additional_fields = data;
119 }
120
121 pub fn encode(&self) -> Vec<u8> {
126 let mut buf = Vec::with_capacity(self.extended_header_size as usize);
127
128 buf.put_u16(self.extended_header_size);
130
131 buf.put_u16(self.metadata_header_size);
133
134 buf.put_u32(self.metadata_size);
136
137 buf.put_u32(self.message_id);
139
140 buf.extend_from_slice(&self.additional_fields);
142
143 buf
144 }
145
146 pub fn decode(data: &[u8]) -> Result<Self> {
158 if data.len() < Self::MIN_SIZE {
159 return Err(IgtlError::InvalidSize {
160 expected: Self::MIN_SIZE,
161 actual: data.len(),
162 });
163 }
164
165 let mut cursor = std::io::Cursor::new(data);
166
167 let extended_header_size = cursor.get_u16();
169
170 if (extended_header_size as usize) < Self::MIN_SIZE {
171 return Err(IgtlError::InvalidHeader(format!(
172 "Extended header size {} is less than minimum {}",
173 extended_header_size,
174 Self::MIN_SIZE
175 )));
176 }
177
178 if (extended_header_size as usize) > data.len() {
179 return Err(IgtlError::InvalidSize {
180 expected: extended_header_size as usize,
181 actual: data.len(),
182 });
183 }
184
185 let metadata_header_size = cursor.get_u16();
187
188 let metadata_size = cursor.get_u32();
190
191 let message_id = cursor.get_u32();
193
194 let additional_size = extended_header_size as usize - Self::MIN_SIZE;
196 let mut additional_fields = vec![0u8; additional_size];
197 if additional_size > 0 {
198 cursor.copy_to_slice(&mut additional_fields);
199 }
200
201 Ok(ExtendedHeader {
202 extended_header_size,
203 metadata_header_size,
204 metadata_size,
205 message_id,
206 additional_fields,
207 })
208 }
209
210 pub fn size(&self) -> usize {
212 self.extended_header_size as usize
213 }
214
215 pub fn has_metadata(&self) -> bool {
217 self.metadata_size > 0
218 }
219
220 pub fn get_metadata_size(&self) -> usize {
222 self.metadata_size as usize
223 }
224
225 pub fn get_metadata_header_size(&self) -> usize {
227 self.metadata_header_size as usize
228 }
229
230 #[deprecated(
232 note = "Use get_metadata_header_size() instead - metadata_header_size is size in bytes, not count"
233 )]
234 pub fn get_metadata_count(&self) -> usize {
235 self.metadata_header_size as usize
236 }
237
238 pub fn get_message_id(&self) -> u32 {
240 self.message_id
241 }
242}
243
244impl Default for ExtendedHeader {
245 fn default() -> Self {
246 Self::new()
247 }
248}
249
250#[cfg(test)]
251mod tests {
252 use super::*;
253
254 #[test]
255 fn test_new_extended_header() {
256 let ext_header = ExtendedHeader::new();
257 assert_eq!(ext_header.extended_header_size, 12);
258 assert_eq!(ext_header.metadata_header_size, 0);
259 assert_eq!(ext_header.metadata_size, 0);
260 assert_eq!(ext_header.message_id, 0);
261 assert!(ext_header.additional_fields.is_empty());
262 }
263
264 #[test]
265 fn test_with_metadata() {
266 let ext_header = ExtendedHeader::with_metadata(5, 128);
267 assert_eq!(ext_header.metadata_header_size, 5);
268 assert_eq!(ext_header.metadata_size, 128);
269 assert!(ext_header.has_metadata());
270 assert_eq!(ext_header.get_metadata_header_size(), 5);
271 assert_eq!(ext_header.get_metadata_size(), 128);
272 }
273
274 #[test]
275 fn test_with_message_id() {
276 let ext_header = ExtendedHeader::with_message_id(12345);
277 assert_eq!(ext_header.message_id, 12345);
278 assert_eq!(ext_header.get_message_id(), 12345);
279 }
280
281 #[test]
282 fn test_encode_decode_roundtrip() {
283 let original = ExtendedHeader {
284 extended_header_size: 12,
285 metadata_header_size: 3,
286 metadata_size: 256,
287 message_id: 98765,
288 additional_fields: Vec::new(),
289 };
290
291 let encoded = original.encode();
292 assert_eq!(encoded.len(), 12);
293
294 let decoded = ExtendedHeader::decode(&encoded).unwrap();
295 assert_eq!(decoded, original);
296 }
297
298 #[test]
299 fn test_encode_decode_with_additional_fields() {
300 let mut original = ExtendedHeader::new();
301 original.set_additional_fields(vec![0xAA, 0xBB, 0xCC, 0xDD]);
302
303 assert_eq!(original.extended_header_size, 16); let encoded = original.encode();
306 assert_eq!(encoded.len(), 16);
307
308 let decoded = ExtendedHeader::decode(&encoded).unwrap();
309 assert_eq!(decoded, original);
310 assert_eq!(decoded.additional_fields, vec![0xAA, 0xBB, 0xCC, 0xDD]);
311 }
312
313 #[test]
314 fn test_decode_too_small() {
315 let data = vec![0u8; 10];
316 let result = ExtendedHeader::decode(&data);
317 assert!(matches!(result, Err(IgtlError::InvalidSize { .. })));
318 }
319
320 #[test]
321 fn test_decode_invalid_size() {
322 let mut data = vec![0u8; 12];
323 data[0] = 0;
325 data[1] = 8;
326
327 let result = ExtendedHeader::decode(&data);
328 assert!(matches!(result, Err(IgtlError::InvalidHeader(_))));
329 }
330
331 #[test]
332 fn test_size_methods() {
333 let ext_header = ExtendedHeader::with_metadata(2, 64);
334 assert_eq!(ext_header.size(), 12);
335 assert!(ext_header.has_metadata());
336 }
337
338 #[test]
339 fn test_big_endian_encoding() {
340 let ext_header = ExtendedHeader {
341 extended_header_size: 0x1234,
342 metadata_header_size: 0x5678,
343 metadata_size: 0x9ABCDEF0,
344 message_id: 0x11223344,
345 additional_fields: Vec::new(),
346 };
347
348 let encoded = ext_header.encode();
349
350 assert_eq!(encoded[0], 0x12);
352 assert_eq!(encoded[1], 0x34);
353 assert_eq!(encoded[2], 0x56);
354 assert_eq!(encoded[3], 0x78);
355 assert_eq!(encoded[4], 0x9A);
356 assert_eq!(encoded[5], 0xBC);
357 assert_eq!(encoded[6], 0xDE);
358 assert_eq!(encoded[7], 0xF0);
359 assert_eq!(encoded[8], 0x11);
360 assert_eq!(encoded[9], 0x22);
361 assert_eq!(encoded[10], 0x33);
362 assert_eq!(encoded[11], 0x44);
363 }
364
365 #[test]
366 fn test_real_world_example() {
367 let data = vec![
369 0x00, 0x0C, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, ];
374
375 let ext_header = ExtendedHeader::decode(&data).unwrap();
376 assert_eq!(ext_header.extended_header_size, 12);
377 assert_eq!(ext_header.metadata_header_size, 1);
378 assert_eq!(ext_header.metadata_size, 20);
379 assert_eq!(ext_header.message_id, 0);
380 assert!(ext_header.has_metadata());
381 }
382}