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