openigtlink_rust/protocol/types/
imgmeta.rs1use crate::protocol::message::Message;
7use crate::error::{IgtlError, Result};
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.iter().position(|&b| b == 0).unwrap_or(64);
207 let patient_name = String::from_utf8(patient_name_bytes[..patient_name_len].to_vec())?;
208
209 let patient_id_bytes = &data[..64];
211 data.advance(64);
212 let patient_id_len = patient_id_bytes.iter().position(|&b| b == 0).unwrap_or(64);
213 let patient_id = String::from_utf8(patient_id_bytes[..patient_id_len].to_vec())?;
214
215 let timestamp = data.get_u64();
217
218 let size = [data.get_u16(), data.get_u16(), data.get_u16()];
220
221 let scalar_type = data.get_u8();
223
224 let _reserved = data.get_u8();
226
227 images.push(ImageMetaElement {
228 name,
229 id,
230 modality,
231 patient_name,
232 patient_id,
233 timestamp,
234 size,
235 scalar_type,
236 });
237 }
238
239 if !data.is_empty() {
240 return Err(IgtlError::InvalidSize {
241 expected: 0,
242 actual: data.len(),
243 });
244 }
245
246 Ok(ImgMetaMessage { images })
247 }
248}
249
250#[cfg(test)]
251mod tests {
252 use super::*;
253
254 #[test]
255 fn test_message_type() {
256 assert_eq!(ImgMetaMessage::message_type(), "IMGMETA");
257 }
258
259 #[test]
260 fn test_empty() {
261 let msg = ImgMetaMessage::empty();
262 assert!(msg.is_empty());
263 assert_eq!(msg.len(), 0);
264 }
265
266 #[test]
267 fn test_new() {
268 let elem = ImageMetaElement::new("Image1", "IMG001", "CT");
269 assert_eq!(elem.name, "Image1");
270 assert_eq!(elem.id, "IMG001");
271 assert_eq!(elem.modality, "CT");
272 }
273
274 #[test]
275 fn test_with_patient() {
276 let elem = ImageMetaElement::new("Image1", "IMG001", "MRI")
277 .with_patient("John Doe", "P12345");
278 assert_eq!(elem.patient_name, "John Doe");
279 assert_eq!(elem.patient_id, "P12345");
280 }
281
282 #[test]
283 fn test_with_size() {
284 let elem = ImageMetaElement::new("Image1", "IMG001", "CT")
285 .with_size([512, 512, 128]);
286 assert_eq!(elem.size, [512, 512, 128]);
287 }
288
289 #[test]
290 fn test_add_image() {
291 let mut msg = ImgMetaMessage::empty();
292 msg.add_image(ImageMetaElement::new("Image1", "IMG001", "CT"));
293 assert_eq!(msg.len(), 1);
294 }
295
296 #[test]
297 fn test_encode_single() {
298 let elem = ImageMetaElement::new("TestImage", "TEST001", "CT");
299 let msg = ImgMetaMessage::new(vec![elem]);
300 let encoded = msg.encode_content().unwrap();
301
302 assert_eq!(encoded.len(), 260);
303 }
304
305 #[test]
306 fn test_roundtrip() {
307 let original = ImgMetaMessage::new(vec![
308 ImageMetaElement::new("CTScan1", "CT001", "CT")
309 .with_patient("Jane Smith", "P67890")
310 .with_timestamp(1234567890)
311 .with_size([512, 512, 200])
312 .with_scalar_type(5), ]);
314
315 let encoded = original.encode_content().unwrap();
316 let decoded = ImgMetaMessage::decode_content(&encoded).unwrap();
317
318 assert_eq!(decoded.images.len(), 1);
319 assert_eq!(decoded.images[0].name, "CTScan1");
320 assert_eq!(decoded.images[0].id, "CT001");
321 assert_eq!(decoded.images[0].modality, "CT");
322 assert_eq!(decoded.images[0].patient_name, "Jane Smith");
323 assert_eq!(decoded.images[0].patient_id, "P67890");
324 assert_eq!(decoded.images[0].timestamp, 1234567890);
325 assert_eq!(decoded.images[0].size, [512, 512, 200]);
326 assert_eq!(decoded.images[0].scalar_type, 5);
327 }
328
329 #[test]
330 fn test_roundtrip_multiple() {
331 let original = ImgMetaMessage::new(vec![
332 ImageMetaElement::new("CT1", "CT001", "CT"),
333 ImageMetaElement::new("MRI1", "MRI001", "MRI"),
334 ImageMetaElement::new("US1", "US001", "Ultrasound"),
335 ]);
336
337 let encoded = original.encode_content().unwrap();
338 let decoded = ImgMetaMessage::decode_content(&encoded).unwrap();
339
340 assert_eq!(decoded.images.len(), 3);
341 assert_eq!(decoded.images[0].modality, "CT");
342 assert_eq!(decoded.images[1].modality, "MRI");
343 assert_eq!(decoded.images[2].modality, "Ultrasound");
344 }
345
346 #[test]
347 fn test_empty_message() {
348 let msg = ImgMetaMessage::empty();
349 let encoded = msg.encode_content().unwrap();
350 let decoded = ImgMetaMessage::decode_content(&encoded).unwrap();
351
352 assert_eq!(decoded.images.len(), 0);
353 }
354
355 #[test]
356 fn test_decode_invalid_size() {
357 let data = vec![0u8; 259]; let result = ImgMetaMessage::decode_content(&data);
359 assert!(result.is_err());
360 }
361}