openigtlink_rust/protocol/types/
capability.rs1use crate::error::{IgtlError, Result};
7use crate::protocol::message::Message;
8use bytes::{Buf, BufMut};
9
10#[derive(Debug, Clone, PartialEq)]
19pub struct CapabilityMessage {
20 pub types: Vec<String>,
22}
23
24impl CapabilityMessage {
25 pub fn new(types: Vec<String>) -> Self {
27 CapabilityMessage { types }
28 }
29
30 pub fn empty() -> Self {
32 CapabilityMessage { types: Vec::new() }
33 }
34}
35
36impl Message for CapabilityMessage {
37 fn message_type() -> &'static str {
38 "CAPABILITY"
39 }
40
41 fn encode_content(&self) -> Result<Vec<u8>> {
42 let mut buf = Vec::new();
43
44 buf.put_u32(self.types.len() as u32);
46
47 for type_name in &self.types {
49 buf.extend_from_slice(type_name.as_bytes());
50 buf.put_u8(0); }
52
53 Ok(buf)
54 }
55
56 fn decode_content(data: &[u8]) -> Result<Self> {
57 if data.len() < 4 {
58 return Err(IgtlError::InvalidSize {
59 expected: 4,
60 actual: data.len(),
61 });
62 }
63
64 let mut cursor = std::io::Cursor::new(data);
65
66 let count = cursor.get_u32() as usize;
68
69 let mut types = Vec::with_capacity(count);
70 let remaining = &data[cursor.position() as usize..];
71 let mut pos = 0;
72
73 for _ in 0..count {
74 if pos >= remaining.len() {
75 return Err(IgtlError::InvalidHeader(
76 "Unexpected end of data while decoding capability types".to_string(),
77 ));
78 }
79
80 let end = remaining[pos..]
82 .iter()
83 .position(|&b| b == 0)
84 .ok_or_else(|| {
85 IgtlError::InvalidHeader(
86 "Missing null terminator in capability type".to_string(),
87 )
88 })?;
89
90 let type_bytes = &remaining[pos..pos + end];
92 let type_name = String::from_utf8(type_bytes.to_vec())?;
93 types.push(type_name);
94
95 pos += end + 1; }
97
98 Ok(CapabilityMessage { types })
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 #[test]
107 fn test_message_type() {
108 assert_eq!(CapabilityMessage::message_type(), "CAPABILITY");
109 }
110
111 #[test]
112 fn test_empty_capability() {
113 let capability = CapabilityMessage::empty();
114 assert_eq!(capability.types.len(), 0);
115 }
116
117 #[test]
118 fn test_new_capability() {
119 let types = vec!["TRANSFORM".to_string(), "IMAGE".to_string()];
120 let capability = CapabilityMessage::new(types.clone());
121 assert_eq!(capability.types, types);
122 }
123
124 #[test]
125 fn test_capability_roundtrip() {
126 let original = CapabilityMessage {
127 types: vec![
128 "TRANSFORM".to_string(),
129 "IMAGE".to_string(),
130 "STATUS".to_string(),
131 ],
132 };
133
134 let encoded = original.encode_content().unwrap();
135 let decoded = CapabilityMessage::decode_content(&encoded).unwrap();
136
137 assert_eq!(original.types, decoded.types);
138 }
139
140 #[test]
141 fn test_empty_list() {
142 let capability = CapabilityMessage { types: Vec::new() };
143
144 let encoded = capability.encode_content().unwrap();
145 assert_eq!(encoded.len(), 4); let decoded = CapabilityMessage::decode_content(&encoded).unwrap();
148 assert_eq!(decoded.types.len(), 0);
149 }
150
151 #[test]
152 fn test_single_type() {
153 let capability = CapabilityMessage {
154 types: vec!["TRANSFORM".to_string()],
155 };
156
157 let encoded = capability.encode_content().unwrap();
158 let decoded = CapabilityMessage::decode_content(&encoded).unwrap();
159
160 assert_eq!(decoded.types.len(), 1);
161 assert_eq!(decoded.types[0], "TRANSFORM");
162 }
163
164 #[test]
165 fn test_multiple_types() {
166 let capability = CapabilityMessage {
167 types: vec![
168 "TRANSFORM".to_string(),
169 "IMAGE".to_string(),
170 "STATUS".to_string(),
171 "POSITION".to_string(),
172 "CAPABILITY".to_string(),
173 ],
174 };
175
176 let encoded = capability.encode_content().unwrap();
177 let decoded = CapabilityMessage::decode_content(&encoded).unwrap();
178
179 assert_eq!(decoded.types, capability.types);
180 }
181
182 #[test]
183 fn test_null_termination() {
184 let capability = CapabilityMessage {
185 types: vec!["TEST".to_string()],
186 };
187
188 let encoded = capability.encode_content().unwrap();
189
190 assert_eq!(encoded.len(), 9);
192
193 assert_eq!(encoded[8], 0);
195 }
196
197 #[test]
198 fn test_big_endian_count() {
199 let capability = CapabilityMessage {
200 types: vec!["A".to_string(), "B".to_string()],
201 };
202
203 let encoded = capability.encode_content().unwrap();
204
205 assert_eq!(encoded[0], 0x00);
207 assert_eq!(encoded[1], 0x00);
208 assert_eq!(encoded[2], 0x00);
209 assert_eq!(encoded[3], 0x02);
210 }
211
212 #[test]
213 fn test_decode_invalid_size() {
214 let short_data = vec![0u8; 2];
215 let result = CapabilityMessage::decode_content(&short_data);
216 assert!(matches!(result, Err(IgtlError::InvalidSize { .. })));
217 }
218
219 #[test]
220 fn test_decode_missing_null_terminator() {
221 let mut data = Vec::new();
222 data.extend_from_slice(&1u32.to_be_bytes()); data.extend_from_slice(b"TEST"); let result = CapabilityMessage::decode_content(&data);
226 assert!(matches!(result, Err(IgtlError::InvalidHeader(_))));
227 }
228
229 #[test]
230 fn test_decode_unexpected_end() {
231 let mut data = Vec::new();
232 data.extend_from_slice(&2u32.to_be_bytes()); data.extend_from_slice(b"TEST\0"); let result = CapabilityMessage::decode_content(&data);
236 assert!(matches!(result, Err(IgtlError::InvalidHeader(_))));
237 }
238}