use crate::object::Value; use anyhow::Result; use serde::Serialize; use std::collections::BTreeMap; #[derive(Serialize)] pub enum HValue { PPtr(PPtr), Pair(Box, Box), Value([Value; 1]), Map(BTreeMap), AssetInfo(AssetInfo), Array(Vec), Object { class: String, fields: BTreeMap, }, } impl HValue { pub fn from_value(v: Value) -> Result { Ok(match v { Value::Array(a) => Self::Array( a.into_iter() .map(|e| HValue::from_value(e)) .collect::>>()?, ), Value::Object { class, fields } => { let mut fields = fields .into_iter() .map(|(k, v)| Ok((k, HValue::from_value(v)?))) .collect::>>()?; 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 { 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, }