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