1use std::borrow::Cow;
2
3use num_derive::FromPrimitive;
4
5#[derive(Debug, PartialEq, Eq, Clone, Copy, FromPrimitive)]
8#[repr(u8)]
9pub enum Amf0Marker {
10 Number = 0x00,
11 Boolean = 0x01,
12 String = 0x02,
13 Object = 0x03,
14 MovieClipMarker = 0x04, Null = 0x05,
16 Undefined = 0x06,
17 Reference = 0x07,
18 EcmaArray = 0x08,
19 ObjectEnd = 0x09,
20 StrictArray = 0x0a,
21 Date = 0x0b,
22 LongString = 0x0c,
23 Unsupported = 0x0d,
24 Recordset = 0x0e, XmlDocument = 0x0f,
26 TypedObject = 0x10,
27 AVMPlusObject = 0x11, }
29
30#[derive(PartialEq, Clone, Debug)]
33pub enum Amf0Value<'a> {
34 Number(f64),
36 Boolean(bool),
38 String(Cow<'a, str>),
40 Object(Cow<'a, [(Cow<'a, str>, Amf0Value<'a>)]>),
42 Null,
44 ObjectEnd,
46 LongString(Cow<'a, str>),
48}
49
50impl Amf0Value<'_> {
51 pub fn marker(&self) -> Amf0Marker {
53 match self {
54 Self::Boolean(_) => Amf0Marker::Boolean,
55 Self::Number(_) => Amf0Marker::Number,
56 Self::String(_) => Amf0Marker::String,
57 Self::Object(_) => Amf0Marker::Object,
58 Self::Null => Amf0Marker::Null,
59 Self::ObjectEnd => Amf0Marker::ObjectEnd,
60 Self::LongString(_) => Amf0Marker::LongString,
61 }
62 }
63
64 pub fn to_owned(&self) -> Amf0Value<'static> {
66 match self {
67 Self::String(s) => Amf0Value::String(Cow::Owned(s.to_string())),
68 Self::LongString(s) => Amf0Value::LongString(Cow::Owned(s.to_string())),
69 Self::Object(o) => Amf0Value::Object(o.iter().map(|(k, v)| (Cow::Owned(k.to_string()), v.to_owned())).collect()),
70 Self::Number(n) => Amf0Value::Number(*n),
71 Self::Boolean(b) => Amf0Value::Boolean(*b),
72 Self::Null => Amf0Value::Null,
73 Self::ObjectEnd => Amf0Value::ObjectEnd,
74 }
75 }
76}
77
78#[cfg(test)]
79#[cfg_attr(all(test, coverage_nightly), coverage(off))]
80mod tests {
81 use num_traits::FromPrimitive;
82
83 use super::*;
84
85 #[test]
86 fn test_marker() {
87 let cases = [
88 (Amf0Value::Number(1.0), Amf0Marker::Number),
89 (Amf0Value::Boolean(true), Amf0Marker::Boolean),
90 (Amf0Value::String(Cow::Borrowed("test")), Amf0Marker::String),
91 (
92 Amf0Value::Object(Cow::Borrowed(&[(Cow::Borrowed("test"), Amf0Value::Number(1.0))])),
93 Amf0Marker::Object,
94 ),
95 (Amf0Value::Null, Amf0Marker::Null),
96 (Amf0Value::ObjectEnd, Amf0Marker::ObjectEnd),
97 (Amf0Value::LongString(Cow::Borrowed("test")), Amf0Marker::LongString),
98 ];
99
100 for (value, marker) in cases {
101 assert_eq!(value.marker(), marker);
102 }
103 }
104
105 #[test]
106 fn test_to_owned() {
107 let value = Amf0Value::Object(Cow::Borrowed(&[(
108 Cow::Borrowed("test"),
109 Amf0Value::LongString(Cow::Borrowed("test")),
110 )]));
111 let owned = value.to_owned();
112 assert_eq!(
113 owned,
114 Amf0Value::Object(Cow::Owned(vec![(
115 "test".to_string().into(),
116 Amf0Value::LongString(Cow::Owned("test".to_string()))
117 )]))
118 );
119
120 let value = Amf0Value::String(Cow::Borrowed("test"));
121 let owned = value.to_owned();
122 assert_eq!(owned, Amf0Value::String(Cow::Owned("test".to_string())));
123
124 let value = Amf0Value::Number(1.0);
125 let owned = value.to_owned();
126 assert_eq!(owned, Amf0Value::Number(1.0));
127
128 let value = Amf0Value::Boolean(true);
129 let owned = value.to_owned();
130 assert_eq!(owned, Amf0Value::Boolean(true));
131
132 let value = Amf0Value::Null;
133 let owned = value.to_owned();
134 assert_eq!(owned, Amf0Value::Null);
135
136 let value = Amf0Value::ObjectEnd;
137 let owned = value.to_owned();
138 assert_eq!(owned, Amf0Value::ObjectEnd);
139 }
140
141 #[test]
142 fn test_marker_primitive() {
143 let cases = [
144 (Amf0Marker::Number, 0x00),
145 (Amf0Marker::Boolean, 0x01),
146 (Amf0Marker::String, 0x02),
147 (Amf0Marker::Object, 0x03),
148 (Amf0Marker::MovieClipMarker, 0x04),
149 (Amf0Marker::Null, 0x05),
150 (Amf0Marker::Undefined, 0x06),
151 (Amf0Marker::Reference, 0x07),
152 (Amf0Marker::EcmaArray, 0x08),
153 (Amf0Marker::ObjectEnd, 0x09),
154 (Amf0Marker::StrictArray, 0x0a),
155 (Amf0Marker::Date, 0x0b),
156 (Amf0Marker::LongString, 0x0c),
157 (Amf0Marker::Unsupported, 0x0d),
158 (Amf0Marker::Recordset, 0x0e),
159 (Amf0Marker::XmlDocument, 0x0f),
160 (Amf0Marker::TypedObject, 0x10),
161 (Amf0Marker::AVMPlusObject, 0x11),
162 ];
163
164 for (marker, value) in cases {
165 assert_eq!(marker as u8, value);
166 assert_eq!(Amf0Marker::from_u8(value), Some(marker));
167 }
168
169 assert!(Amf0Marker::from_u8(0x12).is_none());
170 }
171}