1use std::fmt;
2
3use crate::error::FieldValueConversionError;
4
5#[derive(Clone)]
10pub enum FieldValue {
11 Bool(bool),
12 I32(i32),
13 I64(i64),
14 U32(u32),
15 U64(u64),
16 F32(f32),
17 String(Vec<u8>),
20 Vector2([f32; 2]),
21 Vector3([f32; 3]),
22 Vector4([f32; 4]),
23 QAngle([f32; 3]),
25}
26
27impl fmt::Debug for FieldValue {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 match self {
30 Self::Bool(v) => write!(f, "{v}"),
31 Self::I32(v) => write!(f, "{v}"),
32 Self::I64(v) => write!(f, "{v}"),
33 Self::U32(v) => write!(f, "{v}"),
34 Self::U64(v) => write!(f, "{v}"),
35 Self::F32(v) => write!(f, "{v}"),
36 Self::String(v) => write!(f, "{}", String::from_utf8_lossy(v)),
37 Self::Vector2(v) => write!(f, "[{}, {}]", v[0], v[1]),
38 Self::Vector3(v) => write!(f, "[{}, {}, {}]", v[0], v[1], v[2]),
39 Self::Vector4(v) => write!(f, "[{}, {}, {}, {}]", v[0], v[1], v[2], v[3]),
40 Self::QAngle(v) => write!(f, "QAngle({}, {}, {})", v[0], v[1], v[2]),
41 }
42 }
43}
44
45impl fmt::Display for FieldValue {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 fmt::Debug::fmt(self, f)
48 }
49}
50
51impl serde::Serialize for FieldValue {
52 fn serialize<S: serde::Serializer>(
53 &self,
54 serializer: S,
55 ) -> std::result::Result<S::Ok, S::Error> {
56 match self {
57 Self::Bool(v) => serializer.serialize_bool(*v),
58 Self::I32(v) => serializer.serialize_i32(*v),
59 Self::I64(v) => serializer.serialize_i64(*v),
60 Self::U32(v) => serializer.serialize_u32(*v),
61 Self::U64(v) => serializer.serialize_u64(*v),
62 Self::F32(v) => serializer.serialize_f32(*v),
63 Self::String(v) => serializer.serialize_str(&String::from_utf8_lossy(v)),
64 Self::Vector2(v) => v.serialize(serializer),
65 Self::Vector3(v) => v.serialize(serializer),
66 Self::Vector4(v) => v.serialize(serializer),
67 Self::QAngle(v) => v.serialize(serializer),
68 }
69 }
70}
71
72macro_rules! impl_try_from_signed {
75 ($($ty:ty),+) => {
76 $(
77 impl TryFrom<FieldValue> for $ty {
78 type Error = FieldValueConversionError;
79 fn try_from(v: FieldValue) -> std::result::Result<Self, Self::Error> {
80 match v {
81 FieldValue::I32(val) => <$ty>::try_from(val).map_err(|_| FieldValueConversionError),
82 FieldValue::I64(val) => <$ty>::try_from(val).map_err(|_| FieldValueConversionError),
83 _ => Err(FieldValueConversionError),
84 }
85 }
86 }
87 )+
88 }
89}
90
91macro_rules! impl_try_from_unsigned {
94 ($($ty:ty),+) => {
95 $(
96 impl TryFrom<FieldValue> for $ty {
97 type Error = FieldValueConversionError;
98 fn try_from(v: FieldValue) -> std::result::Result<Self, Self::Error> {
99 match v {
100 FieldValue::U32(val) => <$ty>::try_from(val).map_err(|_| FieldValueConversionError),
101 FieldValue::U64(val) => <$ty>::try_from(val).map_err(|_| FieldValueConversionError),
102 _ => Err(FieldValueConversionError),
103 }
104 }
105 }
106 )+
107 }
108}
109
110impl_try_from_signed!(i8, i16, i32, i64);
111impl_try_from_unsigned!(u8, u16, u32, u64);
112
113impl TryFrom<FieldValue> for f32 {
114 type Error = FieldValueConversionError;
115 fn try_from(v: FieldValue) -> std::result::Result<Self, Self::Error> {
116 match v {
117 FieldValue::F32(val) => Ok(val),
118 _ => Err(FieldValueConversionError),
119 }
120 }
121}
122
123impl TryFrom<FieldValue> for bool {
124 type Error = FieldValueConversionError;
125 fn try_from(v: FieldValue) -> std::result::Result<Self, Self::Error> {
126 match v {
127 FieldValue::Bool(val) => Ok(val),
128 _ => Err(FieldValueConversionError),
129 }
130 }
131}
132
133impl TryFrom<FieldValue> for [f32; 2] {
134 type Error = FieldValueConversionError;
135 fn try_from(v: FieldValue) -> std::result::Result<Self, Self::Error> {
136 match v {
137 FieldValue::Vector2(val) => Ok(val),
138 _ => Err(FieldValueConversionError),
139 }
140 }
141}
142
143impl TryFrom<FieldValue> for [f32; 3] {
144 type Error = FieldValueConversionError;
145 fn try_from(v: FieldValue) -> std::result::Result<Self, Self::Error> {
146 match v {
147 FieldValue::Vector3(val) | FieldValue::QAngle(val) => Ok(val),
148 _ => Err(FieldValueConversionError),
149 }
150 }
151}
152
153impl TryFrom<FieldValue> for [f32; 4] {
154 type Error = FieldValueConversionError;
155 fn try_from(v: FieldValue) -> std::result::Result<Self, Self::Error> {
156 match v {
157 FieldValue::Vector4(val) => Ok(val),
158 _ => Err(FieldValueConversionError),
159 }
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 #[test]
170 fn try_from_i32_to_i32() {
171 let v = FieldValue::I32(42);
172 assert_eq!(i32::try_from(v).unwrap(), 42);
173 }
174
175 #[test]
176 fn try_from_i64_to_i32() {
177 let v = FieldValue::I64(100);
178 assert_eq!(i32::try_from(v).unwrap(), 100);
179 }
180
181 #[test]
182 fn try_from_u32_to_u32() {
183 let v = FieldValue::U32(999);
184 assert_eq!(u32::try_from(v).unwrap(), 999);
185 }
186
187 #[test]
188 fn try_from_u64_to_u16() {
189 let v = FieldValue::U64(65535);
190 assert_eq!(u16::try_from(v).unwrap(), 65535);
191 }
192
193 #[test]
194 fn try_from_f32() {
195 let v = FieldValue::F32(1.5);
196 assert!((f32::try_from(v).unwrap() - 1.5).abs() < f32::EPSILON);
197 }
198
199 #[test]
200 fn try_from_bool() {
201 let v = FieldValue::Bool(true);
202 assert!(bool::try_from(v).unwrap());
203 }
204
205 #[test]
206 fn try_from_vector2() {
207 let v = FieldValue::Vector2([1.0, 2.0]);
208 assert_eq!(<[f32; 2]>::try_from(v).unwrap(), [1.0, 2.0]);
209 }
210
211 #[test]
212 fn try_from_vector3() {
213 let v = FieldValue::Vector3([1.0, 2.0, 3.0]);
214 assert_eq!(<[f32; 3]>::try_from(v).unwrap(), [1.0, 2.0, 3.0]);
215 }
216
217 #[test]
218 fn try_from_vector4() {
219 let v = FieldValue::Vector4([1.0, 2.0, 3.0, 4.0]);
220 assert_eq!(<[f32; 4]>::try_from(v).unwrap(), [1.0, 2.0, 3.0, 4.0]);
221 }
222
223 #[test]
224 fn try_from_qangle_to_f32_3() {
225 let v = FieldValue::QAngle([10.0, 20.0, 30.0]);
226 assert_eq!(<[f32; 3]>::try_from(v).unwrap(), [10.0, 20.0, 30.0]);
227 }
228
229 #[test]
230 fn try_from_i64_overflow_to_i8() {
231 let v = FieldValue::I64(200);
232 assert!(i8::try_from(v).is_err());
233 }
234
235 #[test]
236 fn try_from_u32_to_signed_fails() {
237 let v = FieldValue::U32(1);
238 assert!(i32::try_from(v).is_err());
239 }
240
241 #[test]
242 fn try_from_i32_to_unsigned_fails() {
243 let v = FieldValue::I32(1);
244 assert!(u32::try_from(v).is_err());
245 }
246
247 #[test]
250 fn debug_bool() {
251 assert_eq!(format!("{:?}", FieldValue::Bool(true)), "true");
252 }
253
254 #[test]
255 fn debug_i32() {
256 assert_eq!(format!("{:?}", FieldValue::I32(-42)), "-42");
257 }
258
259 #[test]
260 fn debug_string_utf8() {
261 let v = FieldValue::String(b"hello".to_vec());
262 assert_eq!(format!("{:?}", v), "hello");
263 }
264
265 #[test]
266 fn debug_string_invalid_utf8_no_panic() {
267 let v = FieldValue::String(vec![0xFF, 0xFE]);
268 let s = format!("{:?}", v);
269 assert!(!s.is_empty());
270 }
271
272 #[test]
273 fn debug_vector3() {
274 let v = FieldValue::Vector3([1.0, 2.0, 3.0]);
275 assert_eq!(format!("{:?}", v), "[1, 2, 3]");
276 }
277
278 #[test]
279 fn debug_qangle() {
280 let v = FieldValue::QAngle([1.0, 2.0, 3.0]);
281 assert!(format!("{:?}", v).starts_with("QAngle("));
282 }
283
284 #[test]
285 fn display_delegates_to_debug() {
286 let v = FieldValue::Bool(false);
287 assert_eq!(format!("{}", v), format!("{:?}", v));
288 }
289
290 #[test]
293 fn serialize_bool_and_numbers() {
294 let b = serde_json::to_value(FieldValue::Bool(true)).unwrap();
295 assert_eq!(b, serde_json::json!(true));
296
297 let n = serde_json::to_value(FieldValue::I32(-7)).unwrap();
298 assert_eq!(n, serde_json::json!(-7));
299
300 let u = serde_json::to_value(FieldValue::U32(42)).unwrap();
301 assert_eq!(u, serde_json::json!(42));
302 }
303
304 #[test]
305 fn serialize_string_and_vector() {
306 let s = serde_json::to_value(FieldValue::String(b"hi".to_vec())).unwrap();
307 assert_eq!(s, serde_json::json!("hi"));
308
309 let v = serde_json::to_value(FieldValue::Vector3([1.0, 2.0, 3.0])).unwrap();
310 assert!(v.is_array());
311 assert_eq!(v.as_array().unwrap().len(), 3);
312 }
313}