Skip to main content

yog_data/
borrowed.rs

1//! [`ValueRef`]: a value borrowed from where it was read — what schemas
2//! read. Decoded from the binary form ([`crate::binary::decode_ref`]) no
3//! string is copied: every one points into the bytes, and lists and maps
4//! are slices in an arena ([`Bump`]). An owned [`Value`] lends itself the
5//! same way ([`Value::borrow`]).
6
7use bumpalo::Bump;
8
9use crate::value::{Map, Ref, Res, Value};
10
11/// A borrowed [`Value`]: the same cases, strings `&'a str`, lists and maps slices.
12#[derive(Debug, Clone, Copy, PartialEq)]
13pub enum ValueRef<'a> {
14    Null,
15    Bool(bool),
16    Int(i64),
17    Float(f64),
18    Str(&'a str),
19    List(&'a [ValueRef<'a>]),
20    Map(MapRef<'a>),
21    /// `@item:minecraft:stick`.
22    Ref {
23        kind: &'a str,
24        id: &'a str,
25    },
26    /// `@tag:item:minecraft:planks`.
27    Tag {
28        kind: &'a str,
29        id: &'a str,
30    },
31    /// `@Strings.title`.
32    Res {
33        set: &'a str,
34        key: &'a str,
35    },
36    /// `@lang:gui.done`.
37    Lang(&'a str),
38    /// Yog text.
39    Text(&'a str),
40    /// An image source.
41    Image(&'a str),
42    /// `0xAARRGGBB`.
43    Color(u32),
44    /// Bytes as they are.
45    Bytes(&'a [u8]),
46}
47
48/// A borrowed map: entries in file order.
49#[derive(Debug, Clone, Copy, PartialEq, Default)]
50pub struct MapRef<'a>(pub &'a [(&'a str, ValueRef<'a>)]);
51
52impl<'a> MapRef<'a> {
53    pub fn get(&self, key: &str) -> Option<&'a ValueRef<'a>> {
54        self.0.iter().find(|(k, _)| *k == key).map(|(_, v)| v)
55    }
56
57    pub fn iter(&self) -> impl ExactSizeIterator<Item = (&'a str, &'a ValueRef<'a>)> + 'a {
58        self.0.iter().map(|(k, v)| (*k, v))
59    }
60
61    pub fn keys(&self) -> impl ExactSizeIterator<Item = &'a str> + 'a {
62        self.0.iter().map(|(k, _)| *k)
63    }
64
65    pub fn len(&self) -> usize {
66        self.0.len()
67    }
68
69    pub fn is_empty(&self) -> bool {
70        self.0.is_empty()
71    }
72}
73
74impl<'a> ValueRef<'a> {
75    /// The type's name, for messages: `"a string"`, `"a list"`, ...
76    pub fn kind_name(&self) -> &'static str {
77        match self {
78            ValueRef::Null => "null",
79            ValueRef::Bool(_) => "true/false",
80            ValueRef::Int(_) => "an integer",
81            ValueRef::Float(_) => "a number",
82            ValueRef::Str(_) => "a string",
83            ValueRef::List(_) => "a list",
84            ValueRef::Map(_) => "an object",
85            ValueRef::Ref { .. } => "a reference",
86            ValueRef::Tag { .. } => "a tag",
87            ValueRef::Res { .. } => "a resource",
88            ValueRef::Lang(_) => "a translation key",
89            ValueRef::Text(_) => "a text",
90            ValueRef::Image(_) => "an image",
91            ValueRef::Color(_) => "a color",
92            ValueRef::Bytes(_) => "bytes",
93        }
94    }
95
96    pub fn is_null(&self) -> bool {
97        matches!(self, ValueRef::Null)
98    }
99
100    pub fn as_bool(&self) -> Option<bool> {
101        match self {
102            ValueRef::Bool(b) => Some(*b),
103            _ => None,
104        }
105    }
106
107    pub fn as_i64(&self) -> Option<i64> {
108        match self {
109            ValueRef::Int(n) => Some(*n),
110            ValueRef::Float(f) if f.fract() == 0.0 && f.abs() < 9.0e15 => Some(*f as i64),
111            _ => None,
112        }
113    }
114
115    pub fn as_f64(&self) -> Option<f64> {
116        match self {
117            ValueRef::Int(n) => Some(*n as f64),
118            ValueRef::Float(f) => Some(*f),
119            _ => None,
120        }
121    }
122
123    /// The string of a `Str` (and of the string-like typed values: `Text`, `Image`).
124    pub fn as_str(&self) -> Option<&'a str> {
125        match self {
126            ValueRef::Str(s) | ValueRef::Text(s) | ValueRef::Image(s) => Some(s),
127            _ => None,
128        }
129    }
130
131    pub fn as_list(&self) -> Option<&'a [ValueRef<'a>]> {
132        match self {
133            ValueRef::List(l) => Some(l),
134            _ => None,
135        }
136    }
137
138    pub fn as_map(&self) -> Option<MapRef<'a>> {
139        match self {
140            ValueRef::Map(m) => Some(*m),
141            _ => None,
142        }
143    }
144
145    /// `self[key]` of a map, `None` for anything else.
146    pub fn get(&self, key: &str) -> Option<&'a ValueRef<'a>> {
147        self.as_map()?.get(key)
148    }
149
150    /// An owned copy.
151    pub fn to_value(&self) -> Value {
152        match *self {
153            ValueRef::Null => Value::Null,
154            ValueRef::Bool(b) => Value::Bool(b),
155            ValueRef::Int(n) => Value::Int(n),
156            ValueRef::Float(f) => Value::Float(f),
157            ValueRef::Str(s) => Value::Str(s.to_string()),
158            ValueRef::List(l) => Value::List(l.iter().map(ValueRef::to_value).collect()),
159            ValueRef::Map(m) => {
160                let mut out = Map::with_capacity(m.len());
161                for (k, v) in m.iter() {
162                    out.insert(k, v.to_value());
163                }
164                Value::Map(out)
165            }
166            ValueRef::Ref { kind, id } => Value::Ref(Ref::new(kind, id)),
167            ValueRef::Tag { kind, id } => Value::Tag(Ref::new(kind, id)),
168            ValueRef::Res { set, key } => Value::Res(Res {
169                set: set.to_string(),
170                key: key.to_string(),
171            }),
172            ValueRef::Lang(k) => Value::Lang(k.to_string()),
173            ValueRef::Text(s) => Value::Text(s.to_string()),
174            ValueRef::Image(s) => Value::Image(s.to_string()),
175            ValueRef::Color(c) => Value::Color(c),
176            ValueRef::Bytes(b) => Value::Bytes(b.to_vec()),
177        }
178    }
179
180    /// The reference of a `Ref`, owned.
181    pub fn to_ref(&self) -> Option<Ref> {
182        match *self {
183            ValueRef::Ref { kind, id } => Some(Ref::new(kind, id)),
184            _ => None,
185        }
186    }
187}
188
189impl Value {
190    /// This value, borrowed (lists and maps in `arena`) — what schemas read.
191    pub fn borrow<'a>(&'a self, arena: &'a Bump) -> ValueRef<'a> {
192        match self {
193            Value::Null => ValueRef::Null,
194            Value::Bool(b) => ValueRef::Bool(*b),
195            Value::Int(n) => ValueRef::Int(*n),
196            Value::Float(f) => ValueRef::Float(*f),
197            Value::Str(s) => ValueRef::Str(s),
198            Value::List(l) => {
199                ValueRef::List(arena.alloc_slice_fill_iter(l.iter().map(|v| v.borrow(arena))))
200            }
201            Value::Map(m) => ValueRef::Map(MapRef(
202                arena.alloc_slice_fill_iter(m.iter().map(|(k, v)| (k, v.borrow(arena)))),
203            )),
204            Value::Ref(r) => ValueRef::Ref {
205                kind: &r.kind,
206                id: &r.id,
207            },
208            Value::Tag(r) => ValueRef::Tag {
209                kind: &r.kind,
210                id: &r.id,
211            },
212            Value::Res(r) => ValueRef::Res {
213                set: &r.set,
214                key: &r.key,
215            },
216            Value::Lang(k) => ValueRef::Lang(k),
217            Value::Text(s) => ValueRef::Text(s),
218            Value::Image(s) => ValueRef::Image(s),
219            Value::Color(c) => ValueRef::Color(*c),
220            Value::Bytes(b) => ValueRef::Bytes(b),
221        }
222    }
223}