1use bumpalo::Bump;
8
9use crate::value::{Map, Ref, Res, Value};
10
11#[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 Ref {
23 kind: &'a str,
24 id: &'a str,
25 },
26 Tag {
28 kind: &'a str,
29 id: &'a str,
30 },
31 Res {
33 set: &'a str,
34 key: &'a str,
35 },
36 Lang(&'a str),
38 Text(&'a str),
40 Image(&'a str),
42 Color(u32),
44 Bytes(&'a [u8]),
46}
47
48#[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 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 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 pub fn get(&self, key: &str) -> Option<&'a ValueRef<'a>> {
147 self.as_map()?.get(key)
148 }
149
150 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 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 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}