openigtlink_rust/protocol/types/
capability.rs1use crate::protocol::message::Message;
7use crate::error::{IgtlError, Result};
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("Missing null terminator in capability type".to_string())
86 })?;
87
88 let type_bytes = &remaining[pos..pos + end];
90 let type_name = String::from_utf8(type_bytes.to_vec())?;
91 types.push(type_name);
92
93 pos += end + 1; }
95
96 Ok(CapabilityMessage { types })
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 #[test]
105 fn test_message_type() {
106 assert_eq!(CapabilityMessage::message_type(), "CAPABILITY");
107 }
108
109 #[test]
110 fn test_empty_capability() {
111 let capability = CapabilityMessage::empty();
112 assert_eq!(capability.types.len(), 0);
113 }
114
115 #[test]
116 fn test_new_capability() {
117 let types = vec!["TRANSFORM".to_string(), "IMAGE".to_string()];
118 let capability = CapabilityMessage::new(types.clone());
119 assert_eq!(capability.types, types);
120 }
121
122 #[test]
123 fn test_capability_roundtrip() {
124 let original = CapabilityMessage {
125 types: vec![
126 "TRANSFORM".to_string(),
127 "IMAGE".to_string(),
128 "STATUS".to_string(),
129 ],
130 };
131
132 let encoded = original.encode_content().unwrap();
133 let decoded = CapabilityMessage::decode_content(&encoded).unwrap();
134
135 assert_eq!(original.types, decoded.types);
136 }
137
138 #[test]
139 fn test_empty_list() {
140 let capability = CapabilityMessage { types: Vec::new() };
141
142 let encoded = capability.encode_content().unwrap();
143 assert_eq!(encoded.len(), 4); let decoded = CapabilityMessage::decode_content(&encoded).unwrap();
146 assert_eq!(decoded.types.len(), 0);
147 }
148
149 #[test]
150 fn test_single_type() {
151 let capability = CapabilityMessage {
152 types: vec!["TRANSFORM".to_string()],
153 };
154
155 let encoded = capability.encode_content().unwrap();
156 let decoded = CapabilityMessage::decode_content(&encoded).unwrap();
157
158 assert_eq!(decoded.types.len(), 1);
159 assert_eq!(decoded.types[0], "TRANSFORM");
160 }
161
162 #[test]
163 fn test_multiple_types() {
164 let capability = CapabilityMessage {
165 types: vec![
166 "TRANSFORM".to_string(),
167 "IMAGE".to_string(),
168 "STATUS".to_string(),
169 "POSITION".to_string(),
170 "CAPABILITY".to_string(),
171 ],
172 };
173
174 let encoded = capability.encode_content().unwrap();
175 let decoded = CapabilityMessage::decode_content(&encoded).unwrap();
176
177 assert_eq!(decoded.types, capability.types);
178 }
179
180 #[test]
181 fn test_null_termination() {
182 let capability = CapabilityMessage {
183 types: vec!["TEST".to_string()],
184 };
185
186 let encoded = capability.encode_content().unwrap();
187
188 assert_eq!(encoded.len(), 9);
190
191 assert_eq!(encoded[8], 0);
193 }
194
195 #[test]
196 fn test_big_endian_count() {
197 let capability = CapabilityMessage {
198 types: vec!["A".to_string(), "B".to_string()],
199 };
200
201 let encoded = capability.encode_content().unwrap();
202
203 assert_eq!(encoded[0], 0x00);
205 assert_eq!(encoded[1], 0x00);
206 assert_eq!(encoded[2], 0x00);
207 assert_eq!(encoded[3], 0x02);
208 }
209
210 #[test]
211 fn test_decode_invalid_size() {
212 let short_data = vec![0u8; 2];
213 let result = CapabilityMessage::decode_content(&short_data);
214 assert!(matches!(result, Err(IgtlError::InvalidSize { .. })));
215 }
216
217 #[test]
218 fn test_decode_missing_null_terminator() {
219 let mut data = Vec::new();
220 data.extend_from_slice(&1u32.to_be_bytes()); data.extend_from_slice(b"TEST"); let result = CapabilityMessage::decode_content(&data);
224 assert!(matches!(result, Err(IgtlError::InvalidHeader(_))));
225 }
226
227 #[test]
228 fn test_decode_unexpected_end() {
229 let mut data = Vec::new();
230 data.extend_from_slice(&2u32.to_be_bytes()); data.extend_from_slice(b"TEST\0"); let result = CapabilityMessage::decode_content(&data);
234 assert!(matches!(result, Err(IgtlError::InvalidHeader(_))));
235 }
236}