openigtlink_rust/protocol/types/
bind.rs1use crate::protocol::message::Message;
7use crate::error::{IgtlError, Result};
8use bytes::Buf;
9
10#[derive(Debug, Clone, PartialEq)]
12pub struct BindEntry {
13 pub message_type: String,
15 pub device_name: String,
17}
18
19impl BindEntry {
20 pub fn new(message_type: impl Into<String>, device_name: impl Into<String>) -> Self {
22 BindEntry {
23 message_type: message_type.into(),
24 device_name: device_name.into(),
25 }
26 }
27}
28
29#[derive(Debug, Clone, PartialEq)]
37pub struct BindMessage {
38 pub entries: Vec<BindEntry>,
40}
41
42impl BindMessage {
43 pub fn new(entries: Vec<BindEntry>) -> Self {
45 BindMessage { entries }
46 }
47
48 pub fn empty() -> Self {
50 BindMessage { entries: Vec::new() }
51 }
52
53 pub fn add_entry(&mut self, entry: BindEntry) {
55 self.entries.push(entry);
56 }
57
58 pub fn add(&mut self, message_type: impl Into<String>, device_name: impl Into<String>) {
60 self.entries.push(BindEntry::new(message_type, device_name));
61 }
62
63 pub fn len(&self) -> usize {
65 self.entries.len()
66 }
67
68 pub fn is_empty(&self) -> bool {
70 self.entries.is_empty()
71 }
72}
73
74impl Message for BindMessage {
75 fn message_type() -> &'static str {
76 "BIND"
77 }
78
79 fn encode_content(&self) -> Result<Vec<u8>> {
80 let mut buf = Vec::with_capacity(self.entries.len() * 32);
81
82 for entry in &self.entries {
83 let mut type_bytes = [0u8; 12];
85 let type_str = entry.message_type.as_bytes();
86 let copy_len = type_str.len().min(12);
87 type_bytes[..copy_len].copy_from_slice(&type_str[..copy_len]);
88 buf.extend_from_slice(&type_bytes);
89
90 let mut name_bytes = [0u8; 20];
92 let name_str = entry.device_name.as_bytes();
93 let copy_len = name_str.len().min(20);
94 name_bytes[..copy_len].copy_from_slice(&name_str[..copy_len]);
95 buf.extend_from_slice(&name_bytes);
96 }
97
98 Ok(buf)
99 }
100
101 fn decode_content(mut data: &[u8]) -> Result<Self> {
102 let mut entries = Vec::new();
103
104 while data.len() >= 32 {
105 let type_bytes = &data[..12];
107 data.advance(12);
108 let type_len = type_bytes.iter().position(|&b| b == 0).unwrap_or(12);
109 let message_type = String::from_utf8(type_bytes[..type_len].to_vec())?;
110
111 let name_bytes = &data[..20];
113 data.advance(20);
114 let name_len = name_bytes.iter().position(|&b| b == 0).unwrap_or(20);
115 let device_name = String::from_utf8(name_bytes[..name_len].to_vec())?;
116
117 entries.push(BindEntry {
118 message_type,
119 device_name,
120 });
121 }
122
123 if !data.is_empty() {
124 return Err(IgtlError::InvalidSize {
125 expected: 0,
126 actual: data.len(),
127 });
128 }
129
130 Ok(BindMessage { entries })
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 #[test]
139 fn test_message_type() {
140 assert_eq!(BindMessage::message_type(), "BIND");
141 }
142
143 #[test]
144 fn test_empty() {
145 let msg = BindMessage::empty();
146 assert!(msg.is_empty());
147 assert_eq!(msg.len(), 0);
148 }
149
150 #[test]
151 fn test_new_entry() {
152 let entry = BindEntry::new("TRANSFORM", "Device1");
153 assert_eq!(entry.message_type, "TRANSFORM");
154 assert_eq!(entry.device_name, "Device1");
155 }
156
157 #[test]
158 fn test_add_entry() {
159 let mut msg = BindMessage::empty();
160 msg.add_entry(BindEntry::new("STATUS", "Device2"));
161 assert_eq!(msg.len(), 1);
162 }
163
164 #[test]
165 fn test_add() {
166 let mut msg = BindMessage::empty();
167 msg.add("TRANSFORM", "Device1");
168 msg.add("STATUS", "Device2");
169 assert_eq!(msg.len(), 2);
170 }
171
172 #[test]
173 fn test_encode_single() {
174 let msg = BindMessage::new(vec![
175 BindEntry::new("TRANSFORM", "Device1"),
176 ]);
177 let encoded = msg.encode_content().unwrap();
178
179 assert_eq!(encoded.len(), 32);
181 }
182
183 #[test]
184 fn test_encode_multiple() {
185 let msg = BindMessage::new(vec![
186 BindEntry::new("TRANSFORM", "Device1"),
187 BindEntry::new("STATUS", "Device2"),
188 BindEntry::new("POSITION", "Device3"),
189 ]);
190 let encoded = msg.encode_content().unwrap();
191
192 assert_eq!(encoded.len(), 96); }
194
195 #[test]
196 fn test_roundtrip_single() {
197 let original = BindMessage::new(vec![
198 BindEntry::new("TRANSFORM", "SurgicalTool"),
199 ]);
200
201 let encoded = original.encode_content().unwrap();
202 let decoded = BindMessage::decode_content(&encoded).unwrap();
203
204 assert_eq!(decoded.entries.len(), 1);
205 assert_eq!(decoded.entries[0].message_type, "TRANSFORM");
206 assert_eq!(decoded.entries[0].device_name, "SurgicalTool");
207 }
208
209 #[test]
210 fn test_roundtrip_multiple() {
211 let original = BindMessage::new(vec![
212 BindEntry::new("TRANSFORM", "Device1"),
213 BindEntry::new("STATUS", "Device2"),
214 BindEntry::new("POSITION", "Device3"),
215 BindEntry::new("SENSOR", "Device4"),
216 ]);
217
218 let encoded = original.encode_content().unwrap();
219 let decoded = BindMessage::decode_content(&encoded).unwrap();
220
221 assert_eq!(decoded.entries.len(), 4);
222 assert_eq!(decoded.entries[0].message_type, "TRANSFORM");
223 assert_eq!(decoded.entries[1].message_type, "STATUS");
224 assert_eq!(decoded.entries[2].message_type, "POSITION");
225 assert_eq!(decoded.entries[3].message_type, "SENSOR");
226 }
227
228 #[test]
229 fn test_empty_message() {
230 let msg = BindMessage::empty();
231 let encoded = msg.encode_content().unwrap();
232 let decoded = BindMessage::decode_content(&encoded).unwrap();
233
234 assert!(decoded.is_empty());
235 }
236
237 #[test]
238 fn test_decode_invalid_size() {
239 let data = vec![0u8; 31]; let result = BindMessage::decode_content(&data);
241 assert!(result.is_err());
242 }
243
244 #[test]
245 fn test_long_names_truncated() {
246 let msg = BindMessage::new(vec![
247 BindEntry::new("VERYLONGMESSAGETYPE", "VERYLONGDEVICENAMEOVER20CHARS"),
248 ]);
249 let encoded = msg.encode_content().unwrap();
250 let decoded = BindMessage::decode_content(&encoded).unwrap();
251
252 assert!(decoded.entries[0].message_type.len() <= 12);
254 assert!(decoded.entries[0].device_name.len() <= 20);
255 }
256}