sheave_core/messages/amf/v0/
object.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 anonymous object type of AMF.
14/// This consists of pairs of string keys and any AMF data types.
15///
16/// * Key
17///
18/// The string which doesn't have its marker.
19/// This type is named as `UnmarkedString` in this crate.
20/// Also this occurs the panic if its length exceeds the range of 16 bits.
21///
22/// * Value
23///
24/// The pointer for AMF data types, which is wrapped into `Arc`.
25/// This is because of avoiding to be deallocated its value unexpectedly.
26///
27/// You can access to properties which this constains, as the `HashMap`.
28///
29/// # Example
30///
31/// ```rust
32/// use sheave_core::{
33///     messages::amf::v0::AmfString,
34///     object
35/// };
36///
37/// let mut object = object!(
38///     "app" => AmfString::from("ondemand")
39/// );
40/// object.get_properties().get("app");
41/// &object.get_properties()["app"];
42/// ```
43#[derive(Debug, Clone, Default, PartialEq, Eq)]
44pub struct Object(Properties);
45
46impl Object {
47    /// Constrcuts a new object.
48    pub fn new(properties: Properties) -> Self {
49        Self(properties)
50    }
51
52    /// Gets immutable properties from this object.
53    pub fn get_properties(&self) -> &Properties {
54        &self.0
55    }
56
57    /// Gets mutable properties from this object.
58    pub fn get_properties_mut(&mut self) -> &mut Properties {
59        &mut self.0
60    }
61}
62
63impl Decoder<Object> for ByteBuffer {
64    /// Decodes bytes into an AMF's Object type.
65    ///
66    /// # Errors
67    ///
68    /// * [`InsufficientBufferLength`]
69    ///
70    /// When buffer isn't remained at least 2 bytes. (non-empty object contains at least one pair of key and value)
71    ///
72    /// * [`InconsistentMarker`]
73    ///
74    /// When a marker byte doesn't indicate the AMF Object.
75    ///
76    /// * [`InvalidString`]
77    ///
78    /// When key bytes are invalid for a UTF-8 string.
79    ///
80    /// # Examples
81    ///
82    /// ```rust
83    /// use sheave_core::{
84    ///     ByteBuffer,
85    ///     Decoder,
86    ///     messages::amf::v0::{
87    ///         Marker,
88    ///         Object
89    ///     }
90    /// };
91    ///
92    /// let mut buffer = ByteBuffer::default();
93    /// buffer.put_u8(Marker::Object as u8);
94    /// // AMF's Object type is required a marker of object end (0x09) which is associated with an empty key.
95    /// buffer.put_u16_be(0);
96    /// buffer.put_u8(Marker::ObjectEnd as u8);
97    /// assert!(Decoder::<Object>::decode(&mut buffer).is_ok());
98    ///
99    /// let mut buffer = ByteBuffer::default();
100    /// buffer.put_u8(Marker::Number as u8);
101    /// buffer.put_u16_be(0);
102    /// buffer.put_u8(Marker::ObjectEnd as u8);
103    /// assert!(Decoder::<Object>::decode(&mut buffer).is_err());
104    ///
105    /// // This is a missing sequence of the "sparkle heart(💖)".
106    /// let mut bytes = vec![0, 159, 146, 150];
107    /// let mut buffer = ByteBuffer::default();
108    /// buffer.put_u8(Marker::Object as u8);
109    /// buffer.put_u16_be(4);
110    /// buffer.put_bytes(&bytes);
111    /// buffer.put_u8(Marker::Number as u8);
112    /// buffer.put_f64(0.0);
113    /// buffer.put_u16_be(0);
114    /// buffer.put_u8(Marker::ObjectEnd as u8);
115    /// assert!(Decoder::<Object>::decode(&mut buffer).is_err());
116    ///
117    /// let mut buffer = ByteBuffer::default();
118    /// assert!(Decoder::<Object>::decode(&mut buffer).is_err())
119    /// ```
120    ///
121    /// [`InsufficientBufferLength`]: crate::byte_buffer::InsufficientBufferLength
122    /// [`InconsistentMarker`]: crate::messages::amf::InconsistentMarker
123    /// [`InvalidString`]: crate::messages::amf::InvalidString
124    fn decode(&mut self) -> IOResult<Object> {
125        self.get_u8().and_then(
126            |marker| ensure_marker(Marker::Object as u8, marker)
127        )?;
128
129        let properties: Properties = self.decode()?;
130        Ok(Object(properties))
131    }
132}
133
134impl Encoder<Object> for ByteBuffer {
135    /// Encodes an AMF's Object into bytes.
136    fn encode(&mut self, object: &Object) {
137        self.put_u8(Marker::Object as u8);
138        self.encode(&object.0);
139    }
140}
141
142/// Constructs an AMF's Object.
143///
144/// # Examples
145///
146/// ```rust
147/// use sheave_core::{
148///     // Note the macro is exported from the top of crate.
149///     object,
150///     messages::amf::v0::{
151///         AmfString,
152///         Object
153///     }
154/// };
155///
156/// let mut command_object = Object::default();
157/// command_object.get_properties_mut().insert("app", AmfString::from("ondemand"));
158/// command_object.get_properties_mut().insert("type", AmfString::from("nonprivate"));
159/// command_object.get_properties_mut().insert("flashVer", AmfString::from("FMLE/3.0 (compatible; Lavf 60.10.100)"));
160/// command_object.get_properties_mut().insert("tcUrl", AmfString::from("rtmp://localhost"));
161/// assert_eq!(
162///     command_object,
163///     object!(
164///         "app" => AmfString::from("ondemand"),
165///         "type" => AmfString::from("nonprivate"),
166///         "flashVer" => AmfString::from("FMLE/3.0 (compatible; Lavf 60.10.100)"),
167///         "tcUrl" => AmfString::from("rtmp://localhost")
168///     )
169/// )
170/// ```
171#[macro_export]
172macro_rules! object {
173    ($($key:expr => $value:expr),*) => {
174        {
175            use $crate::messages::amf::v0::{
176                Object,
177                Properties
178            };
179
180            let mut properties = Properties::default();
181            $(properties.insert($key, $value);)*
182            Object::new(properties)
183        }
184    }
185}
186
187#[cfg(test)]
188mod tests {
189    use crate::messages::amf::v0::UnmarkedString;
190    use super::*;
191
192    #[test]
193    fn decode_object() {
194        let mut buffer = ByteBuffer::default();
195        buffer.put_u8(Marker::Object as u8);
196        buffer.encode(&UnmarkedString::from(""));
197        buffer.put_u8(Marker::ObjectEnd as u8);
198        let result: IOResult<Object> = buffer.decode();
199        assert!(result.is_ok());
200        let actual = result.unwrap();
201        assert_eq!(Object::default(), actual)
202    }
203
204    #[test]
205    fn encode_object() {
206        let mut buffer = ByteBuffer::default();
207        buffer.encode(&Object::default());
208        let result: Vec<u8> = buffer.into();
209        assert_eq!(Marker::Object as u8, result[0]);
210        assert_eq!(&0u16.to_be_bytes(), &result[1..3]);
211        assert_eq!(Marker::ObjectEnd as u8, result[3])
212    }
213}