Skip to main content

unity_formats/
value.rs

1//! A decoded object: the value tree its type tree describes. Arrays of a primitive type are kept as typed vectors (a
2//! mesh's vertex data or a terrain's heights are millions of elements).
3
4use std::sync::Arc;
5
6use serde_json::{Map, Value as Json};
7
8/// A typed array of primitives.
9#[derive(Clone, Debug, PartialEq)]
10pub enum Array {
11    /// `bool` elements.
12    Bool(Vec<bool>),
13    /// `SInt8` elements.
14    I8(Vec<i8>),
15    /// `UInt8` / `char` elements, and `TypelessData`.
16    U8(Vec<u8>),
17    /// `short` and `SInt16` elements.
18    I16(Vec<i16>),
19    /// `unsigned short` and `UInt16` elements.
20    U16(Vec<u16>),
21    /// `int` and `SInt32` elements.
22    I32(Vec<i32>),
23    /// `unsigned int` and `UInt32` elements.
24    U32(Vec<u32>),
25    /// `long long` and `SInt64` elements.
26    I64(Vec<i64>),
27    /// `unsigned long long`, `UInt64` and `FileSize` elements.
28    U64(Vec<u64>),
29    /// `float` elements.
30    F32(Vec<f32>),
31    /// `double` elements.
32    F64(Vec<f64>),
33    /// Any other element type.
34    Values(Vec<Value>),
35}
36
37impl Array {
38    /// The number of elements.
39    pub fn len(&self) -> usize {
40        match self {
41            Array::Bool(v) => v.len(),
42            Array::I8(v) => v.len(),
43            Array::U8(v) => v.len(),
44            Array::I16(v) => v.len(),
45            Array::U16(v) => v.len(),
46            Array::I32(v) => v.len(),
47            Array::U32(v) => v.len(),
48            Array::I64(v) => v.len(),
49            Array::U64(v) => v.len(),
50            Array::F32(v) => v.len(),
51            Array::F64(v) => v.len(),
52            Array::Values(v) => v.len(),
53        }
54    }
55
56    /// Whether there are no elements.
57    pub fn is_empty(&self) -> bool {
58        self.len() == 0
59    }
60}
61
62/// A decoded value: a primitive, a string, an array, a pair or a struct of named fields.
63#[derive(Clone, Debug, PartialEq)]
64pub enum Value {
65    /// A `bool`.
66    Bool(bool),
67    /// Signed integers of any width.
68    Int(i64),
69    /// Unsigned integers of any width.
70    UInt(u64),
71    /// A `float`.
72    Float(f32),
73    /// A `double`.
74    Double(f64),
75    /// A `string`.
76    String(String),
77    /// A vector (`Array` node) or `TypelessData`.
78    Array(Array),
79    /// A `pair`.
80    Pair(Box<(Value, Value)>),
81    /// Fields in type tree order.
82    Struct(Vec<(Arc<str>, Value)>),
83}
84
85impl Value {
86    /// The field `name` of a struct.
87    pub fn get(&self, name: &str) -> Option<&Value> {
88        match self {
89            Value::Struct(fields) => fields.iter().find(|(k, _)| &**k == name).map(|(_, v)| v),
90            _ => None,
91        }
92    }
93
94    /// Follow a path of field names.
95    pub fn at(&self, path: &[&str]) -> Option<&Value> {
96        path.iter().try_fold(self, |v, k| v.get(k))
97    }
98
99    /// The value as an `i64` when it is an integer that fits.
100    pub fn as_i64(&self) -> Option<i64> {
101        match *self {
102            Value::Int(i) => Some(i),
103            Value::UInt(u) => i64::try_from(u).ok(),
104            _ => None,
105        }
106    }
107
108    /// The value when it is a `float`.
109    pub fn as_f32(&self) -> Option<f32> {
110        match *self {
111            Value::Float(f) => Some(f),
112            _ => None,
113        }
114    }
115
116    /// The value when it is a string.
117    pub fn as_str(&self) -> Option<&str> {
118        match self {
119            Value::String(s) => Some(s),
120            _ => None,
121        }
122    }
123
124    /// The value when it is a `bool`.
125    pub fn as_bool(&self) -> Option<bool> {
126        match *self {
127            Value::Bool(b) => Some(b),
128            _ => None,
129        }
130    }
131
132    /// The value when it is an array.
133    pub fn as_array(&self) -> Option<&Array> {
134        match self {
135            Value::Array(a) => Some(a),
136            _ => None,
137        }
138    }
139
140    /// The bytes of a `UInt8`, `char` or `TypelessData` array.
141    pub fn as_bytes(&self) -> Option<&[u8]> {
142        match self {
143            Value::Array(Array::U8(b)) => Some(b),
144            _ => None,
145        }
146    }
147
148    /// The value as JSON, byte arrays replaced by `bytes(b)` (e.g. a length and a digest, so a comparison need not
149    /// hold millions of numbers). Non-finite floats become strings (`"NaN"`, `"inf"`, `"-inf"`).
150    pub fn to_json(&self, bytes: &dyn Fn(&[u8]) -> Json) -> Json {
151        fn float(x: f64) -> Json {
152            serde_json::Number::from_f64(x).map_or_else(|| Json::String(format!("{x}")), Json::Number)
153        }
154        let list = |it: &mut dyn Iterator<Item = Json>| Json::Array(it.collect());
155        match self {
156            Value::Bool(b) => Json::Bool(*b),
157            Value::Int(i) => Json::from(*i),
158            Value::UInt(u) => Json::from(*u),
159            Value::Float(f) => float(f64::from(*f)),
160            Value::Double(d) => float(*d),
161            Value::String(s) => Json::String(s.clone()),
162            Value::Pair(p) => Json::Array(vec![p.0.to_json(bytes), p.1.to_json(bytes)]),
163            Value::Struct(fields) => {
164                let mut m = Map::new();
165                for (k, v) in fields {
166                    m.insert(k.to_string(), v.to_json(bytes));
167                }
168                Json::Object(m)
169            }
170            Value::Array(a) => match a {
171                Array::U8(b) => bytes(b),
172                Array::Bool(v) => list(&mut v.iter().map(|&x| Json::Bool(x))),
173                Array::I8(v) => list(&mut v.iter().map(|&x| Json::from(x))),
174                Array::I16(v) => list(&mut v.iter().map(|&x| Json::from(x))),
175                Array::U16(v) => list(&mut v.iter().map(|&x| Json::from(x))),
176                Array::I32(v) => list(&mut v.iter().map(|&x| Json::from(x))),
177                Array::U32(v) => list(&mut v.iter().map(|&x| Json::from(x))),
178                Array::I64(v) => list(&mut v.iter().map(|&x| Json::from(x))),
179                Array::U64(v) => list(&mut v.iter().map(|&x| Json::from(x))),
180                Array::F32(v) => list(&mut v.iter().map(|&x| float(f64::from(x)))),
181                Array::F64(v) => list(&mut v.iter().map(|&x| float(x))),
182                Array::Values(v) => list(&mut v.iter().map(|x| x.to_json(bytes))),
183            },
184        }
185    }
186}