openigtlink_rust/protocol/types/
imgmeta.rs1use crate::error::{IgtlError, Result};
7use crate::protocol::message::Message;
8use bytes::{Buf, BufMut};
9
10#[derive(Debug, Clone, PartialEq)]
12pub struct ImageMetaElement {
13 pub name: String,
15 pub id: String,
17 pub modality: String,
19 pub patient_name: String,
21 pub patient_id: String,
23 pub timestamp: u64,
25 pub size: [u16; 3],
27 pub scalar_type: u8,
29}
30
31impl ImageMetaElement {
32 pub fn new(
34 name: impl Into<String>,
35 id: impl Into<String>,
36 modality: impl Into<String>,
37 ) -> Self {
38 ImageMetaElement {
39 name: name.into(),
40 id: id.into(),
41 modality: modality.into(),
42 patient_name: String::new(),
43 patient_id: String::new(),
44 timestamp: 0,
45 size: [0, 0, 0],
46 scalar_type: 3, }
48 }
49
50 pub fn with_patient(
52 mut self,
53 patient_name: impl Into<String>,
54 patient_id: impl Into<String>,
55 ) -> Self {
56 self.patient_name = patient_name.into();
57 self.patient_id = patient_id.into();
58 self
59 }
60
61 pub fn with_timestamp(mut self, timestamp: u64) -> Self {
63 self.timestamp = timestamp;
64 self
65 }
66
67 pub fn with_size(mut self, size: [u16; 3]) -> Self {
69 self.size = size;
70 self
71 }
72
73 pub fn with_scalar_type(mut self, scalar_type: u8) -> Self {
75 self.scalar_type = scalar_type;
76 self
77 }
78}
79
80#[derive(Debug, Clone, PartialEq)]
87pub struct ImgMetaMessage {
88 pub images: Vec<ImageMetaElement>,
90}
91
92impl ImgMetaMessage {
93 pub fn new(images: Vec<ImageMetaElement>) -> Self {
95 ImgMetaMessage { images }
96 }
97
98 pub fn empty() -> Self {
100 ImgMetaMessage { images: Vec::new() }
101 }
102
103 pub fn add_image(&mut self, image: ImageMetaElement) {
105 self.images.push(image);
106 }
107
108 pub fn len(&self) -> usize {
110 self.images.len()
111 }
112
113 pub fn is_empty(&self) -> bool {
115 self.images.is_empty()
116 }
117}
118
119impl Message for ImgMetaMessage {
120 fn message_type() -> &'static str {
121 "IMGMETA"
122 }
123
124 fn encode_content(&self) -> Result<Vec<u8>> {
125 let mut buf = Vec::with_capacity(self.images.len() * 260);
126
127 for img in &self.images {
128 let mut name_bytes = [0u8; 64];
130 let name_str = img.name.as_bytes();
131 let copy_len = name_str.len().min(63);
132 name_bytes[..copy_len].copy_from_slice(&name_str[..copy_len]);
133 buf.extend_from_slice(&name_bytes);
134
135 let mut id_bytes = [0u8; 20];
137 let id_str = img.id.as_bytes();
138 let copy_len = id_str.len().min(19);
139 id_bytes[..copy_len].copy_from_slice(&id_str[..copy_len]);
140 buf.extend_from_slice(&id_bytes);
141
142 let mut modality_bytes = [0u8; 32];
144 let modality_str = img.modality.as_bytes();
145 let copy_len = modality_str.len().min(31);
146 modality_bytes[..copy_len].copy_from_slice(&modality_str[..copy_len]);
147 buf.extend_from_slice(&modality_bytes);
148
149 let mut patient_name_bytes = [0u8; 64];
151 let patient_name_str = img.patient_name.as_bytes();
152 let copy_len = patient_name_str.len().min(63);
153 patient_name_bytes[..copy_len].copy_from_slice(&patient_name_str[..copy_len]);
154 buf.extend_from_slice(&patient_name_bytes);
155
156 let mut patient_id_bytes = [0u8; 64];
158 let patient_id_str = img.patient_id.as_bytes();
159 let copy_len = patient_id_str.len().min(63);
160 patient_id_bytes[..copy_len].copy_from_slice(&patient_id_str[..copy_len]);
161 buf.extend_from_slice(&patient_id_bytes);
162
163 buf.put_u64(img.timestamp);
165
166 for &s in &img.size {
168 buf.put_u16(s);
169 }
170
171 buf.put_u8(img.scalar_type);
173
174 buf.put_u8(0);
176 }
177
178 Ok(buf)
179 }
180
181 fn decode_content(mut data: &[u8]) -> Result<Self> {
182 let mut images = Vec::new();
183
184 while data.len() >= 260 {
185 let name_bytes = &data[..64];
187 data.advance(64);
188 let name_len = name_bytes.iter().position(|&b| b == 0).unwrap_or(64);
189 let name = String::from_utf8(name_bytes[..name_len].to_vec())?;
190
191 let id_bytes = &data[..20];
193 data.advance(20);
194 let id_len = id_bytes.iter().position(|&b| b == 0).unwrap_or(20);
195 let id = String::from_utf8(id_bytes[..id_len].to_vec())?;
196
197 let modality_bytes = &data[..32];
199 data.advance(32);
200 let modality_len = modality_bytes.iter().position(|&b| b == 0).unwrap_or(32);
201 let modality = String::from_utf8(modality_bytes[..modality_len].to_vec())?;
202
203 let patient_name_bytes = &data[..64];
205 data.advance(64);
206 let patient_name_len = patient_name_bytes
207 .iter()
208 .position(|&b| b == 0)
209 .unwrap_or(64);
210 let patient_name = String::from_utf8(patient_name_bytes[..patient_name_len].to_vec())?;
211
212 let patient_id_bytes = &data[..64];
214 data.advance(64);
215 let patient_id_len = patient_id_bytes.iter().position(|&b| b == 0).unwrap_or(64);
216 let patient_id = String::from_utf8(patient_id_bytes[..patient_id_len].to_vec())?;
217
218 let timestamp = data.get_u64();
220
221 let size = [data.get_u16(), data.get_u16(), data.get_u16()];
223
224 let scalar_type = data.get_u8();
226
227 let _reserved = data.get_u8();
229
230 images.push(ImageMetaElement {
231 name,
232 id,
233 modality,
234 patient_name,
235 patient_id,
236 timestamp,
237 size,
238 scalar_type,
239 });
240 }
241
242 if !data.is_empty() {
243 return Err(IgtlError::InvalidSize {
244 expected: 0,
245 actual: data.len(),
246 });
247 }
248
249 Ok(ImgMetaMessage { images })
250 }
251}
252
253#[cfg(test)]
254mod tests {
255 use super::*;
256
257 #[test]
258 fn test_message_type() {
259 assert_eq!(ImgMetaMessage::message_type(), "IMGMETA");
260 }
261
262 #[test]
263 fn test_empty() {
264 let msg = ImgMetaMessage::empty();
265 assert!(msg.is_empty());
266 assert_eq!(msg.len(), 0);
267 }
268
269 #[test]
270 fn test_new() {
271 let elem = ImageMetaElement::new("Image1", "IMG001", "CT");
272 assert_eq!(elem.name, "Image1");
273 assert_eq!(elem.id, "IMG001");
274 assert_eq!(elem.modality, "CT");
275 }
276
277 #[test]
278 fn test_with_patient() {
279 let elem =
280 ImageMetaElement::new("Image1", "IMG001", "MRI").with_patient("John Doe", "P12345");
281 assert_eq!(elem.patient_name, "John Doe");
282 assert_eq!(elem.patient_id, "P12345");
283 }
284
285 #[test]
286 fn test_with_size() {
287 let elem = ImageMetaElement::new("Image1", "IMG001", "CT").with_size([512, 512, 128]);
288 assert_eq!(elem.size, [512, 512, 128]);
289 }
290
291 #[test]
292 fn test_add_image() {
293 let mut msg = ImgMetaMessage::empty();
294 msg.add_image(ImageMetaElement::new("Image1", "IMG001", "CT"));
295 assert_eq!(msg.len(), 1);
296 }
297
298 #[test]
299 fn test_encode_single() {
300 let elem = ImageMetaElement::new("TestImage", "TEST001", "CT");
301 let msg = ImgMetaMessage::new(vec![elem]);
302 let encoded = msg.encode_content().unwrap();
303
304 assert_eq!(encoded.len(), 260);
305 }
306
307 #[test]
308 fn test_roundtrip() {
309 let original = ImgMetaMessage::new(vec![
310 ImageMetaElement::new("CTScan1", "CT001", "CT")
311 .with_patient("Jane Smith", "P67890")
312 .with_timestamp(1234567890)
313 .with_size([512, 512, 200])
314 .with_scalar_type(5), ]);
316
317 let encoded = original.encode_content().unwrap();
318 let decoded = ImgMetaMessage::decode_content(&encoded).unwrap();
319
320 assert_eq!(decoded.images.len(), 1);
321 assert_eq!(decoded.images[0].name, "CTScan1");
322 assert_eq!(decoded.images[0].id, "CT001");
323 assert_eq!(decoded.images[0].modality, "CT");
324 assert_eq!(decoded.images[0].patient_name, "Jane Smith");
325 assert_eq!(decoded.images[0].patient_id, "P67890");
326 assert_eq!(decoded.images[0].timestamp, 1234567890);
327 assert_eq!(decoded.images[0].size, [512, 512, 200]);
328 assert_eq!(decoded.images[0].scalar_type, 5);
329 }
330
331 #[test]
332 fn test_roundtrip_multiple() {
333 let original = ImgMetaMessage::new(vec![
334 ImageMetaElement::new("CT1", "CT001", "CT"),
335 ImageMetaElement::new("MRI1", "MRI001", "MRI"),
336 ImageMetaElement::new("US1", "US001", "Ultrasound"),
337 ]);
338
339 let encoded = original.encode_content().unwrap();
340 let decoded = ImgMetaMessage::decode_content(&encoded).unwrap();
341
342 assert_eq!(decoded.images.len(), 3);
343 assert_eq!(decoded.images[0].modality, "CT");
344 assert_eq!(decoded.images[1].modality, "MRI");
345 assert_eq!(decoded.images[2].modality, "Ultrasound");
346 }
347
348 #[test]
349 fn test_empty_message() {
350 let msg = ImgMetaMessage::empty();
351 let encoded = msg.encode_content().unwrap();
352 let decoded = ImgMetaMessage::decode_content(&encoded).unwrap();
353
354 assert_eq!(decoded.images.len(), 0);
355 }
356
357 #[test]
358 fn test_decode_invalid_size() {
359 let data = vec![0u8; 259]; let result = ImgMetaMessage::decode_content(&data);
361 assert!(result.is_err());
362 }
363}