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