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}