openigtlink_rust/protocol/types/
lbmeta.rs1use crate::protocol::message::Message;
7use crate::error::{IgtlError, Result};
8use bytes::{Buf, BufMut};
9
10#[derive(Debug, Clone, PartialEq)]
12pub struct LabelMetaElement {
13 pub name: String,
15 pub id: String,
17 pub label: u8,
19 pub rgba: [u8; 4],
21 pub size: [u16; 3],
23 pub owner: String,
25}
26
27impl LabelMetaElement {
28 pub fn new(
30 name: impl Into<String>,
31 id: impl Into<String>,
32 label: u8,
33 ) -> Self {
34 LabelMetaElement {
35 name: name.into(),
36 id: id.into(),
37 label,
38 rgba: [255, 255, 255, 255], size: [0, 0, 0],
40 owner: String::new(),
41 }
42 }
43
44 pub fn with_rgba(mut self, rgba: [u8; 4]) -> Self {
46 self.rgba = rgba;
47 self
48 }
49
50 pub fn with_size(mut self, size: [u16; 3]) -> Self {
52 self.size = size;
53 self
54 }
55
56 pub fn with_owner(mut self, owner: impl Into<String>) -> Self {
58 self.owner = owner.into();
59 self
60 }
61}
62
63#[derive(Debug, Clone, PartialEq)]
70pub struct LbMetaMessage {
71 pub labels: Vec<LabelMetaElement>,
73}
74
75impl LbMetaMessage {
76 pub fn new(labels: Vec<LabelMetaElement>) -> Self {
78 LbMetaMessage { labels }
79 }
80
81 pub fn empty() -> Self {
83 LbMetaMessage { labels: Vec::new() }
84 }
85
86 pub fn add_label(&mut self, label: LabelMetaElement) {
88 self.labels.push(label);
89 }
90
91 pub fn len(&self) -> usize {
93 self.labels.len()
94 }
95
96 pub fn is_empty(&self) -> bool {
98 self.labels.is_empty()
99 }
100}
101
102impl Message for LbMetaMessage {
103 fn message_type() -> &'static str {
104 "LBMETA"
105 }
106
107 fn encode_content(&self) -> Result<Vec<u8>> {
108 let mut buf = Vec::with_capacity(self.labels.len() * 116);
109
110 for label in &self.labels {
111 let mut name_bytes = [0u8; 64];
113 let name_str = label.name.as_bytes();
114 let copy_len = name_str.len().min(63);
115 name_bytes[..copy_len].copy_from_slice(&name_str[..copy_len]);
116 buf.extend_from_slice(&name_bytes);
117
118 let mut id_bytes = [0u8; 20];
120 let id_str = label.id.as_bytes();
121 let copy_len = id_str.len().min(19);
122 id_bytes[..copy_len].copy_from_slice(&id_str[..copy_len]);
123 buf.extend_from_slice(&id_bytes);
124
125 buf.put_u8(label.label);
127
128 buf.put_u8(0);
130
131 buf.extend_from_slice(&label.rgba);
133
134 for &s in &label.size {
136 buf.put_u16(s);
137 }
138
139 let mut owner_bytes = [0u8; 20];
141 let owner_str = label.owner.as_bytes();
142 let copy_len = owner_str.len().min(19);
143 owner_bytes[..copy_len].copy_from_slice(&owner_str[..copy_len]);
144 buf.extend_from_slice(&owner_bytes);
145 }
146
147 Ok(buf)
148 }
149
150 fn decode_content(mut data: &[u8]) -> Result<Self> {
151 let mut labels = Vec::new();
152
153 while data.len() >= 116 {
154 let name_bytes = &data[..64];
156 data.advance(64);
157 let name_len = name_bytes.iter().position(|&b| b == 0).unwrap_or(64);
158 let name = String::from_utf8(name_bytes[..name_len].to_vec())?;
159
160 let id_bytes = &data[..20];
162 data.advance(20);
163 let id_len = id_bytes.iter().position(|&b| b == 0).unwrap_or(20);
164 let id = String::from_utf8(id_bytes[..id_len].to_vec())?;
165
166 let label = data.get_u8();
168
169 let _reserved = data.get_u8();
171
172 let rgba = [data.get_u8(), data.get_u8(), data.get_u8(), data.get_u8()];
174
175 let size = [data.get_u16(), data.get_u16(), data.get_u16()];
177
178 let owner_bytes = &data[..20];
180 data.advance(20);
181 let owner_len = owner_bytes.iter().position(|&b| b == 0).unwrap_or(20);
182 let owner = String::from_utf8(owner_bytes[..owner_len].to_vec())?;
183
184 labels.push(LabelMetaElement {
185 name,
186 id,
187 label,
188 rgba,
189 size,
190 owner,
191 });
192 }
193
194 if !data.is_empty() {
195 return Err(IgtlError::InvalidSize {
196 expected: 0,
197 actual: data.len(),
198 });
199 }
200
201 Ok(LbMetaMessage { labels })
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use super::*;
208
209 #[test]
210 fn test_message_type() {
211 assert_eq!(LbMetaMessage::message_type(), "LBMETA");
212 }
213
214 #[test]
215 fn test_empty() {
216 let msg = LbMetaMessage::empty();
217 assert!(msg.is_empty());
218 assert_eq!(msg.len(), 0);
219 }
220
221 #[test]
222 fn test_new() {
223 let elem = LabelMetaElement::new("Liver", "LBL001", 1);
224 assert_eq!(elem.name, "Liver");
225 assert_eq!(elem.id, "LBL001");
226 assert_eq!(elem.label, 1);
227 assert_eq!(elem.rgba, [255, 255, 255, 255]);
228 }
229
230 #[test]
231 fn test_with_rgba() {
232 let elem = LabelMetaElement::new("Heart", "LBL002", 2)
233 .with_rgba([255, 0, 0, 255]);
234 assert_eq!(elem.rgba, [255, 0, 0, 255]);
235 }
236
237 #[test]
238 fn test_with_size() {
239 let elem = LabelMetaElement::new("Kidney", "LBL003", 3)
240 .with_size([256, 256, 100]);
241 assert_eq!(elem.size, [256, 256, 100]);
242 }
243
244 #[test]
245 fn test_add_label() {
246 let mut msg = LbMetaMessage::empty();
247 msg.add_label(LabelMetaElement::new("Liver", "LBL001", 1));
248 assert_eq!(msg.len(), 1);
249 }
250
251 #[test]
252 fn test_encode_single() {
253 let elem = LabelMetaElement::new("TestLabel", "TEST001", 1);
254 let msg = LbMetaMessage::new(vec![elem]);
255 let encoded = msg.encode_content().unwrap();
256
257 assert_eq!(encoded.len(), 116);
258 }
259
260 #[test]
261 fn test_roundtrip() {
262 let original = LbMetaMessage::new(vec![
263 LabelMetaElement::new("Liver", "LBL001", 1)
264 .with_rgba([139, 69, 19, 255])
265 .with_size([512, 512, 200])
266 .with_owner("CT001"),
267 ]);
268
269 let encoded = original.encode_content().unwrap();
270 let decoded = LbMetaMessage::decode_content(&encoded).unwrap();
271
272 assert_eq!(decoded.labels.len(), 1);
273 assert_eq!(decoded.labels[0].name, "Liver");
274 assert_eq!(decoded.labels[0].id, "LBL001");
275 assert_eq!(decoded.labels[0].label, 1);
276 assert_eq!(decoded.labels[0].rgba, [139, 69, 19, 255]);
277 assert_eq!(decoded.labels[0].size, [512, 512, 200]);
278 assert_eq!(decoded.labels[0].owner, "CT001");
279 }
280
281 #[test]
282 fn test_roundtrip_multiple() {
283 let original = LbMetaMessage::new(vec![
284 LabelMetaElement::new("Liver", "LBL001", 1)
285 .with_rgba([139, 69, 19, 255]),
286 LabelMetaElement::new("Heart", "LBL002", 2)
287 .with_rgba([255, 0, 0, 255]),
288 LabelMetaElement::new("Kidney", "LBL003", 3)
289 .with_rgba([0, 255, 0, 255]),
290 ]);
291
292 let encoded = original.encode_content().unwrap();
293 let decoded = LbMetaMessage::decode_content(&encoded).unwrap();
294
295 assert_eq!(decoded.labels.len(), 3);
296 assert_eq!(decoded.labels[0].name, "Liver");
297 assert_eq!(decoded.labels[1].name, "Heart");
298 assert_eq!(decoded.labels[2].name, "Kidney");
299 }
300
301 #[test]
302 fn test_empty_message() {
303 let msg = LbMetaMessage::empty();
304 let encoded = msg.encode_content().unwrap();
305 let decoded = LbMetaMessage::decode_content(&encoded).unwrap();
306
307 assert_eq!(decoded.labels.len(), 0);
308 }
309
310 #[test]
311 fn test_decode_invalid_size() {
312 let data = vec![0u8; 115]; let result = LbMetaMessage::decode_content(&data);
314 assert!(result.is_err());
315 }
316}