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}