use crate::error::{IgtlError, Result};
use crate::protocol::message::Message;
use bytes::{Buf, BufMut};
#[derive(Debug, Clone, PartialEq)]
pub struct ImageMetaElement {
pub name: String,
pub id: String,
pub modality: String,
pub patient_name: String,
pub patient_id: String,
pub timestamp: u64,
pub size: [u16; 3],
pub scalar_type: u8,
}
impl ImageMetaElement {
pub fn new(
name: impl Into<String>,
id: impl Into<String>,
modality: impl Into<String>,
) -> Self {
ImageMetaElement {
name: name.into(),
id: id.into(),
modality: modality.into(),
patient_name: String::new(),
patient_id: String::new(),
timestamp: 0,
size: [0, 0, 0],
scalar_type: 3, }
}
pub fn with_patient(
mut self,
patient_name: impl Into<String>,
patient_id: impl Into<String>,
) -> Self {
self.patient_name = patient_name.into();
self.patient_id = patient_id.into();
self
}
pub fn with_timestamp(mut self, timestamp: u64) -> Self {
self.timestamp = timestamp;
self
}
pub fn with_size(mut self, size: [u16; 3]) -> Self {
self.size = size;
self
}
pub fn with_scalar_type(mut self, scalar_type: u8) -> Self {
self.scalar_type = scalar_type;
self
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct ImgMetaMessage {
pub images: Vec<ImageMetaElement>,
}
impl ImgMetaMessage {
pub fn new(images: Vec<ImageMetaElement>) -> Self {
ImgMetaMessage { images }
}
pub fn empty() -> Self {
ImgMetaMessage { images: Vec::new() }
}
pub fn add_image(&mut self, image: ImageMetaElement) {
self.images.push(image);
}
pub fn len(&self) -> usize {
self.images.len()
}
pub fn is_empty(&self) -> bool {
self.images.is_empty()
}
}
impl Message for ImgMetaMessage {
fn message_type() -> &'static str {
"IMGMETA"
}
fn encode_content(&self) -> Result<Vec<u8>> {
let mut buf = Vec::with_capacity(self.images.len() * 260);
for img in &self.images {
let mut name_bytes = [0u8; 64];
let name_str = img.name.as_bytes();
let copy_len = name_str.len().min(63);
name_bytes[..copy_len].copy_from_slice(&name_str[..copy_len]);
buf.extend_from_slice(&name_bytes);
let mut id_bytes = [0u8; 20];
let id_str = img.id.as_bytes();
let copy_len = id_str.len().min(19);
id_bytes[..copy_len].copy_from_slice(&id_str[..copy_len]);
buf.extend_from_slice(&id_bytes);
let mut modality_bytes = [0u8; 32];
let modality_str = img.modality.as_bytes();
let copy_len = modality_str.len().min(31);
modality_bytes[..copy_len].copy_from_slice(&modality_str[..copy_len]);
buf.extend_from_slice(&modality_bytes);
let mut patient_name_bytes = [0u8; 64];
let patient_name_str = img.patient_name.as_bytes();
let copy_len = patient_name_str.len().min(63);
patient_name_bytes[..copy_len].copy_from_slice(&patient_name_str[..copy_len]);
buf.extend_from_slice(&patient_name_bytes);
let mut patient_id_bytes = [0u8; 64];
let patient_id_str = img.patient_id.as_bytes();
let copy_len = patient_id_str.len().min(63);
patient_id_bytes[..copy_len].copy_from_slice(&patient_id_str[..copy_len]);
buf.extend_from_slice(&patient_id_bytes);
buf.put_u64(img.timestamp);
for &s in &img.size {
buf.put_u16(s);
}
buf.put_u8(img.scalar_type);
buf.put_u8(0);
}
Ok(buf)
}
fn decode_content(mut data: &[u8]) -> Result<Self> {
let mut images = Vec::new();
while data.len() >= 260 {
let name_bytes = &data[..64];
data.advance(64);
let name_len = name_bytes.iter().position(|&b| b == 0).unwrap_or(64);
let name = String::from_utf8(name_bytes[..name_len].to_vec())?;
let id_bytes = &data[..20];
data.advance(20);
let id_len = id_bytes.iter().position(|&b| b == 0).unwrap_or(20);
let id = String::from_utf8(id_bytes[..id_len].to_vec())?;
let modality_bytes = &data[..32];
data.advance(32);
let modality_len = modality_bytes.iter().position(|&b| b == 0).unwrap_or(32);
let modality = String::from_utf8(modality_bytes[..modality_len].to_vec())?;
let patient_name_bytes = &data[..64];
data.advance(64);
let patient_name_len = patient_name_bytes
.iter()
.position(|&b| b == 0)
.unwrap_or(64);
let patient_name = String::from_utf8(patient_name_bytes[..patient_name_len].to_vec())?;
let patient_id_bytes = &data[..64];
data.advance(64);
let patient_id_len = patient_id_bytes.iter().position(|&b| b == 0).unwrap_or(64);
let patient_id = String::from_utf8(patient_id_bytes[..patient_id_len].to_vec())?;
let timestamp = data.get_u64();
let size = [data.get_u16(), data.get_u16(), data.get_u16()];
let scalar_type = data.get_u8();
let _reserved = data.get_u8();
images.push(ImageMetaElement {
name,
id,
modality,
patient_name,
patient_id,
timestamp,
size,
scalar_type,
});
}
if !data.is_empty() {
return Err(IgtlError::InvalidSize {
expected: 0,
actual: data.len(),
});
}
Ok(ImgMetaMessage { images })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_message_type() {
assert_eq!(ImgMetaMessage::message_type(), "IMGMETA");
}
#[test]
fn test_empty() {
let msg = ImgMetaMessage::empty();
assert!(msg.is_empty());
assert_eq!(msg.len(), 0);
}
#[test]
fn test_new() {
let elem = ImageMetaElement::new("Image1", "IMG001", "CT");
assert_eq!(elem.name, "Image1");
assert_eq!(elem.id, "IMG001");
assert_eq!(elem.modality, "CT");
}
#[test]
fn test_with_patient() {
let elem =
ImageMetaElement::new("Image1", "IMG001", "MRI").with_patient("John Doe", "P12345");
assert_eq!(elem.patient_name, "John Doe");
assert_eq!(elem.patient_id, "P12345");
}
#[test]
fn test_with_size() {
let elem = ImageMetaElement::new("Image1", "IMG001", "CT").with_size([512, 512, 128]);
assert_eq!(elem.size, [512, 512, 128]);
}
#[test]
fn test_add_image() {
let mut msg = ImgMetaMessage::empty();
msg.add_image(ImageMetaElement::new("Image1", "IMG001", "CT"));
assert_eq!(msg.len(), 1);
}
#[test]
fn test_encode_single() {
let elem = ImageMetaElement::new("TestImage", "TEST001", "CT");
let msg = ImgMetaMessage::new(vec![elem]);
let encoded = msg.encode_content().unwrap();
assert_eq!(encoded.len(), 260);
}
#[test]
fn test_roundtrip() {
let original = ImgMetaMessage::new(vec![
ImageMetaElement::new("CTScan1", "CT001", "CT")
.with_patient("Jane Smith", "P67890")
.with_timestamp(1234567890)
.with_size([512, 512, 200])
.with_scalar_type(5), ]);
let encoded = original.encode_content().unwrap();
let decoded = ImgMetaMessage::decode_content(&encoded).unwrap();
assert_eq!(decoded.images.len(), 1);
assert_eq!(decoded.images[0].name, "CTScan1");
assert_eq!(decoded.images[0].id, "CT001");
assert_eq!(decoded.images[0].modality, "CT");
assert_eq!(decoded.images[0].patient_name, "Jane Smith");
assert_eq!(decoded.images[0].patient_id, "P67890");
assert_eq!(decoded.images[0].timestamp, 1234567890);
assert_eq!(decoded.images[0].size, [512, 512, 200]);
assert_eq!(decoded.images[0].scalar_type, 5);
}
#[test]
fn test_roundtrip_multiple() {
let original = ImgMetaMessage::new(vec![
ImageMetaElement::new("CT1", "CT001", "CT"),
ImageMetaElement::new("MRI1", "MRI001", "MRI"),
ImageMetaElement::new("US1", "US001", "Ultrasound"),
]);
let encoded = original.encode_content().unwrap();
let decoded = ImgMetaMessage::decode_content(&encoded).unwrap();
assert_eq!(decoded.images.len(), 3);
assert_eq!(decoded.images[0].modality, "CT");
assert_eq!(decoded.images[1].modality, "MRI");
assert_eq!(decoded.images[2].modality, "Ultrasound");
}
#[test]
fn test_empty_message() {
let msg = ImgMetaMessage::empty();
let encoded = msg.encode_content().unwrap();
let decoded = ImgMetaMessage::decode_content(&encoded).unwrap();
assert_eq!(decoded.images.len(), 0);
}
#[test]
fn test_decode_invalid_size() {
let data = vec![0u8; 259]; let result = ImgMetaMessage::decode_content(&data);
assert!(result.is_err());
}
}