aboutsummaryrefslogtreecommitdiff
path: root/src/classes/mod.rs
blob: f7b89cbe5550344da9b2a3a70a009b7e53565748 (plain)
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
pub mod assetinfo;
pub mod gameobject;
pub mod pptr;
pub mod streaminginfo;
pub mod texture2d;
pub mod transform;
pub mod vectors;

use crate::object::Value;
use anyhow::Result;
use assetinfo::AssetInfo;
use gameobject::GameObject;
use pptr::PPtr;
use serde::Serialize;
use std::collections::BTreeMap;
use streaminginfo::StreamingInfo;
use texture2d::Texture2D;
use transform::Transform;

#[derive(Debug, Serialize)]
pub enum HValue {
    AssetInfo(AssetInfo),
    GameObject(GameObject),
    Transform(Transform),
    PPtr(PPtr),
    Texture2D(Texture2D),
    StreamingInfo(StreamingInfo),

    Pair(Box<HValue>, Box<HValue>),
    Value([Value; 1]),
    Map(BTreeMap<String, HValue>),
    Array(Vec<HValue>),
    Object {
        class: String,
        fields: BTreeMap<String, HValue>,
    },
}

impl HValue {
    pub fn from_value(v: Value) -> Result<HValue> {
        Ok(match v {
            value @ Value::Object { .. } => {
                let class = value.class_name().unwrap();
                match class.as_str() {
                    x if x.starts_with("PPtr<") => Self::PPtr(PPtr::from_value(value)?),
                    "AssetInfo" => Self::AssetInfo(AssetInfo::from_value(value)?),
                    "GameObject" => Self::GameObject(GameObject::from_value(value)?),
                    "Transform" => Self::Transform(Transform::from_value(value)?),
                    "Texture2D" => Self::Texture2D(Texture2D::from_value(value)?),
                    "StreamingInfo" => Self::StreamingInfo(StreamingInfo::from_value(value)?),
                    _ => {
                        let Value::Object { class, fields } = value else {
                            unreachable!()
                        };
                        let mut fields = fields
                            .into_iter()
                            .map(|(k, v)| Ok((k, HValue::from_value(v)?)))
                            .collect::<Result<BTreeMap<_, _>>>()?;
                        match class.as_str() {
                            "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 },
                        }
                    }
                }
            }
            Value::Array(a) => Self::Array(
                a.into_iter()
                    .map(|e| HValue::from_value(e))
                    .collect::<Result<Vec<_>>>()?,
            ),
            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
        }
    }
    pub fn as_array(self) -> Option<Vec<HValue>> {
        if let HValue::Array(v) = self {
            Some(v)
        } else {
            None
        }
    }
    pub fn as_class(self, name: &str) -> Option<BTreeMap<String, HValue>> {
        if let HValue::Object { class, fields } = self {
            if class == name { Some(fields) } else { None }
        } else {
            None
        }
    }
}

pub trait FromValue: Sized {
    fn from_value(v: Value) -> Result<Self>;
}

impl Value {
    pub(self) fn parse<T: FromValue>(self) -> Result<T> {
        T::from_value(self)
    }
}