openigtlink_rust/protocol/types/
string.rs1use crate::protocol::message::Message;
7use crate::error::{IgtlError, Result};
8use bytes::{Buf, BufMut};
9
10#[derive(Debug, Clone, PartialEq)]
18pub struct StringMessage {
19 pub encoding: u16,
26
27 pub string: String,
29}
30
31impl StringMessage {
32 pub fn new(string: impl Into<String>) -> Self {
34 StringMessage {
35 encoding: 3, string: string.into(),
37 }
38 }
39
40 pub fn utf8(string: impl Into<String>) -> Self {
42 StringMessage {
43 encoding: 106, string: string.into(),
45 }
46 }
47
48 pub fn with_encoding(encoding: u16, string: impl Into<String>) -> Self {
50 StringMessage {
51 encoding,
52 string: string.into(),
53 }
54 }
55
56 pub fn as_str(&self) -> &str {
58 &self.string
59 }
60
61 pub fn len(&self) -> usize {
63 self.string.len()
64 }
65
66 pub fn is_empty(&self) -> bool {
68 self.string.is_empty()
69 }
70}
71
72impl Message for StringMessage {
73 fn message_type() -> &'static str {
74 "STRING"
75 }
76
77 fn encode_content(&self) -> Result<Vec<u8>> {
78 let string_bytes = self.string.as_bytes();
79 let length = string_bytes.len();
80
81 if length > 65535 {
82 return Err(IgtlError::BodyTooLarge {
83 size: length,
84 max: 65535,
85 });
86 }
87
88 let mut buf = Vec::with_capacity(4 + length);
89
90 buf.put_u16(self.encoding);
92
93 buf.put_u16(length as u16);
95
96 buf.extend_from_slice(string_bytes);
98
99 Ok(buf)
100 }
101
102 fn decode_content(mut data: &[u8]) -> Result<Self> {
103 if data.len() < 4 {
104 return Err(IgtlError::InvalidSize {
105 expected: 4,
106 actual: data.len(),
107 });
108 }
109
110 let encoding = data.get_u16();
112
113 let length = data.get_u16() as usize;
115
116 if data.len() < length {
118 return Err(IgtlError::InvalidSize {
119 expected: length,
120 actual: data.len(),
121 });
122 }
123
124 let string_bytes = &data[..length];
126 let string = String::from_utf8(string_bytes.to_vec())?;
127
128 Ok(StringMessage { encoding, string })
129 }
130}
131
132impl From<&str> for StringMessage {
133 fn from(s: &str) -> Self {
134 StringMessage::new(s)
135 }
136}
137
138impl From<String> for StringMessage {
139 fn from(s: String) -> Self {
140 StringMessage::new(s)
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147
148 #[test]
149 fn test_message_type() {
150 assert_eq!(StringMessage::message_type(), "STRING");
151 }
152
153 #[test]
154 fn test_new() {
155 let msg = StringMessage::new("Hello");
156 assert_eq!(msg.encoding, 3); assert_eq!(msg.string, "Hello");
158 }
159
160 #[test]
161 fn test_utf8() {
162 let msg = StringMessage::utf8("こんにちは");
163 assert_eq!(msg.encoding, 106); assert_eq!(msg.string, "こんにちは");
165 }
166
167 #[test]
168 fn test_with_encoding() {
169 let msg = StringMessage::with_encoding(42, "Test");
170 assert_eq!(msg.encoding, 42);
171 assert_eq!(msg.string, "Test");
172 }
173
174 #[test]
175 fn test_as_str() {
176 let msg = StringMessage::new("Test");
177 assert_eq!(msg.as_str(), "Test");
178 }
179
180 #[test]
181 fn test_len() {
182 let msg = StringMessage::new("Hello");
183 assert_eq!(msg.len(), 5);
184 }
185
186 #[test]
187 fn test_is_empty() {
188 let msg1 = StringMessage::new("");
189 assert!(msg1.is_empty());
190
191 let msg2 = StringMessage::new("test");
192 assert!(!msg2.is_empty());
193 }
194
195 #[test]
196 fn test_encode_simple() {
197 let msg = StringMessage::new("Test");
198 let encoded = msg.encode_content().unwrap();
199
200 assert_eq!(encoded[0..2], [0, 3]); assert_eq!(encoded[2..4], [0, 4]); assert_eq!(&encoded[4..], b"Test");
204 }
205
206 #[test]
207 fn test_roundtrip_ascii() {
208 let original = StringMessage::new("Hello, World!");
209 let encoded = original.encode_content().unwrap();
210 let decoded = StringMessage::decode_content(&encoded).unwrap();
211
212 assert_eq!(decoded.encoding, original.encoding);
213 assert_eq!(decoded.string, original.string);
214 }
215
216 #[test]
217 fn test_roundtrip_utf8() {
218 let original = StringMessage::utf8("Hello 世界 🌍");
219 let encoded = original.encode_content().unwrap();
220 let decoded = StringMessage::decode_content(&encoded).unwrap();
221
222 assert_eq!(decoded.encoding, original.encoding);
223 assert_eq!(decoded.string, original.string);
224 }
225
226 #[test]
227 fn test_empty_string() {
228 let msg = StringMessage::new("");
229 let encoded = msg.encode_content().unwrap();
230 let decoded = StringMessage::decode_content(&encoded).unwrap();
231
232 assert_eq!(decoded.string, "");
233 assert_eq!(encoded.len(), 4); }
235
236 #[test]
237 fn test_max_length() {
238 let long_string = "A".repeat(65535);
239 let msg = StringMessage::new(long_string.clone());
240 let encoded = msg.encode_content().unwrap();
241 let decoded = StringMessage::decode_content(&encoded).unwrap();
242
243 assert_eq!(decoded.string, long_string);
244 }
245
246 #[test]
247 fn test_too_long() {
248 let too_long = "A".repeat(65536);
249 let msg = StringMessage::new(too_long);
250 let result = msg.encode_content();
251
252 assert!(result.is_err());
253 }
254
255 #[test]
256 fn test_decode_invalid_size() {
257 let data = vec![0, 3]; let result = StringMessage::decode_content(&data);
259 assert!(result.is_err());
260 }
261
262 #[test]
263 fn test_decode_truncated() {
264 let mut data = vec![0, 3, 0, 10]; data.extend_from_slice(b"Short"); let result = StringMessage::decode_content(&data);
268 assert!(result.is_err());
269 }
270
271 #[test]
272 fn test_from_str() {
273 let msg: StringMessage = "Test".into();
274 assert_eq!(msg.string, "Test");
275 assert_eq!(msg.encoding, 3);
276 }
277
278 #[test]
279 fn test_from_string() {
280 let s = String::from("Test");
281 let msg: StringMessage = s.into();
282 assert_eq!(msg.string, "Test");
283 assert_eq!(msg.encoding, 3);
284 }
285
286 #[test]
287 fn test_big_endian_encoding() {
288 let msg = StringMessage::new("X");
289 let encoded = msg.encode_content().unwrap();
290
291 assert_eq!(encoded[0], 0x00);
293 assert_eq!(encoded[1], 0x03);
294
295 assert_eq!(encoded[2], 0x00);
297 assert_eq!(encoded[3], 0x01);
298 }
299}