sheave_core/messages/amf/v0/
string.rs

1use std::{
2    borrow::Cow,
3    fmt::{
4        Display,
5        Formatter,
6        Result as FormatResult
7    },
8    io::Result as IOResult,
9    ops::{
10        Deref,
11        DerefMut
12    },
13    string::String as StdString
14};
15use crate::{
16    Decoder,
17    Encoder,
18    ByteBuffer
19};
20use super::{
21    Marker,
22    super::{
23        ensure_marker,
24        invalid_string
25    }
26};
27
28/// The UTF-8 string of AMF data types.
29#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
30pub struct AmfString(StdString);
31
32impl AmfString {
33    /// Constructs an AMF's String.
34    pub fn new(string: StdString) -> Self {
35        Self(string)
36    }
37}
38
39impl Deref for AmfString {
40    type Target = StdString;
41
42    fn deref(&self) -> &Self::Target {
43        &self.0
44    }
45}
46
47impl DerefMut for AmfString {
48    fn deref_mut(&mut self) -> &mut Self::Target {
49        &mut self.0
50    }
51}
52
53impl<'a> PartialEq<&'a str> for AmfString {
54    fn eq(&self, other: &&'a str) -> bool {
55        self.0.eq(other)
56    }
57}
58
59impl<'a> PartialEq<Cow<'a, str>> for AmfString {
60    fn eq(&self, other: &Cow<'a, str>) -> bool {
61        self.0.eq(other)
62    }
63}
64
65impl<'a> PartialEq<AmfString> for &'a str {
66    fn eq(&self, other: &AmfString) -> bool {
67        self.eq(&other.0)
68    }
69}
70
71impl<'a> PartialEq<AmfString> for Cow<'a, str> {
72    fn eq(&self, other: &AmfString) -> bool {
73        self.eq(&other.0)
74    }
75}
76
77impl PartialEq<AmfString> for str {
78    fn eq(&self, other: &AmfString) -> bool {
79        self.eq(&other.0)
80    }
81}
82
83impl PartialEq<StdString> for AmfString {
84    fn eq(&self, other: &StdString) -> bool {
85        self.0.eq(other)
86    }
87}
88
89impl PartialEq<AmfString> for StdString {
90    fn eq(&self, other: &AmfString) -> bool {
91        self.eq(&other.0)
92    }
93}
94
95impl From<&str> for AmfString {
96    fn from(s: &str) -> Self {
97        Self(s.into())
98    }
99}
100
101impl Display for AmfString {
102    fn fmt(&self, f: &mut Formatter<'_>) -> FormatResult {
103        Display::fmt(&self.0, f)
104    }
105}
106
107impl Decoder<AmfString> for ByteBuffer {
108    /// Decodes bytes into an AMF's String.
109    ///
110    /// # Errors
111    ///
112    /// * [`InsufficientBufferLength`]
113    ///
114    /// When buffer isn't remained at least 3 bytes.
115    ///
116    /// * [`InconsistentMarker`]
117    ///
118    /// When a marker byte doesn't indicate the AMF String.
119    ///
120    /// * [`InvalidString`]
121    ///
122    /// When bytes are invalid for a UTF-8 string.
123    ///
124    /// # Examples
125    ///
126    /// ```rust
127    /// use sheave_core::{
128    ///     ByteBuffer,
129    ///     Decoder,
130    ///     messages::amf::v0::{
131    ///         Marker,
132    ///         AmfString
133    ///     }
134    /// };
135    ///
136    /// let s = "hello world!".as_bytes();
137    /// let mut buffer = ByteBuffer::default();
138    /// buffer.put_u8(Marker::AmfString as u8);
139    /// buffer.put_u16_be(s.len() as u16);
140    /// buffer.put_bytes(s);
141    /// assert!(Decoder::<AmfString>::decode(&mut buffer).is_ok());
142    ///
143    /// let mut buffer = ByteBuffer::default();
144    /// buffer.put_u8(Marker::Number as u8);
145    /// buffer.put_u16_be(s.len() as u16);
146    /// buffer.put_bytes(s);
147    /// assert!(Decoder::<AmfString>::decode(&mut buffer).is_err());
148    ///
149    /// // This is a missing sequence of the "sparkle heart(💖)".
150    /// let bytes = vec![0, 159, 146, 150];
151    /// let mut buffer = ByteBuffer::default();
152    /// buffer.put_u8(Marker::AmfString as u8);
153    /// buffer.put_u16_be(bytes.len() as u16);
154    /// buffer.put_bytes(&bytes);
155    /// assert!(Decoder::<AmfString>::decode(&mut buffer).is_err());
156    ///
157    /// let mut buffer = ByteBuffer::default();
158    /// assert!(Decoder::<AmfString>::decode(&mut buffer).is_err())
159    /// ```
160    ///
161    /// [`InsufficientBufferLength`]: crate::byte_buffer::InsufficientBufferLength
162    /// [`InconsistentMarker`]: crate::messages::amf::InconsistentMarker
163    /// [`InvalidString`]: crate::messages::amf::InvalidString
164    fn decode(&mut self) -> IOResult<AmfString> {
165        self.get_u8().and_then(
166            |marker| ensure_marker(Marker::AmfString as u8, marker)
167        )?;
168
169        let len = self.get_u16_be()? as usize;
170        if len == 0 {
171            return Ok("".into())
172        }
173        let bytes = self.get_bytes(len)?;
174        StdString::from_utf8(bytes.to_vec()).map(AmfString::new).map_err(invalid_string)
175    }
176}
177
178impl Encoder<AmfString> for ByteBuffer {
179    /// Encodes an AMF String into bytes.
180    ///
181    /// # Panics
182    ///
183    /// Its length must be the range of 16 bits.
184    /// If it exceeds, a panic is occured.
185    ///
186    /// # Examples
187    ///
188    /// ```rust
189    /// use std::panic::catch_unwind;
190    /// use sheave_core::{
191    ///     ByteBuffer,
192    ///     Encoder,
193    ///     messages::amf::v0::{
194    ///         Marker,
195    ///         AmfString
196    ///     }
197    /// };
198    ///
199    /// let s = "hello world!";
200    /// let mut buffer = ByteBuffer::default();
201    /// buffer.encode(&AmfString::from(s));
202    /// let bytes: Vec<u8> = buffer.into();
203    /// assert_eq!(Marker::AmfString as u8, bytes[0]);
204    /// assert_eq!((s.len() as u16).to_be_bytes().as_slice(), &bytes[1..3]);
205    /// assert_eq!(s.as_bytes(), &bytes[3..]);
206    ///
207    /// let result = catch_unwind(
208    ///     || {
209    ///         let mut buffer = ByteBuffer::default();
210    ///         buffer.encode(&AmfString::new("a".repeat(1 + u16::MAX as usize)))
211    ///     }
212    /// );
213    /// assert!(result.is_err())
214    /// ```
215    fn encode(&mut self, string: &AmfString) {
216        assert!(string.len() <= u16::MAX as usize);
217        self.put_u8(Marker::AmfString as u8);
218        self.put_u16_be(string.len() as u16);
219        self.put_bytes(string.as_bytes());
220    }
221}
222
223#[cfg(test)]
224mod tests {
225    use super::*;
226
227    #[test]
228    fn decode_string() {
229        let string = "connect".as_bytes();
230        let mut buffer = ByteBuffer::default();
231        buffer.put_u8(Marker::AmfString as u8);
232        buffer.put_u16_be(string.len() as u16);
233        buffer.put_bytes(string);
234        let result: IOResult<AmfString> = buffer.decode();
235        assert!(result.is_ok());
236        let string = result.unwrap();
237        assert_eq!("connect", string)
238    }
239
240    #[test]
241    fn encode_string() {
242        let string = AmfString::from("connect");
243        let mut buffer = ByteBuffer::default();
244        buffer.encode(&string);
245        let result: Vec<u8> = buffer.into();
246        assert_eq!(Marker::AmfString as u8, result[0]);
247        assert_eq!(&(string.len() as u16).to_be_bytes(), &result[1..3]);
248        assert_eq!("connect".as_bytes(), &result[3..])
249    }
250
251    #[test]
252    #[should_panic]
253    fn panic_when_length_exceeded() {
254        let mut buffer = ByteBuffer::default();
255        buffer.encode(&AmfString::new("a".repeat(1 + u16::MAX as usize)));
256    }
257}