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