unity_asset_core/
unity_value.rs

1//! Unity value types
2//!
3//! This module defines the UnityValue enum and related functionality
4//! for representing Unity asset values in a type-safe manner.
5
6use indexmap::IndexMap;
7use serde::{Deserialize, Serialize};
8use std::fmt;
9
10/// A Unity value that can be stored in a Unity class
11#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12#[serde(untagged)]
13pub enum UnityValue {
14    Null,
15    Bool(bool),
16    Integer(i64),
17    Float(f64),
18    String(String),
19    Array(Vec<UnityValue>),
20    Object(IndexMap<String, UnityValue>),
21}
22
23impl UnityValue {
24    /// Check if the value is null
25    pub fn is_null(&self) -> bool {
26        matches!(self, UnityValue::Null)
27    }
28
29    /// Get as boolean
30    pub fn as_bool(&self) -> Option<bool> {
31        match self {
32            UnityValue::Bool(b) => Some(*b),
33            _ => None,
34        }
35    }
36
37    /// Get as integer
38    pub fn as_i64(&self) -> Option<i64> {
39        match self {
40            UnityValue::Integer(i) => Some(*i),
41            _ => None,
42        }
43    }
44
45    /// Get as float
46    pub fn as_f64(&self) -> Option<f64> {
47        match self {
48            UnityValue::Float(f) => Some(*f),
49            UnityValue::Integer(i) => Some(*i as f64),
50            _ => None,
51        }
52    }
53
54    /// Get as string
55    pub fn as_str(&self) -> Option<&str> {
56        match self {
57            UnityValue::String(s) => Some(s),
58            _ => None,
59        }
60    }
61
62    /// Get as array
63    pub fn as_array(&self) -> Option<&Vec<UnityValue>> {
64        match self {
65            UnityValue::Array(arr) => Some(arr),
66            _ => None,
67        }
68    }
69
70    /// Get as object
71    pub fn as_object(&self) -> Option<&IndexMap<String, UnityValue>> {
72        match self {
73            UnityValue::Object(obj) => Some(obj),
74            _ => None,
75        }
76    }
77
78    /// Get mutable reference as object
79    pub fn as_object_mut(&mut self) -> Option<&mut IndexMap<String, UnityValue>> {
80        match self {
81            UnityValue::Object(obj) => Some(obj),
82            _ => None,
83        }
84    }
85}
86
87impl fmt::Display for UnityValue {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        match self {
90            UnityValue::Null => write!(f, "null"),
91            UnityValue::Bool(b) => write!(f, "{}", b),
92            UnityValue::Integer(i) => write!(f, "{}", i),
93            UnityValue::Float(fl) => write!(f, "{}", fl),
94            UnityValue::String(s) => write!(f, "{}", s),
95            UnityValue::Array(arr) => {
96                write!(f, "[")?;
97                for (i, item) in arr.iter().enumerate() {
98                    if i > 0 {
99                        write!(f, ", ")?;
100                    }
101                    write!(f, "{}", item)?;
102                }
103                write!(f, "]")
104            }
105            UnityValue::Object(obj) => {
106                write!(f, "{{")?;
107                for (i, (key, value)) in obj.iter().enumerate() {
108                    if i > 0 {
109                        write!(f, ", ")?;
110                    }
111                    write!(f, "{}: {}", key, value)?;
112                }
113                write!(f, "}}")
114            }
115        }
116    }
117}
118
119// Conversion implementations
120impl From<bool> for UnityValue {
121    fn from(b: bool) -> Self {
122        UnityValue::Bool(b)
123    }
124}
125
126impl From<i32> for UnityValue {
127    fn from(i: i32) -> Self {
128        UnityValue::Integer(i as i64)
129    }
130}
131
132impl From<i64> for UnityValue {
133    fn from(i: i64) -> Self {
134        UnityValue::Integer(i)
135    }
136}
137
138impl From<f32> for UnityValue {
139    fn from(f: f32) -> Self {
140        UnityValue::Float(f as f64)
141    }
142}
143
144impl From<f64> for UnityValue {
145    fn from(f: f64) -> Self {
146        UnityValue::Float(f)
147    }
148}
149
150impl From<String> for UnityValue {
151    fn from(s: String) -> Self {
152        UnityValue::String(s)
153    }
154}
155
156impl From<&str> for UnityValue {
157    fn from(s: &str) -> Self {
158        UnityValue::String(s.to_string())
159    }
160}
161
162impl From<Vec<UnityValue>> for UnityValue {
163    fn from(arr: Vec<UnityValue>) -> Self {
164        UnityValue::Array(arr)
165    }
166}
167
168impl From<IndexMap<String, UnityValue>> for UnityValue {
169    fn from(obj: IndexMap<String, UnityValue>) -> Self {
170        UnityValue::Object(obj)
171    }
172}
173
174#[cfg(test)]
175mod tests {
176    use super::*;
177
178    #[test]
179    fn test_unity_value_creation() {
180        let val = UnityValue::String("test".to_string());
181        assert_eq!(val.as_str(), Some("test"));
182    }
183
184    #[test]
185    fn test_unity_value_conversions() {
186        // Test various value types
187        let bool_val: UnityValue = true.into();
188        assert_eq!(bool_val.as_bool(), Some(true));
189
190        let int_val: UnityValue = 42i32.into();
191        assert_eq!(int_val.as_i64(), Some(42));
192
193        let float_val: UnityValue = std::f64::consts::PI.into();
194        assert_eq!(float_val.as_f64(), Some(std::f64::consts::PI));
195
196        let string_val: UnityValue = "test".into();
197        assert_eq!(string_val.as_str(), Some("test"));
198
199        // Test null
200        let null_val = UnityValue::Null;
201        assert!(null_val.is_null());
202    }
203
204    #[test]
205    fn test_unity_value_display() {
206        let val = UnityValue::String("test".to_string());
207        assert_eq!(format!("{}", val), "test");
208
209        let val = UnityValue::Integer(42);
210        assert_eq!(format!("{}", val), "42");
211
212        let val = UnityValue::Bool(true);
213        assert_eq!(format!("{}", val), "true");
214    }
215}