1use std::collections::HashMap;
2use std::convert::TryInto;
3
4#[derive(Clone, Debug)]
5pub enum WorldInfoType {
6 String(String),
7 Boolean(bool),
8 Number(Number),
9 List(Vec<WorldInfoType>),
10 Map(HashMap<String, WorldInfoType>),
11 Null
12}
13
14#[derive(Clone, Debug)]
15pub enum Number {
16 Int(i64),
17 UInt(u64),
18 Float(f64),
19}
20
21impl Number {
22 pub fn as_i64(&self) -> Option<i64> {
23 match self {
24 Number::Int(i) => Some(*i),
25 _ => None,
26 }
27 }
28
29 pub fn as_u64(&self) -> Option<u64> {
30 match self {
31 Number::UInt(u) => Some(*u),
32 _ => None,
33 }
34 }
35
36 pub fn as_f64(&self) -> f64 {
37 match self {
38 Number::Int(i) => *i as f64,
39 Number::UInt(u) => *u as f64,
40 Number::Float(f) => *f,
41 }
42 }
43}
44
45macro_rules! impl_world_info_type_conversion {
47 ($variant:ident, $type:ty, $error_msg:expr) => {
48 impl TryInto<$type> for WorldInfoType {
49 type Error = String;
50
51 fn try_into(self) -> Result<$type, Self::Error> {
52 if let WorldInfoType::$variant(value) = self {
53 Ok(value)
54 } else {
55 Err($error_msg.to_string())
56 }
57 }
58 }
59
60 impl Into<WorldInfoType> for $type {
61 fn into(self) -> WorldInfoType {
62 WorldInfoType::$variant(self)
63 }
64 }
65 };
66}
67
68macro_rules! impl_number_type_conversion {
69 ($variant:ident, $type:ty) => {
70 impl Into<Number> for $type {
71 fn into(self) -> Number {
72 Number::$variant(self)
73 }
74 }
75 }
76}
77
78macro_rules! impl_world_info_number_type_conversion {
79 ($variant:ident, $type:ty) => {
80 impl Into<WorldInfoType> for $type {
81 fn into(self) -> WorldInfoType {
82 WorldInfoType::Number(Number::$variant(self))
83 }
84 }
85 }
86}
87
88impl_world_info_type_conversion!(String, String, "Not a string");
90impl_world_info_type_conversion!(Boolean, bool, "Not a boolean");
91impl_world_info_type_conversion!(List, Vec<WorldInfoType>, "Not a list");
92impl_world_info_type_conversion!(Map, HashMap<String, WorldInfoType>, "Not a map");
93impl_number_type_conversion!(Int, i64);
94impl_number_type_conversion!(UInt, u64);
95impl_number_type_conversion!(Float, f64);
96impl_world_info_number_type_conversion!(Int, i64);
97impl_world_info_number_type_conversion!(UInt, u64);
98impl_world_info_number_type_conversion!(Float, f64);
99
100impl Into<WorldInfoType> for serde_json::Value {
101 fn into(self) -> WorldInfoType {
102 match self {
103 serde_json::Value::Null => WorldInfoType::Null,
104 serde_json::Value::Bool(b) => WorldInfoType::Boolean(b),
105 serde_json::Value::Number(number) => WorldInfoType::Number(number.into()),
106 serde_json::Value::String(s) => WorldInfoType::String(s),
107 serde_json::Value::Array(values) => WorldInfoType::List(values.into_iter().map(|x| x.into()).collect()),
108 serde_json::Value::Object(map) => WorldInfoType::Map(map.into_iter().map(|(k, v)| (k, v.into())).collect()),
109 }
110 }
111}
112
113impl Into<WorldInfoType> for &serde_json::Value {
114 fn into(self) -> WorldInfoType {
115 match self {
116 serde_json::Value::Null => WorldInfoType::Null,
117 serde_json::Value::Bool(b) => WorldInfoType::Boolean(b.clone()),
118 serde_json::Value::Number(number) => WorldInfoType::Number(number.clone().into()),
119 serde_json::Value::String(s) => WorldInfoType::String(s.clone()),
120 serde_json::Value::Array(values) => WorldInfoType::List(values.into_iter().map(|x| x.into()).collect()),
121 serde_json::Value::Object(map) => WorldInfoType::Map(map.into_iter().map(|(k, v)| (k.clone(), v.clone().into())).collect()),
122 }
123 }
124}
125
126impl Into<Number> for serde_json::Number {
127 fn into(self) -> Number {
128 if self.is_f64() {
129 Number::Float(self.as_f64().unwrap())
130 } else if self.is_u64() {
131 Number::UInt(self.as_u64().unwrap())
132 } else {
133 Number::Int(self.as_i64().unwrap())
134 }
135 }
136}