1use crate::amf0::type_marker::TypeMarker;
2use crate::errors::AmfError;
3use crate::traits::{Marshall, MarshallLength, Unmarshall};
4use std::fmt::{Display, Formatter};
5use std::ops::Deref;
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash)]
13pub struct BooleanType {
14 type_marker: TypeMarker,
15 value: bool,
16}
17
18impl BooleanType {
19 pub fn new(value: bool) -> Self {
20 Self {
21 type_marker: TypeMarker::Boolean,
22 value,
23 }
24 }
25}
26
27impl Marshall for BooleanType {
28 fn marshall(&self) -> Result<Vec<u8>, AmfError> {
29 debug_assert!(self.type_marker == TypeMarker::Boolean);
30 let mut buf = [0u8; 2];
31 buf[0] = self.type_marker as u8; buf[1] = self.value as u8;
33 Ok(buf.to_vec())
34 }
35}
36
37impl MarshallLength for BooleanType {
38 fn marshall_length(&self) -> usize {
39 2 }
41}
42
43impl Unmarshall for BooleanType {
44 fn unmarshall(buf: &[u8]) -> Result<(Self, usize), AmfError> {
45 if buf.len() < 2 {
46 return Err(AmfError::BufferTooSmall {
47 want: 2,
48 got: buf.len(),
49 });
50 }
51 let type_marker = TypeMarker::try_from(buf[0])?; if type_marker != TypeMarker::Boolean {
53 return Err(AmfError::TypeMarkerValueMismatch {
54 want: TypeMarker::Boolean as u8,
55 got: buf[0],
56 });
57 }
58 let value = buf[1] != 0;
59 Ok((Self { type_marker, value }, 2))
60 }
61}
62
63impl TryFrom<&[u8]> for BooleanType {
66 type Error = AmfError;
67
68 fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
69 Self::unmarshall(buf).map(|(b, _)| b)
70 }
71}
72
73impl TryFrom<Vec<u8>> for BooleanType {
74 type Error = AmfError;
75
76 fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
77 Self::try_from(vec.as_slice())
78 }
79}
80
81impl TryFrom<BooleanType> for Vec<u8> {
82 type Error = AmfError;
83
84 fn try_from(value: BooleanType) -> Result<Self, Self::Error> {
85 value.marshall()
86 }
87}
88
89impl From<bool> for BooleanType {
90 fn from(value: bool) -> Self {
91 Self::new(value)
92 }
93}
94
95impl From<BooleanType> for bool {
96 fn from(value: BooleanType) -> Self {
97 value.value
98 }
99}
100
101impl AsRef<bool> for BooleanType {
102 fn as_ref(&self) -> &bool {
103 &self.value
104 }
105}
106
107impl Deref for BooleanType {
108 type Target = bool;
109
110 fn deref(&self) -> &bool {
111 self.as_ref()
112 }
113}
114
115impl Display for BooleanType {
116 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
117 write!(f, "{}", self.value)
118 }
119}
120
121impl Default for BooleanType {
122 fn default() -> Self {
123 Self::new(false)
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130 use crate::amf0::type_marker::TypeMarker;
131 use crate::errors::AmfError;
132 use std::convert::TryFrom;
133 use std::fmt::Write as _;
134 use std::hash::{DefaultHasher, Hash, Hasher};
135 #[test]
138 fn boolean_round_trip_true() {
139 let orig = BooleanType::new(true);
140 let bytes = orig.marshall().expect("marshall should succeed");
141 assert_eq!(bytes, vec![TypeMarker::Boolean as u8, 1]);
143 let (decoded, len) = BooleanType::unmarshall(&bytes).expect("unmarshall should succeed");
145 assert_eq!(len, 2);
146 assert_eq!(decoded.value, true);
147 let from_buf = BooleanType::try_from(&bytes[..]).unwrap();
149 assert_eq!(from_buf.value, true);
150 let from_bool: BooleanType = false.into();
152 assert_eq!(from_bool.value, false);
153 assert_eq!(orig.as_ref(), &true);
155 assert_eq!(*orig, true);
156 let mut s = String::new();
158 write!(&mut s, "{}", orig).unwrap();
159 assert_eq!(s, "true");
160 }
161
162 #[test]
163 fn boolean_round_trip_false() {
164 let orig = BooleanType::new(false);
165 let bytes = orig.marshall().unwrap();
166 assert_eq!(bytes, vec![TypeMarker::Boolean as u8, 0]);
167 let (decoded, _) = BooleanType::unmarshall(&bytes).unwrap();
168 assert!(!decoded.value);
169 }
170
171 #[test]
172 fn boolean_unmarshall_errors() {
173 let err = BooleanType::unmarshall(&[TypeMarker::Boolean as u8]).unwrap_err();
175 match err {
176 AmfError::BufferTooSmall { want, got } => {
177 assert_eq!(want, 2);
178 assert_eq!(got, 1);
179 }
180 _ => panic!("expected BufferTooSmall"),
181 }
182 let bad = vec![TypeMarker::Number as u8, 1];
184 let err2 = BooleanType::unmarshall(&bad).unwrap_err();
185 match err2 {
186 AmfError::TypeMarkerValueMismatch { want, got } => {
187 assert_eq!(want, TypeMarker::Boolean as u8);
188 assert_eq!(got, TypeMarker::Number as u8);
189 }
190 _ => panic!("expected TypeMarkerValueMismatch"),
191 }
192 }
193
194 fn calculate_hash<T: Hash>(t: &T) -> u64 {
195 let mut hasher = DefaultHasher::new();
196 t.hash(&mut hasher);
197 hasher.finish()
198 }
199
200 #[test]
201 fn clone_preserves_equality() {
202 let orig = BooleanType::new(true);
203 let cloned = orig.clone();
204 assert_eq!(orig, cloned);
205 }
206
207 #[test]
208 fn eq_and_neq_behaviour() {
209 let a = BooleanType::new(true);
210 let b = BooleanType::new(true);
211 let c = BooleanType::new(false);
212
213 assert_eq!(a, b);
214 assert_ne!(a, c);
215 }
216
217 #[test]
218 fn equal_values_have_same_hash() {
219 let x = BooleanType::new(true);
220 let y = BooleanType::new(true);
221
222 assert_eq!(calculate_hash(&x), calculate_hash(&y));
223 }
224
225 #[test]
226 fn different_values_have_different_hash() {
227 let x = BooleanType::new(true);
228 let y = BooleanType::new(false);
229
230 assert_ne!(calculate_hash(&x), calculate_hash(&y));
231 }
232
233 #[test]
234 fn clone_preserves_hash() {
235 let orig = BooleanType::new(false);
236 let cloned = orig.clone();
237
238 assert_eq!(calculate_hash(&orig), calculate_hash(&cloned));
239 }
240}