1use crate::amf0::type_marker::TypeMarker;
2use crate::errors::AmfError;
3use crate::traits::{Marshall, MarshallLength, Unmarshall};
4use std::fmt::Display;
5use std::hash::{Hash, Hasher};
6
7pub trait MarkerType: Sized {
8 const TM: TypeMarker;
9}
10
11impl<M: MarkerType> Marshall for M {
12 fn marshall(&self) -> Result<Vec<u8>, AmfError> {
13 let mut buf = [0u8; 1];
14 buf[0] = M::TM as u8; Ok(buf.to_vec())
16 }
17}
18
19impl<M: MarkerType> MarshallLength for M {
20 fn marshall_length(&self) -> usize {
21 1
22 }
23}
24
25impl<M: MarkerType + Default> Unmarshall for M {
26 fn unmarshall(buf: &[u8]) -> Result<(Self, usize), AmfError> {
27 if buf.len() < 1 {
28 return Err(AmfError::BufferTooSmall {
29 want: 1,
30 got: buf.len(),
31 });
32 }
33 let type_marker = TypeMarker::try_from(buf[0])?;
34 if type_marker != M::TM {
35 return Err(AmfError::TypeMarkerValueMismatch {
36 want: M::TM as u8,
37 got: buf[0],
38 });
39 }
40 Ok((M::default(), 1))
41 }
42}
43
44#[derive(Debug, Clone, PartialEq, Eq, Default)]
47pub struct NullType;
48
49impl MarkerType for NullType {
50 const TM: TypeMarker = TypeMarker::Null;
51}
52
53impl TryFrom<&[u8]> for NullType {
56 type Error = AmfError;
57
58 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
59 Self::unmarshall(value).map(|(o, _)| o)
60 }
61}
62
63impl TryFrom<Vec<u8>> for NullType {
64 type Error = AmfError;
65
66 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
67 Self::try_from(value.as_slice())
68 }
69}
70
71impl TryFrom<NullType> for Vec<u8> {
72 type Error = AmfError;
73
74 fn try_from(value: NullType) -> Result<Self, Self::Error> {
75 value.marshall()
76 }
77}
78
79impl Display for NullType {
80 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81 write!(f, "null")
82 }
83}
84
85impl Hash for NullType {
86 fn hash<H: Hasher>(&self, state: &mut H) {
87 TypeMarker::Null.hash(state);
88 }
89}
90
91#[derive(Debug, Clone, PartialEq, Eq, Default)]
94pub struct UndefinedType;
95
96impl MarkerType for UndefinedType {
97 const TM: TypeMarker = TypeMarker::Undefined;
98}
99
100impl TryFrom<&[u8]> for UndefinedType {
103 type Error = AmfError;
104
105 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
106 Self::unmarshall(value).map(|(o, _)| o)
107 }
108}
109
110impl TryFrom<Vec<u8>> for UndefinedType {
111 type Error = AmfError;
112
113 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
114 Self::try_from(value.as_slice())
115 }
116}
117
118impl TryFrom<UndefinedType> for Vec<u8> {
119 type Error = AmfError;
120
121 fn try_from(value: UndefinedType) -> Result<Self, Self::Error> {
122 value.marshall()
123 }
124}
125
126impl Display for UndefinedType {
127 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128 write!(f, "undefined")
129 }
130}
131
132impl Hash for UndefinedType {
133 fn hash<H: Hasher>(&self, state: &mut H) {
134 TypeMarker::Undefined.hash(state);
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141 use crate::amf0::type_marker::TypeMarker;
142 use std::hash::{DefaultHasher, Hash, Hasher};
143
144 #[test]
146 fn test_null_marshall() {
147 let null = NullType;
148 let data = null.marshall().unwrap();
149 assert_eq!(data, vec![TypeMarker::Null as u8]);
150 }
151
152 #[test]
153 fn test_null_marshall_length() {
154 let null = NullType;
155 assert_eq!(null.marshall_length(), 1);
156 }
157
158 #[test]
159 fn test_null_unmarshall_valid() {
160 let data = [TypeMarker::Null as u8];
161 let (null, bytes_read) = NullType::unmarshall(&data).unwrap();
162 assert_eq!(bytes_read, 1);
163 assert_eq!(null, NullType);
164 }
165
166 #[test]
167 fn test_null_unmarshall_buffer_too_small() {
168 let data = [];
169 let result = NullType::unmarshall(&data);
170 assert!(matches!(
171 result,
172 Err(AmfError::BufferTooSmall { want: 1, got: 0 })
173 ));
174 }
175
176 #[test]
177 fn test_null_try_from() {
178 let data = [TypeMarker::Null as u8];
179 let null = NullType::try_from(&data[..]).unwrap();
180 assert_eq!(null, NullType);
181 }
182
183 #[test]
184 fn test_null_display() {
185 assert_eq!(format!("{}", NullType), "null");
186 }
187
188 #[test]
190 fn test_undefined_marshall() {
191 let undefined = UndefinedType;
192 let data = undefined.marshall().unwrap();
193 assert_eq!(data, vec![TypeMarker::Undefined as u8]);
194 }
195
196 #[test]
197 fn test_undefined_marshall_length() {
198 let undefined = UndefinedType;
199 assert_eq!(undefined.marshall_length(), 1);
200 }
201
202 #[test]
203 fn test_undefined_unmarshall_valid() {
204 let data = [TypeMarker::Undefined as u8];
205 let (undefined, bytes_read) = UndefinedType::unmarshall(&data).unwrap();
206 assert_eq!(bytes_read, 1);
207 assert_eq!(undefined, UndefinedType);
208 }
209
210 #[test]
211 fn test_undefined_unmarshall_buffer_too_small() {
212 let data = [];
213 let result = UndefinedType::unmarshall(&data);
214 assert!(matches!(
215 result,
216 Err(AmfError::BufferTooSmall { want: 1, got: 0 })
217 ));
218 }
219
220 #[test]
221 fn test_undefined_try_from() {
222 let data = [TypeMarker::Undefined as u8];
223 let undefined = UndefinedType::try_from(&data[..]).unwrap();
224 assert_eq!(undefined, UndefinedType);
225 }
226
227 #[test]
228 fn test_undefined_display() {
229 assert_eq!(format!("{}", UndefinedType), "undefined");
230 }
231
232 #[test]
234 fn test_generic_marker_type() {
235 assert_eq!(NullType::TM, TypeMarker::Null);
237
238 assert_eq!(UndefinedType::TM, TypeMarker::Undefined);
240 }
241
242 fn calculate_hash<T: Hash>(t: &T) -> u64 {
244 let mut hasher = DefaultHasher::new();
245 t.hash(&mut hasher);
246 hasher.finish()
247 }
248
249 #[test]
250 fn null_and_undefined_clone_eq_hash() {
251 let n1 = NullType::default(); let n2 = n1.clone();
254 assert_eq!(n1, n2);
255
256 let u1 = UndefinedType::default();
257 let u2 = u1.clone();
258 assert_eq!(u1, u2);
259
260 assert_eq!(calculate_hash(&n1), calculate_hash(&n2));
262 assert_eq!(calculate_hash(&u1), calculate_hash(&u2));
263
264 assert_ne!(calculate_hash(&n1), calculate_hash(&u1));
266 }
267}