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