scuffle_amf0/
encoder.rs

1//! AMF0 encoder
2
3use std::borrow::Borrow;
4use std::io;
5
6use byteorder::{BigEndian, WriteBytesExt};
7
8use crate::{Amf0Error, Amf0Marker, Amf0Object, Amf0Value};
9
10/// AMF0 encoder.
11///
12/// Provides various functions to encode different types of AMF0 values into a writer.
13#[derive(Debug)]
14pub struct Amf0Encoder<W> {
15    writer: W,
16}
17
18impl<W> Amf0Encoder<W> {
19    /// Create a new encoder from a writer.
20    pub fn new(writer: W) -> Self {
21        Amf0Encoder { writer }
22    }
23}
24
25impl<W> Amf0Encoder<W>
26where
27    W: io::Write,
28{
29    /// Encode a [`bool`] as a AMF0 boolean value.
30    pub fn encode_boolean(&mut self, value: bool) -> Result<(), Amf0Error> {
31        self.writer.write_u8(Amf0Marker::Boolean as u8)?;
32        self.writer.write_u8(value as u8)?;
33        Ok(())
34    }
35
36    /// Encode a [`f64`] as a AMF0 number value.
37    pub fn encode_number(&mut self, value: f64) -> Result<(), Amf0Error> {
38        self.writer.write_u8(Amf0Marker::Number as u8)?;
39        self.writer.write_f64::<BigEndian>(value)?;
40        Ok(())
41    }
42
43    /// Encode a [`&str`](str) as a AMF0 string value.
44    ///
45    /// This function decides based on the length of the given string slice whether to use a normal string or a long string.
46    pub fn encode_string(&mut self, value: &str) -> Result<(), Amf0Error> {
47        let len = value.len();
48
49        if len <= (u16::MAX as usize) {
50            // Normal string
51            self.writer.write_u8(Amf0Marker::String as u8)?;
52            self.writer.write_u16::<BigEndian>(len as u16)?;
53            self.writer.write_all(value.as_bytes())?;
54        } else {
55            // Long string
56
57            // This try_into fails if the length is greater than u32::MAX
58            let len: u32 = len.try_into()?;
59
60            self.writer.write_u8(Amf0Marker::LongString as u8)?;
61            self.writer.write_u32::<BigEndian>(len)?;
62            self.writer.write_all(value.as_bytes())?;
63        }
64
65        Ok(())
66    }
67
68    /// Encode AMF0 Null value.
69    pub fn encode_null(&mut self) -> Result<(), Amf0Error> {
70        self.writer.write_u8(Amf0Marker::Null as u8)?;
71        Ok(())
72    }
73
74    /// Encode AMF0 Undefined value.
75    pub fn encode_undefined(&mut self) -> Result<(), Amf0Error> {
76        self.writer.write_u8(Amf0Marker::Undefined as u8)?;
77        Ok(())
78    }
79
80    pub(crate) fn encode_array_header(&mut self, len: u32) -> Result<(), Amf0Error> {
81        self.writer.write_u8(Amf0Marker::StrictArray as u8)?;
82        self.writer.write_u32::<BigEndian>(len)?;
83        Ok(())
84    }
85
86    /// Encode an Amf0Array as an AMF0 StrictArray value.
87    pub fn encode_array<'a, I, B>(&mut self, values: I) -> Result<(), Amf0Error>
88    where
89        B: Borrow<Amf0Value<'a>>,
90        I: IntoIterator<Item = B>,
91        I::IntoIter: ExactSizeIterator,
92    {
93        let iter = values.into_iter();
94        self.encode_array_header(iter.len().try_into()?)?;
95
96        for value in iter {
97            value.borrow().encode(self)?;
98        }
99
100        Ok(())
101    }
102
103    pub(crate) fn encode_object_header(&mut self) -> Result<(), Amf0Error> {
104        self.writer.write_u8(Amf0Marker::Object as u8)?;
105        Ok(())
106    }
107
108    pub(crate) fn encode_object_key(&mut self, key: &str) -> Result<(), Amf0Error> {
109        self.writer.write_u16::<BigEndian>(key.len().try_into()?)?;
110        self.writer.write_all(key.as_bytes())?;
111        Ok(())
112    }
113
114    pub(crate) fn encode_object_trailer(&mut self) -> Result<(), Amf0Error> {
115        // Final object key length is 0
116        self.writer.write_u16::<BigEndian>(0)?;
117        // Followed by object end
118        self.writer.write_u8(Amf0Marker::ObjectEnd as u8)?;
119        Ok(())
120    }
121
122    /// Encode an [`Amf0Object`] as an AMF0 Object value.
123    pub fn encode_object(&mut self, values: &Amf0Object) -> Result<(), Amf0Error> {
124        self.encode_object_header()?;
125
126        for (key, value) in values.iter() {
127            self.encode_object_key(key.as_str())?;
128            value.encode(self)?;
129        }
130
131        self.encode_object_trailer()?;
132
133        Ok(())
134    }
135
136    /// Encode a given value using [serde].
137    #[cfg(feature = "serde")]
138    pub fn serialize<T>(&mut self, value: T) -> Result<(), Amf0Error>
139    where
140        T: serde::Serialize,
141    {
142        value.serialize(self)?;
143        Ok(())
144    }
145}