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