1use std::fmt;
4
5#[derive(Debug, Clone, PartialEq, Default)]
12pub enum Value {
13 #[default]
14 Null,
15 Bool(bool),
16 Int(i64),
17 Float(f64),
18 Str(String),
19 List(Vec<Value>),
20 Map(Map),
21 Ref(Ref),
23 Tag(Ref),
25 Res(Res),
27 Text(String),
29 Image(String),
31 Color(u32),
33}
34
35#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
39pub struct Ref {
40 pub kind: String,
41 pub id: String,
42}
43
44impl Ref {
45 pub fn new(kind: impl Into<String>, id: impl Into<String>) -> Self {
46 Self {
47 kind: kind.into(),
48 id: id.into(),
49 }
50 }
51
52 pub fn namespace(&self) -> &str {
54 self.id.split_once(':').map_or("minecraft", |(ns, _)| ns)
55 }
56}
57
58#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
61pub struct Res {
62 pub set: String,
63 pub key: String,
64}
65
66#[derive(Debug, Clone, PartialEq, Default)]
68pub struct Map(Vec<(String, Value)>);
69
70impl Map {
71 pub fn new() -> Self {
72 Self(Vec::new())
73 }
74
75 pub fn with_capacity(n: usize) -> Self {
76 Self(Vec::with_capacity(n))
77 }
78
79 pub fn get(&self, key: &str) -> Option<&Value> {
80 self.0.iter().find(|(k, _)| k == key).map(|(_, v)| v)
81 }
82
83 pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
84 self.0.iter_mut().find(|(k, _)| k == key).map(|(_, v)| v)
85 }
86
87 pub fn index_of(&self, key: &str) -> Option<usize> {
89 self.0.iter().position(|(k, _)| k == key)
90 }
91
92 pub fn insert(&mut self, key: impl Into<String>, value: Value) -> Option<Value> {
94 let key = key.into();
95 match self.get_mut(&key) {
96 Some(slot) => Some(std::mem::replace(slot, value)),
97 None => {
98 self.0.push((key, value));
99 None
100 }
101 }
102 }
103
104 pub(crate) fn push_unchecked(&mut self, key: String, value: Value) {
106 self.0.push((key, value));
107 }
108
109 pub fn remove(&mut self, key: &str) -> Option<Value> {
110 let i = self.index_of(key)?;
111 Some(self.0.remove(i).1)
112 }
113
114 pub fn len(&self) -> usize {
115 self.0.len()
116 }
117
118 pub fn is_empty(&self) -> bool {
119 self.0.is_empty()
120 }
121
122 pub fn iter(&self) -> impl ExactSizeIterator<Item = (&str, &Value)> {
123 self.0.iter().map(|(k, v)| (k.as_str(), v))
124 }
125
126 pub fn keys(&self) -> impl ExactSizeIterator<Item = &str> {
127 self.0.iter().map(|(k, _)| k.as_str())
128 }
129
130 pub fn retain(&mut self, mut keep: impl FnMut(&str, &Value) -> bool) {
131 self.0.retain(|(k, v)| keep(k, v));
132 }
133}
134
135impl IntoIterator for Map {
136 type Item = (String, Value);
137 type IntoIter = std::vec::IntoIter<(String, Value)>;
138 fn into_iter(self) -> Self::IntoIter {
139 self.0.into_iter()
140 }
141}
142
143impl<K: Into<String>> FromIterator<(K, Value)> for Map {
144 fn from_iter<I: IntoIterator<Item = (K, Value)>>(iter: I) -> Self {
145 let mut map = Map::new();
146 for (k, v) in iter {
147 map.insert(k, v);
148 }
149 map
150 }
151}
152
153impl Value {
154 pub fn kind_name(&self) -> &'static str {
156 match self {
157 Value::Null => "null",
158 Value::Bool(_) => "true/false",
159 Value::Int(_) => "an integer",
160 Value::Float(_) => "a number",
161 Value::Str(_) => "a string",
162 Value::List(_) => "a list",
163 Value::Map(_) => "an object",
164 Value::Ref(_) => "a reference",
165 Value::Tag(_) => "a tag",
166 Value::Res(_) => "a resource",
167 Value::Text(_) => "a text",
168 Value::Image(_) => "an image",
169 Value::Color(_) => "a color",
170 }
171 }
172
173 pub fn is_null(&self) -> bool {
174 matches!(self, Value::Null)
175 }
176
177 pub fn as_bool(&self) -> Option<bool> {
178 match self {
179 Value::Bool(b) => Some(*b),
180 _ => None,
181 }
182 }
183
184 pub fn as_i64(&self) -> Option<i64> {
185 match self {
186 Value::Int(n) => Some(*n),
187 Value::Float(f) if f.fract() == 0.0 && f.abs() < 9.0e15 => Some(*f as i64),
188 _ => None,
189 }
190 }
191
192 pub fn as_f64(&self) -> Option<f64> {
193 match self {
194 Value::Int(n) => Some(*n as f64),
195 Value::Float(f) => Some(*f),
196 _ => None,
197 }
198 }
199
200 pub fn as_str(&self) -> Option<&str> {
202 match self {
203 Value::Str(s) | Value::Text(s) | Value::Image(s) => Some(s),
204 _ => None,
205 }
206 }
207
208 pub fn as_list(&self) -> Option<&[Value]> {
209 match self {
210 Value::List(l) => Some(l),
211 _ => None,
212 }
213 }
214
215 pub fn as_map(&self) -> Option<&Map> {
216 match self {
217 Value::Map(m) => Some(m),
218 _ => None,
219 }
220 }
221
222 pub fn get(&self, key: &str) -> Option<&Value> {
224 self.as_map()?.get(key)
225 }
226
227 pub fn at(&self, path: &Path) -> Option<&Value> {
229 let mut v = self;
230 for seg in path.segments() {
231 v = match (seg, v) {
232 (Seg::Key(k), Value::Map(m)) => m.get(k)?,
233 (Seg::Index(i), Value::List(l)) => l.get(*i)?,
234 _ => return None,
235 };
236 }
237 Some(v)
238 }
239}
240
241impl From<bool> for Value {
242 fn from(b: bool) -> Self {
243 Value::Bool(b)
244 }
245}
246impl From<i64> for Value {
247 fn from(n: i64) -> Self {
248 Value::Int(n)
249 }
250}
251impl From<f64> for Value {
252 fn from(f: f64) -> Self {
253 Value::Float(f)
254 }
255}
256impl From<&str> for Value {
257 fn from(s: &str) -> Self {
258 Value::Str(s.to_string())
259 }
260}
261impl From<String> for Value {
262 fn from(s: String) -> Self {
263 Value::Str(s)
264 }
265}
266impl From<Vec<Value>> for Value {
267 fn from(l: Vec<Value>) -> Self {
268 Value::List(l)
269 }
270}
271impl From<Map> for Value {
272 fn from(m: Map) -> Self {
273 Value::Map(m)
274 }
275}
276
277#[derive(Debug, Clone, PartialEq, Eq, Hash)]
279pub enum Seg {
280 Key(String),
281 Index(usize),
282}
283
284#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
286pub struct Path(Vec<Seg>);
287
288impl Path {
289 pub fn root() -> Self {
290 Self(Vec::new())
291 }
292
293 pub fn segments(&self) -> &[Seg] {
294 &self.0
295 }
296
297 pub fn is_root(&self) -> bool {
298 self.0.is_empty()
299 }
300
301 pub fn push(&mut self, seg: Seg) {
302 self.0.push(seg);
303 }
304
305 pub fn pop(&mut self) {
306 self.0.pop();
307 }
308
309 pub fn key(&self, key: &str) -> Path {
310 let mut p = self.clone();
311 p.0.push(Seg::Key(key.to_string()));
312 p
313 }
314
315 pub fn index(&self, i: usize) -> Path {
316 let mut p = self.clone();
317 p.0.push(Seg::Index(i));
318 p
319 }
320}
321
322impl fmt::Display for Path {
323 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
324 if self.0.is_empty() {
325 return f.write_str("(root)");
326 }
327 for (i, seg) in self.0.iter().enumerate() {
328 match seg {
329 Seg::Key(k) if is_plain_key(k) => {
330 if i > 0 {
331 f.write_str(".")?;
332 }
333 f.write_str(k)?;
334 }
335 Seg::Key(k) => write!(f, "[{k:?}]")?,
336 Seg::Index(n) => write!(f, "[{n}]")?,
337 }
338 }
339 Ok(())
340 }
341}
342
343fn is_plain_key(k: &str) -> bool {
344 let mut chars = k.chars();
345 chars
346 .next()
347 .is_some_and(|c| c.is_ascii_alphabetic() || c == '_' || c == '$')
348 && chars.all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '$')
349}