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
70impl Res {
71 pub fn name(&self) -> String {
73 format!("{}.{}", self.set, self.key)
74 }
75}
76
77impl std::fmt::Display for Res {
78 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 write!(f, "{}{}.{}", yog_ids::sep::TYPED, self.set, self.key)
81 }
82}
83
84#[derive(Debug, Clone, PartialEq, Default)]
87pub struct Map(Vec<(yog_sync::Arc<str>, Value)>);
88
89impl Map {
90 pub fn new() -> Self {
91 Self(Vec::new())
92 }
93
94 pub fn with_capacity(n: usize) -> Self {
95 Self(Vec::with_capacity(n))
96 }
97
98 pub fn get(&self, key: &str) -> Option<&Value> {
99 self.0.iter().find(|(k, _)| &**k == key).map(|(_, v)| v)
100 }
101
102 pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
103 self.0.iter_mut().find(|(k, _)| &**k == key).map(|(_, v)| v)
104 }
105
106 pub fn value_at(&self, i: usize) -> Option<&Value> {
108 self.0.get(i).map(|(_, v)| v)
109 }
110
111 pub fn index_of(&self, key: &str) -> Option<usize> {
113 self.0.iter().position(|(k, _)| &**k == key)
114 }
115
116 pub fn insert(&mut self, key: impl Into<String>, value: Value) -> Option<Value> {
118 let key = key.into();
119 match self.get_mut(&key) {
120 Some(slot) => Some(std::mem::replace(slot, value)),
121 None => {
122 self.0.push((key.into(), value));
123 None
124 }
125 }
126 }
127
128 pub(crate) fn push_unchecked(&mut self, key: yog_sync::Arc<str>, value: Value) {
130 self.0.push((key, value));
131 }
132
133 pub fn remove(&mut self, key: &str) -> Option<Value> {
134 let i = self.index_of(key)?;
135 Some(self.0.remove(i).1)
136 }
137
138 pub fn len(&self) -> usize {
139 self.0.len()
140 }
141
142 pub fn is_empty(&self) -> bool {
143 self.0.is_empty()
144 }
145
146 pub fn iter(&self) -> impl ExactSizeIterator<Item = (&str, &Value)> {
147 self.0.iter().map(|(k, v)| (&**k, v))
148 }
149
150 pub fn keys(&self) -> impl ExactSizeIterator<Item = &str> {
151 self.0.iter().map(|(k, _)| &**k)
152 }
153
154 pub fn values(&self) -> impl ExactSizeIterator<Item = &Value> {
155 self.0.iter().map(|(_, v)| v)
156 }
157
158 pub fn retain(&mut self, mut keep: impl FnMut(&str, &Value) -> bool) {
159 self.0.retain(|(k, v)| keep(k, v));
160 }
161}
162
163impl IntoIterator for Map {
164 type Item = (String, Value);
165 type IntoIter = std::iter::Map<
166 std::vec::IntoIter<(yog_sync::Arc<str>, Value)>,
167 fn((yog_sync::Arc<str>, Value)) -> (String, Value),
168 >;
169 fn into_iter(self) -> Self::IntoIter {
170 self.0.into_iter().map(|(k, v)| (k.to_string(), v))
171 }
172}
173
174impl<'a> IntoIterator for &'a Map {
175 type Item = (&'a str, &'a Value);
176 type IntoIter = std::iter::Map<
177 std::slice::Iter<'a, (yog_sync::Arc<str>, Value)>,
178 fn(&'a (yog_sync::Arc<str>, Value)) -> (&'a str, &'a Value),
179 >;
180 fn into_iter(self) -> Self::IntoIter {
181 self.0.iter().map(|(k, v)| (&**k, v))
182 }
183}
184
185impl<K: Into<String>> FromIterator<(K, Value)> for Map {
186 fn from_iter<I: IntoIterator<Item = (K, Value)>>(iter: I) -> Self {
187 let mut map = Map::new();
188 for (k, v) in iter {
189 map.insert(k, v);
190 }
191 map
192 }
193}
194
195impl Value {
196 pub fn kind_name(&self) -> &'static str {
198 match self {
199 Value::Null => "null",
200 Value::Bool(_) => "true/false",
201 Value::Int(_) => "an integer",
202 Value::Float(_) => "a number",
203 Value::Str(_) => "a string",
204 Value::List(_) => "a list",
205 Value::Map(_) => "an object",
206 Value::Ref(_) => "a reference",
207 Value::Tag(_) => "a tag",
208 Value::Res(_) => "a resource",
209 Value::Lang(_) => "a translation key",
210 Value::Text(_) => "a text",
211 Value::Image(_) => "an image",
212 Value::Color(_) => "a color",
213 Value::Bytes(_) => "bytes",
214 }
215 }
216
217 pub fn is_null(&self) -> bool {
218 matches!(self, Value::Null)
219 }
220
221 pub fn as_bool(&self) -> Option<bool> {
222 match self {
223 Value::Bool(b) => Some(*b),
224 _ => None,
225 }
226 }
227
228 pub fn as_i64(&self) -> Option<i64> {
229 match self {
230 Value::Int(n) => Some(*n),
231 Value::Float(f) if f.fract() == 0.0 && f.abs() < 9.0e15 => Some(*f as i64),
232 _ => None,
233 }
234 }
235
236 pub fn as_f64(&self) -> Option<f64> {
237 match self {
238 Value::Int(n) => Some(*n as f64),
239 Value::Float(f) => Some(*f),
240 _ => None,
241 }
242 }
243
244 pub fn as_str(&self) -> Option<&str> {
246 match self {
247 Value::Str(s) | Value::Text(s) | Value::Image(s) => Some(s),
248 _ => None,
249 }
250 }
251
252 pub fn as_list(&self) -> Option<&[Value]> {
253 match self {
254 Value::List(l) => Some(l),
255 _ => None,
256 }
257 }
258
259 pub fn as_map(&self) -> Option<&Map> {
260 match self {
261 Value::Map(m) => Some(m),
262 _ => None,
263 }
264 }
265
266 pub fn get(&self, key: &str) -> Option<&Value> {
268 self.as_map()?.get(key)
269 }
270
271 pub fn at(&self, path: &Path) -> Option<&Value> {
273 let mut v = self;
274 for seg in path.segments() {
275 v = match (seg, v) {
276 (Seg::Key(k), Value::Map(m)) => m.get(k)?,
277 (Seg::Index(i), Value::List(l)) => l.get(*i)?,
278 _ => return None,
279 };
280 }
281 Some(v)
282 }
283
284 pub fn at_mut(&mut self, segs: &[Seg]) -> Option<&mut Value> {
286 let mut v = self;
287 for seg in segs {
288 v = match (seg, v) {
289 (Seg::Key(k), Value::Map(m)) => m.get_mut(k)?,
290 (Seg::Index(i), Value::List(l)) => l.get_mut(*i)?,
291 _ => return None,
292 };
293 }
294 Some(v)
295 }
296}
297
298impl From<bool> for Value {
299 fn from(b: bool) -> Self {
300 Value::Bool(b)
301 }
302}
303impl From<i64> for Value {
304 fn from(n: i64) -> Self {
305 Value::Int(n)
306 }
307}
308impl From<f64> for Value {
309 fn from(f: f64) -> Self {
310 Value::Float(f)
311 }
312}
313impl From<&str> for Value {
314 fn from(s: &str) -> Self {
315 Value::Str(s.to_string())
316 }
317}
318impl From<String> for Value {
319 fn from(s: String) -> Self {
320 Value::Str(s)
321 }
322}
323impl From<Vec<Value>> for Value {
324 fn from(l: Vec<Value>) -> Self {
325 Value::List(l)
326 }
327}
328impl From<Map> for Value {
329 fn from(m: Map) -> Self {
330 Value::Map(m)
331 }
332}
333
334#[derive(Debug, Clone, PartialEq, Eq, Hash, crate::Schema)]
336#[data(tag = "type")]
337pub enum Seg {
338 Key(String),
339 Index(usize),
340}
341
342#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
344pub struct Path(Vec<Seg>);
345
346impl Path {
347 pub fn root() -> Self {
348 Self(Vec::new())
349 }
350
351 pub fn segments(&self) -> &[Seg] {
352 &self.0
353 }
354
355 pub fn is_root(&self) -> bool {
356 self.0.is_empty()
357 }
358
359 pub fn push(&mut self, seg: Seg) {
360 self.0.push(seg);
361 }
362
363 pub fn pop(&mut self) {
364 self.0.pop();
365 }
366
367 pub fn key(&self, key: &str) -> Path {
368 let mut p = self.clone();
369 p.0.push(Seg::Key(key.to_string()));
370 p
371 }
372
373 pub fn then(&self, rest: &Path) -> Path {
375 let mut p = self.clone();
376 p.0.extend(rest.0.iter().cloned());
377 p
378 }
379
380 pub fn index(&self, i: usize) -> Path {
381 let mut p = self.clone();
382 p.0.push(Seg::Index(i));
383 p
384 }
385}
386
387impl crate::Schema for Path {
389 fn shape() -> crate::Shape {
390 Vec::<Seg>::shape()
391 }
392 fn read(v: &crate::ValueRef<'_>, cx: &mut crate::Reader) -> Option<Self> {
393 Vec::<Seg>::read(v, cx).map(Path)
394 }
395 fn write(&self) -> Value {
396 self.0.write()
397 }
398}
399
400impl fmt::Display for Path {
401 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
402 if self.0.is_empty() {
403 return f.write_str("(root)");
404 }
405 for (i, seg) in self.0.iter().enumerate() {
406 match seg {
407 Seg::Key(k) if is_plain_key(k) => {
408 if i > 0 {
409 f.write_str(".")?;
410 }
411 f.write_str(k)?;
412 }
413 Seg::Key(k) => write!(f, "[{k:?}]")?,
414 Seg::Index(n) => write!(f, "[{n}]")?,
415 }
416 }
417 Ok(())
418 }
419}
420
421fn is_plain_key(k: &str) -> bool {
422 let mut chars = k.chars();
423 chars
424 .next()
425 .is_some_and(|c| c.is_ascii_alphabetic() || c == '_' || c == '$')
426 && chars.all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '$')
427}