use crate::protocol::message::Message;
use crate::error::{IgtlError, Result};
use bytes::{Buf, BufMut};
#[derive(Debug, Clone, PartialEq)]
pub struct LabelMetaElement {
pub name: String,
pub id: String,
pub label: u8,
pub rgba: [u8; 4],
pub size: [u16; 3],
pub owner: String,
}
impl LabelMetaElement {
pub fn new(
name: impl Into<String>,
id: impl Into<String>,
label: u8,
) -> Self {
LabelMetaElement {
name: name.into(),
id: id.into(),
label,
rgba: [255, 255, 255, 255], size: [0, 0, 0],
owner: String::new(),
}
}
pub fn with_rgba(mut self, rgba: [u8; 4]) -> Self {
self.rgba = rgba;
self
}
pub fn with_size(mut self, size: [u16; 3]) -> Self {
self.size = size;
self
}
pub fn with_owner(mut self, owner: impl Into<String>) -> Self {
self.owner = owner.into();
self
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct LbMetaMessage {
pub labels: Vec<LabelMetaElement>,
}
impl LbMetaMessage {
pub fn new(labels: Vec<LabelMetaElement>) -> Self {
LbMetaMessage { labels }
}
pub fn empty() -> Self {
LbMetaMessage { labels: Vec::new() }
}
pub fn add_label(&mut self, label: LabelMetaElement) {
self.labels.push(label);
}
pub fn len(&self) -> usize {
self.labels.len()
}
pub fn is_empty(&self) -> bool {
self.labels.is_empty()
}
}
impl Message for LbMetaMessage {
fn message_type() -> &'static str {
"LBMETA"
}
fn encode_content(&self) -> Result<Vec<u8>> {
let mut buf = Vec::with_capacity(self.labels.len() * 116);
for label in &self.labels {
let mut name_bytes = [0u8; 64];
let name_str = label.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 = label.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);
buf.put_u8(label.label);
buf.put_u8(0);
buf.extend_from_slice(&label.rgba);
for &s in &label.size {
buf.put_u16(s);
}
let mut owner_bytes = [0u8; 20];
let owner_str = label.owner.as_bytes();
let copy_len = owner_str.len().min(19);
owner_bytes[..copy_len].copy_from_slice(&owner_str[..copy_len]);
buf.extend_from_slice(&owner_bytes);
}
Ok(buf)
}
fn decode_content(mut data: &[u8]) -> Result<Self> {
let mut labels = Vec::new();
while data.len() >= 116 {
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 label = data.get_u8();
let _reserved = data.get_u8();
let rgba = [data.get_u8(), data.get_u8(), data.get_u8(), data.get_u8()];
let size = [data.get_u16(), data.get_u16(), data.get_u16()];
let owner_bytes = &data[..20];
data.advance(20);
let owner_len = owner_bytes.iter().position(|&b| b == 0).unwrap_or(20);
let owner = String::from_utf8(owner_bytes[..owner_len].to_vec())?;
labels.push(LabelMetaElement {
name,
id,
label,
rgba,
size,
owner,
});
}
if !data.is_empty() {
return Err(IgtlError::InvalidSize {
expected: 0,
actual: data.len(),
});
}
Ok(LbMetaMessage { labels })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_message_type() {
assert_eq!(LbMetaMessage::message_type(), "LBMETA");
}
#[test]
fn test_empty() {
let msg = LbMetaMessage::empty();
assert!(msg.is_empty());
assert_eq!(msg.len(), 0);
}
#[test]
fn test_new() {
let elem = LabelMetaElement::new("Liver", "LBL001", 1);
assert_eq!(elem.name, "Liver");
assert_eq!(elem.id, "LBL001");
assert_eq!(elem.label, 1);
assert_eq!(elem.rgba, [255, 255, 255, 255]);
}
#[test]
fn test_with_rgba() {
let elem = LabelMetaElement::new("Heart", "LBL002", 2)
.with_rgba([255, 0, 0, 255]);
assert_eq!(elem.rgba, [255, 0, 0, 255]);
}
#[test]
fn test_with_size() {
let elem = LabelMetaElement::new("Kidney", "LBL003", 3)
.with_size([256, 256, 100]);
assert_eq!(elem.size, [256, 256, 100]);
}
#[test]
fn test_add_label() {
let mut msg = LbMetaMessage::empty();
msg.add_label(LabelMetaElement::new("Liver", "LBL001", 1));
assert_eq!(msg.len(), 1);
}
#[test]
fn test_encode_single() {
let elem = LabelMetaElement::new("TestLabel", "TEST001", 1);
let msg = LbMetaMessage::new(vec![elem]);
let encoded = msg.encode_content().unwrap();
assert_eq!(encoded.len(), 116);
}
#[test]
fn test_roundtrip() {
let original = LbMetaMessage::new(vec![
LabelMetaElement::new("Liver", "LBL001", 1)
.with_rgba([139, 69, 19, 255])
.with_size([512, 512, 200])
.with_owner("CT001"),
]);
let encoded = original.encode_content().unwrap();
let decoded = LbMetaMessage::decode_content(&encoded).unwrap();
assert_eq!(decoded.labels.len(), 1);
assert_eq!(decoded.labels[0].name, "Liver");
assert_eq!(decoded.labels[0].id, "LBL001");
assert_eq!(decoded.labels[0].label, 1);
assert_eq!(decoded.labels[0].rgba, [139, 69, 19, 255]);
assert_eq!(decoded.labels[0].size, [512, 512, 200]);
assert_eq!(decoded.labels[0].owner, "CT001");
}
#[test]
fn test_roundtrip_multiple() {
let original = LbMetaMessage::new(vec![
LabelMetaElement::new("Liver", "LBL001", 1)
.with_rgba([139, 69, 19, 255]),
LabelMetaElement::new("Heart", "LBL002", 2)
.with_rgba([255, 0, 0, 255]),
LabelMetaElement::new("Kidney", "LBL003", 3)
.with_rgba([0, 255, 0, 255]),
]);
let encoded = original.encode_content().unwrap();
let decoded = LbMetaMessage::decode_content(&encoded).unwrap();
assert_eq!(decoded.labels.len(), 3);
assert_eq!(decoded.labels[0].name, "Liver");
assert_eq!(decoded.labels[1].name, "Heart");
assert_eq!(decoded.labels[2].name, "Kidney");
}
#[test]
fn test_empty_message() {
let msg = LbMetaMessage::empty();
let encoded = msg.encode_content().unwrap();
let decoded = LbMetaMessage::decode_content(&encoded).unwrap();
assert_eq!(decoded.labels.len(), 0);
}
#[test]
fn test_decode_invalid_size() {
let data = vec![0u8; 115]; let result = LbMetaMessage::decode_content(&data);
assert!(result.is_err());
}
}