Skip to main content

source2_demo/entity/field/
value.rs

1//! Field value types and conversions.
2//!
3//! This module defines the [`FieldValue`] enum which represents all possible
4//! types that entity properties can have.
5
6use crate::error::FieldValueError;
7
8/// Value type for entity properties.
9///
10/// This enum represents all possible types that can be stored in entity properties.
11/// Use [`TryInto`] to convert to Rust types, or use the `property!` macro for
12/// convenient access.
13///
14/// # Variants
15///
16/// - Numeric types: `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`
17/// - Floating point: `f32`
18/// - Text: `String`
19/// - Vectors: 2D, 3D, and 4D float arrays
20/// - Boolean: `bool`
21///
22/// # Examples
23///
24/// ## Manual conversion
25///
26/// ```no_run
27/// use source2_demo::prelude::*;
28///
29/// # fn example(entity: &Entity) -> anyhow::Result<()> {
30/// let field_value = entity.get_property_by_name("m_iHealth")?;
31/// let health: i32 = field_value.try_into()?;
32/// println!("Health: {}", health);
33/// # Ok(())
34/// # }
35/// ```
36///
37/// ## Using property! macro
38///
39/// ```no_run
40/// use source2_demo::prelude::*;
41///
42/// # fn example(entity: &Entity) -> anyhow::Result<()> {
43/// // Type is inferred
44/// let health: i32 = property!(entity, "m_iHealth");
45/// # Ok(())
46/// # }
47/// ```
48#[derive(Debug, Clone, PartialEq)]
49pub enum FieldValue {
50    /// Boolean value
51    Boolean(bool),
52    /// String value
53    String(String),
54    /// 32-bit floating point value
55    Float(f32),
56
57    /// 2D vector
58    Vector2D([f32; 2]),
59    /// 3D vector
60    Vector3D([f32; 3]),
61    /// 4D vector
62    Vector4D([f32; 4]),
63
64    /// Signed 8-bit integer
65    Signed8(i8),
66    /// Signed 16-bit integer
67    Signed16(i16),
68    /// Signed 32-bit integer
69    Signed32(i32),
70    /// Signed 64-bit integer
71    Signed64(i64),
72
73    /// Unsigned 8-bit integer
74    Unsigned8(u8),
75    /// Unsigned 16-bit integer
76    Unsigned16(u16),
77    /// Unsigned 32-bit integer
78    Unsigned32(u32),
79    /// Unsigned 64-bit integer
80    Unsigned64(u64),
81}
82
83impl TryInto<String> for FieldValue {
84    type Error = FieldValueError;
85
86    fn try_into(self) -> Result<String, FieldValueError> {
87        if let FieldValue::String(x) = self {
88            Ok(x)
89        } else {
90            Err(FieldValueError::ConversionError(
91                format!("{:?}", self),
92                "String".to_string(),
93            ))
94        }
95    }
96}
97
98impl TryInto<String> for &FieldValue {
99    type Error = FieldValueError;
100
101    fn try_into(self) -> Result<String, FieldValueError> {
102        if let FieldValue::String(x) = self {
103            Ok(x.to_owned())
104        } else {
105            Err(FieldValueError::ConversionError(
106                format!("{:?}", self),
107                "String".to_string(),
108            ))
109        }
110    }
111}
112
113impl TryInto<[f32; 2]> for FieldValue {
114    type Error = FieldValueError;
115
116    fn try_into(self) -> Result<[f32; 2], FieldValueError> {
117        if let FieldValue::Vector2D(x) = self {
118            Ok(x)
119        } else {
120            Err(FieldValueError::ConversionError(
121                format!("{:?}", self),
122                "[f32; 2]".to_string(),
123            ))
124        }
125    }
126}
127
128impl TryInto<[f32; 2]> for &FieldValue {
129    type Error = FieldValueError;
130
131    fn try_into(self) -> Result<[f32; 2], FieldValueError> {
132        if let FieldValue::Vector2D(x) = self {
133            Ok(*x)
134        } else {
135            Err(FieldValueError::ConversionError(
136                format!("{:?}", self),
137                "[f32; 2]".to_string(),
138            ))
139        }
140    }
141}
142
143impl TryInto<(f32, f32)> for FieldValue {
144    type Error = FieldValueError;
145
146    fn try_into(self) -> Result<(f32, f32), FieldValueError> {
147        if let FieldValue::Vector2D(x) = self {
148            Ok(x.into())
149        } else {
150            Err(FieldValueError::ConversionError(
151                format!("{:?}", self),
152                "(f32, f32)".to_string(),
153            ))
154        }
155    }
156}
157
158impl TryInto<(f32, f32)> for &FieldValue {
159    type Error = FieldValueError;
160
161    fn try_into(self) -> Result<(f32, f32), FieldValueError> {
162        if let FieldValue::Vector2D(x) = self {
163            Ok((*x).into())
164        } else {
165            Err(FieldValueError::ConversionError(
166                format!("{:?}", self),
167                "(f32, f32)".to_string(),
168            ))
169        }
170    }
171}
172
173impl TryInto<[f32; 3]> for FieldValue {
174    type Error = FieldValueError;
175
176    fn try_into(self) -> Result<[f32; 3], FieldValueError> {
177        if let FieldValue::Vector3D(x) = self {
178            Ok(x)
179        } else {
180            Err(FieldValueError::ConversionError(
181                format!("{:?}", self),
182                "[f32; 3]".to_string(),
183            ))
184        }
185    }
186}
187
188impl TryInto<[f32; 3]> for &FieldValue {
189    type Error = FieldValueError;
190
191    fn try_into(self) -> Result<[f32; 3], FieldValueError> {
192        if let FieldValue::Vector3D(x) = self {
193            Ok(*x)
194        } else {
195            Err(FieldValueError::ConversionError(
196                format!("{:?}", self),
197                "[f32; 3]".to_string(),
198            ))
199        }
200    }
201}
202
203impl TryInto<(f32, f32, f32)> for FieldValue {
204    type Error = FieldValueError;
205
206    fn try_into(self) -> Result<(f32, f32, f32), FieldValueError> {
207        if let FieldValue::Vector3D(x) = self {
208            Ok(x.into())
209        } else {
210            Err(FieldValueError::ConversionError(
211                format!("{:?}", self),
212                "(f32, f32, f32)".to_string(),
213            ))
214        }
215    }
216}
217
218impl TryInto<(f32, f32, f32)> for &FieldValue {
219    type Error = FieldValueError;
220
221    fn try_into(self) -> Result<(f32, f32, f32), FieldValueError> {
222        if let FieldValue::Vector3D(x) = self {
223            Ok((*x).into())
224        } else {
225            Err(FieldValueError::ConversionError(
226                format!("{:?}", self),
227                "(f32, f32, f32)".to_string(),
228            ))
229        }
230    }
231}
232
233impl TryInto<[f32; 4]> for FieldValue {
234    type Error = FieldValueError;
235
236    fn try_into(self) -> Result<[f32; 4], FieldValueError> {
237        if let FieldValue::Vector4D(x) = self {
238            Ok(x)
239        } else {
240            Err(FieldValueError::ConversionError(
241                format!("{:?}", self),
242                "[f32; 4]".to_string(),
243            ))
244        }
245    }
246}
247
248impl TryInto<[f32; 4]> for &FieldValue {
249    type Error = FieldValueError;
250
251    fn try_into(self) -> Result<[f32; 4], FieldValueError> {
252        if let FieldValue::Vector4D(x) = self {
253            Ok(*x)
254        } else {
255            Err(FieldValueError::ConversionError(
256                format!("{:?}", self),
257                "[f32; 4]".to_string(),
258            ))
259        }
260    }
261}
262
263impl TryInto<(f32, f32, f32, f32)> for FieldValue {
264    type Error = FieldValueError;
265
266    fn try_into(self) -> Result<(f32, f32, f32, f32), FieldValueError> {
267        if let FieldValue::Vector4D(x) = self {
268            Ok(x.into())
269        } else {
270            Err(FieldValueError::ConversionError(
271                format!("{:?}", self),
272                "(f32, f32, f32, f32)".to_string(),
273            ))
274        }
275    }
276}
277
278impl TryInto<(f32, f32, f32, f32)> for &FieldValue {
279    type Error = FieldValueError;
280
281    fn try_into(self) -> Result<(f32, f32, f32, f32), FieldValueError> {
282        if let FieldValue::Vector4D(x) = self {
283            Ok((*x).into())
284        } else {
285            Err(FieldValueError::ConversionError(
286                format!("{:?}", self),
287                "(f32, f32, f32, f32)".to_string(),
288            ))
289        }
290    }
291}
292
293impl TryInto<Vec<f32>> for FieldValue {
294    type Error = FieldValueError;
295
296    fn try_into(self) -> Result<Vec<f32>, FieldValueError> {
297        match self {
298            FieldValue::Vector2D(x) => Ok(x.to_vec()),
299            FieldValue::Vector3D(x) => Ok(x.to_vec()),
300            FieldValue::Vector4D(x) => Ok(x.to_vec()),
301            _ => Err(FieldValueError::ConversionError(
302                format!("{:?}", self),
303                "Vec<f32>".to_string(),
304            )),
305        }
306    }
307}
308
309impl TryInto<Vec<f32>> for &FieldValue {
310    type Error = FieldValueError;
311
312    fn try_into(self) -> Result<Vec<f32>, FieldValueError> {
313        match self {
314            FieldValue::Vector2D(x) => Ok(x.to_vec()),
315            FieldValue::Vector3D(x) => Ok(x.to_vec()),
316            FieldValue::Vector4D(x) => Ok(x.to_vec()),
317            _ => Err(FieldValueError::ConversionError(
318                format!("{:?}", self),
319                "Vec<f32>".to_string(),
320            )),
321        }
322    }
323}
324
325impl TryInto<f32> for FieldValue {
326    type Error = FieldValueError;
327
328    fn try_into(self) -> Result<f32, FieldValueError> {
329        if let FieldValue::Float(x) = self {
330            Ok(x)
331        } else {
332            Err(FieldValueError::ConversionError(
333                format!("{:?}", self),
334                "f32".to_string(),
335            ))
336        }
337    }
338}
339
340impl TryInto<f32> for &FieldValue {
341    type Error = FieldValueError;
342
343    fn try_into(self) -> Result<f32, FieldValueError> {
344        if let FieldValue::Float(x) = self {
345            Ok(*x)
346        } else {
347            Err(FieldValueError::ConversionError(
348                format!("{:?}", self),
349                "f32".to_string(),
350            ))
351        }
352    }
353}
354
355impl TryInto<bool> for FieldValue {
356    type Error = FieldValueError;
357
358    fn try_into(self) -> Result<bool, FieldValueError> {
359        if let FieldValue::Boolean(x) = self {
360            Ok(x)
361        } else {
362            Err(FieldValueError::ConversionError(
363                format!("{:?}", self),
364                "bool".to_string(),
365            ))
366        }
367    }
368}
369
370impl TryInto<bool> for &FieldValue {
371    type Error = FieldValueError;
372
373    fn try_into(self) -> Result<bool, FieldValueError> {
374        if let FieldValue::Boolean(x) = self {
375            Ok(*x)
376        } else {
377            Err(FieldValueError::ConversionError(
378                format!("{:?}", self),
379                "bool".to_string(),
380            ))
381        }
382    }
383}
384
385macro_rules! impl_try_into_for_integers {
386    ($target:ty) => {
387        impl TryInto<$target> for FieldValue {
388            type Error = FieldValueError;
389
390            fn try_into(self) -> Result<$target, FieldValueError> {
391                match self {
392                    // EntityFieldType::Boolean(x) => Ok((x == 1) as $target),
393                    FieldValue::Signed8(x) => {
394                        Ok(TryInto::<$target>::try_into(x).map_err(|_| {
395                            FieldValueError::ConversionError(
396                                format!("{:?}", x),
397                                stringify!($target).to_string(),
398                            )
399                        })?)
400                    }
401                    FieldValue::Signed16(x) => {
402                        Ok(TryInto::<$target>::try_into(x).map_err(|_| {
403                            FieldValueError::ConversionError(
404                                format!("{:?}", x),
405                                stringify!($target).to_string(),
406                            )
407                        })?)
408                    }
409                    FieldValue::Signed32(x) => {
410                        Ok(TryInto::<$target>::try_into(x).map_err(|_| {
411                            FieldValueError::ConversionError(
412                                format!("{:?}", x),
413                                stringify!($target).to_string(),
414                            )
415                        })?)
416                    }
417                    FieldValue::Signed64(x) => {
418                        Ok(TryInto::<$target>::try_into(x).map_err(|_| {
419                            FieldValueError::ConversionError(
420                                format!("{:?}", x),
421                                stringify!($target).to_string(),
422                            )
423                        })?)
424                    }
425                    FieldValue::Unsigned8(x) => {
426                        Ok(TryInto::<$target>::try_into(x).map_err(|_| {
427                            FieldValueError::ConversionError(
428                                format!("{:?}", x),
429                                stringify!($target).to_string(),
430                            )
431                        })?)
432                    }
433                    FieldValue::Unsigned16(x) => {
434                        Ok(TryInto::<$target>::try_into(x).map_err(|_| {
435                            FieldValueError::ConversionError(
436                                format!("{:?}", x),
437                                stringify!($target).to_string(),
438                            )
439                        })?)
440                    }
441                    FieldValue::Unsigned32(x) => {
442                        Ok(TryInto::<$target>::try_into(x).map_err(|_| {
443                            FieldValueError::ConversionError(
444                                format!("{:?}", x),
445                                stringify!($target).to_string(),
446                            )
447                        })?)
448                    }
449                    FieldValue::Unsigned64(x) => {
450                        Ok(TryInto::<$target>::try_into(x).map_err(|_| {
451                            FieldValueError::ConversionError(
452                                format!("{:?}", x),
453                                stringify!($target).to_string(),
454                            )
455                        })?)
456                    }
457                    FieldValue::Float(x) => Ok(x as $target),
458                    _ => Err(FieldValueError::ConversionError(
459                        format!("{:?}", self),
460                        stringify!($target).to_string(),
461                    )),
462                }
463            }
464        }
465
466        impl TryInto<$target> for &FieldValue {
467            type Error = FieldValueError;
468
469            fn try_into(self) -> Result<$target, FieldValueError> {
470                match self {
471                    // EntityFieldType::Boolean(x) => Ok(x == 1 as $target),
472                    FieldValue::Signed8(x) => {
473                        Ok(TryInto::<$target>::try_into(*x).map_err(|_| {
474                            FieldValueError::ConversionError(
475                                format!("{:?}", x),
476                                stringify!($target).to_string(),
477                            )
478                        })?)
479                    }
480                    FieldValue::Signed16(x) => {
481                        Ok(TryInto::<$target>::try_into(*x).map_err(|_| {
482                            FieldValueError::ConversionError(
483                                format!("{:?}", x),
484                                stringify!($target).to_string(),
485                            )
486                        })?)
487                    }
488                    FieldValue::Signed32(x) => {
489                        Ok(TryInto::<$target>::try_into(*x).map_err(|_| {
490                            FieldValueError::ConversionError(
491                                format!("{:?}", x),
492                                stringify!($target).to_string(),
493                            )
494                        })?)
495                    }
496                    FieldValue::Signed64(x) => {
497                        Ok(TryInto::<$target>::try_into(*x).map_err(|_| {
498                            FieldValueError::ConversionError(
499                                format!("{:?}", x),
500                                stringify!($target).to_string(),
501                            )
502                        })?)
503                    }
504                    FieldValue::Unsigned8(x) => {
505                        Ok(TryInto::<$target>::try_into(*x).map_err(|_| {
506                            FieldValueError::ConversionError(
507                                format!("{:?}", x),
508                                stringify!($target).to_string(),
509                            )
510                        })?)
511                    }
512                    FieldValue::Unsigned16(x) => {
513                        Ok(TryInto::<$target>::try_into(*x).map_err(|_| {
514                            FieldValueError::ConversionError(
515                                format!("{:?}", x),
516                                stringify!($target).to_string(),
517                            )
518                        })?)
519                    }
520                    FieldValue::Unsigned32(x) => {
521                        Ok(TryInto::<$target>::try_into(*x).map_err(|_| {
522                            FieldValueError::ConversionError(
523                                format!("{:?}", x),
524                                stringify!($target).to_string(),
525                            )
526                        })?)
527                    }
528                    FieldValue::Unsigned64(x) => {
529                        Ok(TryInto::<$target>::try_into(*x).map_err(|_| {
530                            FieldValueError::ConversionError(
531                                format!("{:?}", x),
532                                stringify!($target).to_string(),
533                            )
534                        })?)
535                    }
536                    FieldValue::Float(x) => Ok(*x as $target),
537                    _ => Err(FieldValueError::ConversionError(
538                        format!("{:?}", self),
539                        stringify!($target).to_string(),
540                    )),
541                }
542            }
543        }
544    };
545}
546
547impl_try_into_for_integers!(i8);
548impl_try_into_for_integers!(i16);
549impl_try_into_for_integers!(i32);
550impl_try_into_for_integers!(i64);
551impl_try_into_for_integers!(i128);
552impl_try_into_for_integers!(u8);
553impl_try_into_for_integers!(u16);
554impl_try_into_for_integers!(u32);
555impl_try_into_for_integers!(u64);
556impl_try_into_for_integers!(u128);
557impl_try_into_for_integers!(usize);
558impl_try_into_for_integers!(isize);
559
560#[allow(dead_code)]
561impl FieldValue {
562    #[inline]
563    pub(crate) fn as_string(&self) -> String {
564        if let FieldValue::String(s) = self {
565            s.to_string()
566        } else {
567            panic!("Tried to read as String, Found {:?}", self);
568        }
569    }
570
571    #[inline]
572    pub(crate) fn as_bool(&self) -> bool {
573        if let FieldValue::Boolean(b) = self {
574            *b
575        } else {
576            panic!("Tried to read as Boolean, Found {:?}", self);
577        }
578    }
579
580    #[inline]
581    pub(crate) fn as_float(&self) -> f32 {
582        if let FieldValue::Float(f) = self {
583            *f
584        } else {
585            panic!("Tried to read as Float, Found {:?}", self);
586        }
587    }
588
589    #[inline]
590    pub(crate) fn as_vector2d(&self) -> &[f32; 2] {
591        if let FieldValue::Vector2D(v) = self {
592            v
593        } else {
594            panic!("Tried to read as Vector2D, Found {:?}", self);
595        }
596    }
597
598    #[inline]
599    pub(crate) fn as_vector(&self) -> &[f32; 3] {
600        if let FieldValue::Vector3D(v) = self {
601            v
602        } else {
603            panic!("Tried to read as Vector3D, Found {:?}", self);
604        }
605    }
606
607    #[inline]
608    pub(crate) fn as_vector4d(&self) -> &[f32; 4] {
609        if let FieldValue::Vector4D(v) = self {
610            v
611        } else {
612            panic!("Tried to read as Vector4D, Found {:?}", self);
613        }
614    }
615}