1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//! A Rust Implementation of AMF (Action Media Format).
//!
//! # Examples
//! ```
//! use amf::{Value, Amf0Value, Version};
//!
//! // Encodes a AMF0's number
//! let number = Value::from(Amf0Value::Number(1.23));
//! let mut buf = Vec::new();
//! number.write_to(&mut buf).unwrap();
//!
//! // Decodes above number
//! let decoded = Value::read_from(&mut &buf[..], Version::Amf0).unwrap();
//! assert_eq!(number, decoded);
//! ```
//!
//! # References
//! - [AMF0 Specification](http://download.macromedia.com/pub/labs/amf/amf0_spec_121207.pdf)
//! - [AMF3 Specification](http://download.macromedia.com/pub/labs/amf/amf3_spec_121207.pdf)
#![warn(missing_docs)]
extern crate byteorder;

use std::io;

pub use amf0::Value as Amf0Value;
pub use amf3::Value as Amf3Value;

pub mod amf0;
pub mod amf3;
pub mod error;

/// AMF decoding result.
pub type DecodeResult<T> = Result<T, error::DecodeError>;

/// Format version.
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub enum Version {
    /// Version 0.
    Amf0,

    /// Version 3.
    Amf3,
}

/// AMF value.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum Value {
    /// AMF0 value.
    Amf0(Amf0Value),

    /// AMF3 value.
    Amf3(Amf3Value),
}
impl Value {
    /// Reads an AMF encoded `Value` from `reader`.
    ///
    /// Note that reference objects are copied in the decoding phase
    /// for the sake of simplicity of the resulting value representation.
    /// And circular reference are unsupported (i.e., those are treated as errors).
    pub fn read_from<R>(reader: R, version: Version) -> DecodeResult<Self>
        where R: io::Read
    {
        match version {
            Version::Amf0 => Amf0Value::read_from(reader).map(Value::Amf0),
            Version::Amf3 => Amf3Value::read_from(reader).map(Value::Amf3),
        }
    }

    /// Writes the AMF encoded bytes of this value to `writer`.
    pub fn write_to<W>(&self, writer: W) -> io::Result<()>
        where W: io::Write
    {
        match *self {
            Value::Amf0(ref x) => x.write_to(writer),
            Value::Amf3(ref x) => x.write_to(writer),
        }
    }

    /// Tries to convert the value as a `str` reference.
    pub fn try_as_str(&self) -> Option<&str> {
        match *self {
            Value::Amf0(ref x) => x.try_as_str(),
            Value::Amf3(ref x) => x.try_as_str(),
        }
    }

    /// Tries to convert the value as a `f64`.
    pub fn try_as_f64(&self) -> Option<f64> {
        match *self {
            Value::Amf0(ref x) => x.try_as_f64(),
            Value::Amf3(ref x) => x.try_as_f64(),
        }
    }

    /// Tries to convert the value as an iterator of the contained values.
    pub fn try_into_values(self) -> Result<Box<Iterator<Item = Value>>, Self> {
        match self {
            Value::Amf0(x) => x.try_into_values().map_err(Value::Amf0),
            Value::Amf3(x) => {
                x.try_into_values()
                    .map(|iter| iter.map(Value::Amf3))
                    .map(iter_boxed)
                    .map_err(Value::Amf3)
            }
        }
    }

    /// Tries to convert the value as an iterator of the contained pairs.
    pub fn try_into_pairs(self) -> Result<Box<Iterator<Item = (String, Value)>>, Self> {
        match self {
            Value::Amf0(x) => x.try_into_pairs().map_err(Value::Amf0),
            Value::Amf3(x) => {
                x.try_into_pairs()
                    .map(|iter| iter.map(|(k, v)| (k, Value::Amf3(v))))
                    .map(iter_boxed)
                    .map_err(Value::Amf3)
            }
        }
    }
}
impl From<Amf0Value> for Value {
    fn from(f: Amf0Value) -> Value {
        Value::Amf0(f)
    }
}
impl From<Amf3Value> for Value {
    fn from(f: Amf3Value) -> Value {
        Value::Amf3(f)
    }
}

/// Key-value pair.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Pair<K, V> {
    /// The key of the pair.
    pub key: K,

    /// The value of the pair.
    pub value: V,
}

fn iter_boxed<I, T>(iter: I) -> Box<Iterator<Item = T>>
    where I: Iterator<Item = T> + 'static
{
    Box::new(iter)
}