use crate::error::{IgtlError, Result};
use crate::protocol::message::Message;
use bytes::{Buf, BufMut};
#[derive(Debug, Clone, PartialEq)]
pub struct StringMessage {
pub encoding: u16,
pub string: String,
}
impl StringMessage {
pub fn new(string: impl Into<String>) -> Self {
StringMessage {
encoding: 3, string: string.into(),
}
}
pub fn utf8(string: impl Into<String>) -> Self {
StringMessage {
encoding: 106, string: string.into(),
}
}
pub fn with_encoding(encoding: u16, string: impl Into<String>) -> Self {
StringMessage {
encoding,
string: string.into(),
}
}
pub fn as_str(&self) -> &str {
&self.string
}
pub fn len(&self) -> usize {
self.string.len()
}
pub fn is_empty(&self) -> bool {
self.string.is_empty()
}
}
impl Message for StringMessage {
fn message_type() -> &'static str {
"STRING"
}
fn encode_content(&self) -> Result<Vec<u8>> {
let string_bytes = self.string.as_bytes();
let length = string_bytes.len();
if length > 65535 {
return Err(IgtlError::BodyTooLarge {
size: length,
max: 65535,
});
}
let mut buf = Vec::with_capacity(4 + length);
buf.put_u16(self.encoding);
buf.put_u16(length as u16);
buf.extend_from_slice(string_bytes);
Ok(buf)
}
fn decode_content(mut data: &[u8]) -> Result<Self> {
if data.len() < 4 {
return Err(IgtlError::InvalidSize {
expected: 4,
actual: data.len(),
});
}
let encoding = data.get_u16();
let length = data.get_u16() as usize;
if data.len() < length {
return Err(IgtlError::InvalidSize {
expected: length,
actual: data.len(),
});
}
let string_bytes = &data[..length];
let string = String::from_utf8(string_bytes.to_vec())?;
Ok(StringMessage { encoding, string })
}
}
impl From<&str> for StringMessage {
fn from(s: &str) -> Self {
StringMessage::new(s)
}
}
impl From<String> for StringMessage {
fn from(s: String) -> Self {
StringMessage::new(s)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_message_type() {
assert_eq!(StringMessage::message_type(), "STRING");
}
#[test]
fn test_new() {
let msg = StringMessage::new("Hello");
assert_eq!(msg.encoding, 3); assert_eq!(msg.string, "Hello");
}
#[test]
fn test_utf8() {
let msg = StringMessage::utf8("γγγ«γ‘γ―");
assert_eq!(msg.encoding, 106); assert_eq!(msg.string, "γγγ«γ‘γ―");
}
#[test]
fn test_with_encoding() {
let msg = StringMessage::with_encoding(42, "Test");
assert_eq!(msg.encoding, 42);
assert_eq!(msg.string, "Test");
}
#[test]
fn test_as_str() {
let msg = StringMessage::new("Test");
assert_eq!(msg.as_str(), "Test");
}
#[test]
fn test_len() {
let msg = StringMessage::new("Hello");
assert_eq!(msg.len(), 5);
}
#[test]
fn test_is_empty() {
let msg1 = StringMessage::new("");
assert!(msg1.is_empty());
let msg2 = StringMessage::new("test");
assert!(!msg2.is_empty());
}
#[test]
fn test_encode_simple() {
let msg = StringMessage::new("Test");
let encoded = msg.encode_content().unwrap();
assert_eq!(encoded[0..2], [0, 3]); assert_eq!(encoded[2..4], [0, 4]); assert_eq!(&encoded[4..], b"Test");
}
#[test]
fn test_roundtrip_ascii() {
let original = StringMessage::new("Hello, World!");
let encoded = original.encode_content().unwrap();
let decoded = StringMessage::decode_content(&encoded).unwrap();
assert_eq!(decoded.encoding, original.encoding);
assert_eq!(decoded.string, original.string);
}
#[test]
fn test_roundtrip_utf8() {
let original = StringMessage::utf8("Hello δΈη π");
let encoded = original.encode_content().unwrap();
let decoded = StringMessage::decode_content(&encoded).unwrap();
assert_eq!(decoded.encoding, original.encoding);
assert_eq!(decoded.string, original.string);
}
#[test]
fn test_empty_string() {
let msg = StringMessage::new("");
let encoded = msg.encode_content().unwrap();
let decoded = StringMessage::decode_content(&encoded).unwrap();
assert_eq!(decoded.string, "");
assert_eq!(encoded.len(), 4); }
#[test]
fn test_max_length() {
let long_string = "A".repeat(65535);
let msg = StringMessage::new(long_string.clone());
let encoded = msg.encode_content().unwrap();
let decoded = StringMessage::decode_content(&encoded).unwrap();
assert_eq!(decoded.string, long_string);
}
#[test]
fn test_too_long() {
let too_long = "A".repeat(65536);
let msg = StringMessage::new(too_long);
let result = msg.encode_content();
assert!(result.is_err());
}
#[test]
fn test_decode_invalid_size() {
let data = vec![0, 3]; let result = StringMessage::decode_content(&data);
assert!(result.is_err());
}
#[test]
fn test_decode_truncated() {
let mut data = vec![0, 3, 0, 10]; data.extend_from_slice(b"Short");
let result = StringMessage::decode_content(&data);
assert!(result.is_err());
}
#[test]
fn test_from_str() {
let msg: StringMessage = "Test".into();
assert_eq!(msg.string, "Test");
assert_eq!(msg.encoding, 3);
}
#[test]
fn test_from_string() {
let s = String::from("Test");
let msg: StringMessage = s.into();
assert_eq!(msg.string, "Test");
assert_eq!(msg.encoding, 3);
}
#[test]
fn test_big_endian_encoding() {
let msg = StringMessage::new("X");
let encoded = msg.encode_content().unwrap();
assert_eq!(encoded[0], 0x00);
assert_eq!(encoded[1], 0x03);
assert_eq!(encoded[2], 0x00);
assert_eq!(encoded[3], 0x01);
}
}