1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
use crate::object::Value;
use anyhow::Result;
use serde::Serialize;
use std::collections::BTreeMap;
#[derive(Serialize)]
pub enum HValue {
PPtr(PPtr),
Pair(Box<HValue>, Box<HValue>),
Value([Value; 1]),
Map(BTreeMap<String, HValue>),
AssetInfo(AssetInfo),
Array(Vec<HValue>),
Object {
class: String,
fields: BTreeMap<String, HValue>,
},
}
impl HValue {
pub fn from_value(v: Value) -> Result<HValue> {
Ok(match v {
Value::Array(a) => Self::Array(
a.into_iter()
.map(|e| HValue::from_value(e))
.collect::<Result<Vec<_>>>()?,
),
Value::Object { class, fields } => {
let mut fields = fields
.into_iter()
.map(|(k, v)| Ok((k, HValue::from_value(v)?)))
.collect::<Result<BTreeMap<_, _>>>()?;
match class.as_str() {
x if x.starts_with("PPtr<") => {
let inner = x.strip_prefix("PPtr<").unwrap().strip_suffix(">").unwrap();
Self::PPtr(PPtr {
class: inner.to_owned(),
file_id: fields["m_FileID"].as_value().unwrap().as_i32().unwrap(),
path_id: fields["m_PathID"].as_value().unwrap().as_i64().unwrap(),
})
}
"AssetInfo" => Self::AssetInfo(AssetInfo {
preload_index: fields["preloadIndex"].as_value().unwrap().as_i32().unwrap(),
preload_size: fields["preloadSize"].as_value().unwrap().as_i32().unwrap(),
asset: fields.remove("asset").unwrap().as_pptr().unwrap(),
}),
"map" => {
let Self::Array(a) = fields.remove("Array").unwrap() else {
unreachable!()
};
Self::Map(
a.into_iter()
.map(|e| {
let Self::Pair(k, v) = e else { unreachable!() };
(k.as_value().unwrap().clone().as_string().unwrap(), *v)
})
.collect(),
)
}
"pair" => Self::Pair(
Box::new(fields.remove("first").unwrap()),
Box::new(fields.remove("second").unwrap()),
),
"vector" => fields.remove("Array").unwrap(),
_ => Self::Object { class, fields },
}
}
x => Self::Value([x]),
})
}
pub fn as_value(&self) -> Option<&Value> {
if let HValue::Value(v) = self {
Some(&v[0])
} else {
None
}
}
pub fn as_pptr(self) -> Option<PPtr> {
if let HValue::PPtr(v) = self {
Some(v)
} else {
None
}
}
}
#[derive(Debug, Serialize)]
pub struct PPtr {
class: String,
file_id: i32,
path_id: i64,
}
#[derive(Debug, Serialize)]
pub struct AssetInfo {
preload_index: i32,
preload_size: i32,
asset: PPtr,
}
|