sheave_core/messages/amf/v0/
ecma_array.rs

1use std::io::Result as IOResult;
2use crate::{
3    Decoder,
4    Encoder,
5    ByteBuffer,
6    messages::amf::{
7        ensure_marker,
8        v0::Marker
9    }
10};
11use super::Properties;
12
13/// The **sized** object type of AMF.
14/// This consists of:
15///
16/// * Count
17///
18/// The unsigned 32 bits integer.
19///
20/// This consists of pairs of string keys and any AMF data types.
21///
22/// * Key
23///
24/// The string which doesn't have its marker.
25/// This type is named as `UnmarkedString` in this crate.
26/// Also this occurs the panic if its length exceeds the range of 16 bits.
27///
28/// * Value
29///
30/// The pointer for AMF data types, which is wrapped into `Arc`.
31/// This is because of avoiding to be deallocated its value unexpectedly.
32///
33/// This is expected its size is same as the above count.
34///
35/// You can access to properties which this contains, as the `HashMap`.
36///
37/// # Examples
38///
39/// ```rust
40/// use sheave_core::{
41///     ecma_array,
42///     messages::amf::v0::{
43///         EcmaArray,
44///         Number
45///     },
46/// };
47///
48/// let ecma_array = ecma_array!(
49///     "videocodecid" => Number::from(0)
50/// );
51/// ecma_array.get_properties().get("videocodecid");
52/// &ecma_array.get_properties()["videocodecid"];
53/// ```
54#[derive(Debug, Clone, Default, PartialEq, Eq)]
55pub struct EcmaArray(Properties);
56
57impl EcmaArray {
58    /// Constructs a new ECMA array.
59    pub fn new(properties: Properties) -> Self {
60        Self(properties)
61    }
62
63    /// Gets immutable properties from this array.
64    pub fn get_properties(&self) -> &Properties {
65        &self.0
66    }
67
68    /// Gets mutable properties from this array.
69    pub fn get_properties_mut(&mut self) -> &mut Properties {
70        &mut self.0
71    }
72}
73
74impl Decoder<EcmaArray> for ByteBuffer {
75    /// Decodes bytes into an ECMA array.
76    ///
77    /// # Errors
78    ///
79    /// * [`InsufficientBufferLength`]
80    ///
81    /// When buffer isn't remained at least 2 bytes. (non-empty ECMA array contains at least one pair of key and value)
82    ///
83    /// * [`InconsistentMarker`]
84    ///
85    /// When a marker byte doesn't indicate the ECMA array.
86    ///
87    /// * [`InvalidString`]
88    ///
89    /// When key bytes are invalid for a UTF-8 string.
90    ///
91    /// # Examples
92    ///
93    /// ```rust
94    /// use sheave_core::{
95    ///     ByteBuffer,
96    ///     Decoder,
97    ///     messages::amf::v0::{
98    ///         Marker,
99    ///         EcmaArray
100    ///     }
101    /// };
102    ///
103    /// let mut buffer = ByteBuffer::default();
104    /// buffer.put_u8(Marker::EcmaArray as u8);
105    /// buffer.put_u32_be(0);
106    /// // Also ECMA array type is required a marker of object end (0x09) which is associated with an empty key.
107    /// buffer.put_u16_be(0);
108    /// buffer.put_u8(Marker::ObjectEnd as u8);
109    /// assert!(Decoder::<EcmaArray>::decode(&mut buffer).is_ok());
110    ///
111    /// let mut buffer = ByteBuffer::default();
112    /// buffer.put_u8(Marker::Number as u8);
113    /// buffer.put_u32_be(0);
114    /// buffer.put_u16_be(0);
115    /// buffer.put_u8(Marker::ObjectEnd as u8);
116    /// assert!(Decoder::<EcmaArray>::decode(&mut buffer).is_err());
117    ///
118    /// // This is a missing sequence of the "sparkle heart(💖)".
119    /// let mut bytes = vec![0, 159, 146, 150];
120    /// let mut buffer = ByteBuffer::default();
121    /// buffer.put_u8(Marker::EcmaArray as u8);
122    /// buffer.put_u32_be(0);
123    /// buffer.put_u16_be(4);
124    /// buffer.put_bytes(&bytes);
125    /// buffer.put_u8(Marker::Number as u8);
126    /// buffer.put_f64(0.0);
127    /// buffer.put_u16_be(0);
128    /// buffer.put_u8(Marker::ObjectEnd as u8);
129    /// assert!(Decoder::<EcmaArray>::decode(&mut buffer).is_err());
130    ///
131    /// let mut buffer = ByteBuffer::default();
132    /// assert!(Decoder::<EcmaArray>::decode(&mut buffer).is_err())
133    /// ```
134    ///
135    /// Note the length field will not be so cared because to decodde is enough to check the object end marker (0x09).
136    /// However warning will emit if lengths is inconsistent.
137    ///
138    /// [`InsufficientBufferLength`]: crate::byte_buffer::InsufficientBufferLength
139    /// [`InconsistentMarker`]: crate::messages::amf::InconsistentMarker
140    /// [`InvalidString`]: crate::messages::amf::InvalidString
141    fn decode(&mut self) -> IOResult<EcmaArray> {
142        self.get_u8().and_then(
143            |marker| ensure_marker(Marker::EcmaArray as u8, marker)
144        )?;
145
146        let length = self.get_u32_be()?;
147        let properties: Properties = self.decode()?;
148
149        if properties.len() != length as usize {
150            // TODO: Replaces something logger later.
151            println!("Properties length doesn't match previous field: previous field: {length}, actual length: {}", properties.len());
152        }
153
154        Ok(EcmaArray(properties))
155    }
156}
157
158impl Encoder<EcmaArray> for ByteBuffer {
159    /// Encodes an ECMA array into bytes.
160    ///
161    /// # Panics
162    ///
163    /// Its length must be the range of 32 bits.
164    /// If it exceeds, a panic is occured.
165    fn encode(&mut self, ecma_array: &EcmaArray) {
166        assert!(ecma_array.0.len() <= u32::MAX as usize);
167
168        self.put_u8(Marker::EcmaArray as u8);
169        self.put_u32_be(ecma_array.0.len() as u32);
170        self.encode(&ecma_array.0);
171    }
172}
173
174/// Constructs an ECMA array.
175///
176/// # Examples
177///
178/// ```rust
179/// use sheave_core::{
180///     ecma_array,
181///     messages::amf::v0::{
182///         EcmaArray,
183///         Number
184///     }
185/// };
186///
187/// let mut on_metadata = EcmaArray::default();
188/// on_metadata.get_properties_mut().insert("videocodecid", Number::from(0));
189/// on_metadata.get_properties_mut().insert("audiocodecid", Number::from(0));
190///
191/// assert_eq!(
192///     on_metadata,
193///     ecma_array!(
194///         "videocodecid" => Number::from(0),
195///         "audiocodecid" => Number::from(0)
196///     )
197/// )
198/// ```
199#[macro_export]
200macro_rules! ecma_array {
201    ($($key:expr => $value:expr),*) => {
202        {
203            use $crate::messages::amf::v0::{
204                EcmaArray,
205                Properties
206            };
207            let mut properties = Properties::default();
208            $(properties.insert($key, $value);)*
209            EcmaArray::new(properties)
210        }
211    }
212}
213
214#[cfg(test)]
215mod tests {
216    use crate::messages::amf::v0::UnmarkedString;
217    use super::*;
218
219    #[test]
220    fn decode_ecma_array() {
221        let mut buffer = ByteBuffer::default();
222        buffer.put_u8(Marker::EcmaArray as u8);
223        buffer.put_u32_be(0);
224        buffer.encode(&UnmarkedString::from(""));
225        buffer.put_u8(Marker::ObjectEnd as u8);
226        let result: IOResult<EcmaArray> = buffer.decode();
227        assert!(result.is_ok());
228        let actual = result.unwrap();
229        assert_eq!(EcmaArray::default(), actual)
230    }
231
232    #[test]
233    fn encode_ecma_array() {
234        let mut buffer = ByteBuffer::default();
235        buffer.encode(&EcmaArray::default());
236        let result: Vec<u8> = buffer.into();
237        assert_eq!(Marker::EcmaArray as u8, result[0]);
238        assert_eq!(&0u32.to_be_bytes(), &result[1..5]);
239        assert_eq!(&0u16.to_be_bytes(), &result[5..7]);
240        assert_eq!(Marker::ObjectEnd as u8, result[7])
241    }
242}