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 { kind: &'a str, id: &'a str },
23 Tag { kind: &'a str, id: &'a str },
25 Res { set: &'a str, key: &'a str },
27 Lang(&'a str),
29 Text(&'a str),
31 Image(&'a str),
33 Color(u32),
35 Bytes(&'a [u8]),
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Default)]
41pub struct MapRef<'a>(pub &'a [(&'a str, ValueRef<'a>)]);
42
43impl<'a> MapRef<'a> {
44 pub fn get(&self, key: &str) -> Option<&'a ValueRef<'a>> {
45 self.0.iter().find(|(k, _)| *k == key).map(|(_, v)| v)
46 }
47
48 pub fn iter(&self) -> impl ExactSizeIterator<Item = (&'a str, &'a ValueRef<'a>)> + 'a {
49 self.0.iter().map(|(k, v)| (*k, v))
50 }
51
52 pub fn keys(&self) -> impl ExactSizeIterator<Item = &'a str> + 'a {
53 self.0.iter().map(|(k, _)| *k)
54 }
55
56 pub fn len(&self) -> usize {
57 self.0.len()
58 }
59
60 pub fn is_empty(&self) -> bool {
61 self.0.is_empty()
62 }
63}
64
65impl<'a> ValueRef<'a> {
66 pub fn kind_name(&self) -> &'static str {
68 match self {
69 ValueRef::Null => "null",
70 ValueRef::Bool(_) => "true/false",
71 ValueRef::Int(_) => "an integer",
72 ValueRef::Float(_) => "a number",
73 ValueRef::Str(_) => "a string",
74 ValueRef::List(_) => "a list",
75 ValueRef::Map(_) => "an object",
76 ValueRef::Ref { .. } => "a reference",
77 ValueRef::Tag { .. } => "a tag",
78 ValueRef::Res { .. } => "a resource",
79 ValueRef::Lang(_) => "a translation key",
80 ValueRef::Text(_) => "a text",
81 ValueRef::Image(_) => "an image",
82 ValueRef::Color(_) => "a color",
83 ValueRef::Bytes(_) => "bytes",
84 }
85 }
86
87 pub fn is_null(&self) -> bool {
88 matches!(self, ValueRef::Null)
89 }
90
91 pub fn as_bool(&self) -> Option<bool> {
92 match self {
93 ValueRef::Bool(b) => Some(*b),
94 _ => None,
95 }
96 }
97
98 pub fn as_i64(&self) -> Option<i64> {
99 match self {
100 ValueRef::Int(n) => Some(*n),
101 ValueRef::Float(f) if f.fract() == 0.0 && f.abs() < 9.0e15 => Some(*f as i64),
102 _ => None,
103 }
104 }
105
106 pub fn as_f64(&self) -> Option<f64> {
107 match self {
108 ValueRef::Int(n) => Some(*n as f64),
109 ValueRef::Float(f) => Some(*f),
110 _ => None,
111 }
112 }
113
114 pub fn as_str(&self) -> Option<&'a str> {
116 match self {
117 ValueRef::Str(s) | ValueRef::Text(s) | ValueRef::Image(s) => Some(s),
118 _ => None,
119 }
120 }
121
122 pub fn as_list(&self) -> Option<&'a [ValueRef<'a>]> {
123 match self {
124 ValueRef::List(l) => Some(l),
125 _ => None,
126 }
127 }
128
129 pub fn as_map(&self) -> Option<MapRef<'a>> {
130 match self {
131 ValueRef::Map(m) => Some(*m),
132 _ => None,
133 }
134 }
135
136 pub fn get(&self, key: &str) -> Option<&'a ValueRef<'a>> {
138 self.as_map()?.get(key)
139 }
140
141 pub fn to_value(&self) -> Value {
143 match *self {
144 ValueRef::Null => Value::Null,
145 ValueRef::Bool(b) => Value::Bool(b),
146 ValueRef::Int(n) => Value::Int(n),
147 ValueRef::Float(f) => Value::Float(f),
148 ValueRef::Str(s) => Value::Str(s.to_string()),
149 ValueRef::List(l) => Value::List(l.iter().map(ValueRef::to_value).collect()),
150 ValueRef::Map(m) => {
151 let mut out = Map::with_capacity(m.len());
152 for (k, v) in m.iter() {
153 out.insert(k, v.to_value());
154 }
155 Value::Map(out)
156 }
157 ValueRef::Ref { kind, id } => Value::Ref(Ref::new(kind, id)),
158 ValueRef::Tag { kind, id } => Value::Tag(Ref::new(kind, id)),
159 ValueRef::Res { set, key } => Value::Res(Res { set: set.to_string(), key: key.to_string() }),
160 ValueRef::Lang(k) => Value::Lang(k.to_string()),
161 ValueRef::Text(s) => Value::Text(s.to_string()),
162 ValueRef::Image(s) => Value::Image(s.to_string()),
163 ValueRef::Color(c) => Value::Color(c),
164 ValueRef::Bytes(b) => Value::Bytes(b.to_vec()),
165 }
166 }
167
168 pub fn to_ref(&self) -> Option<Ref> {
170 match *self {
171 ValueRef::Ref { kind, id } => Some(Ref::new(kind, id)),
172 _ => None,
173 }
174 }
175}
176
177impl Value {
178 pub fn borrow<'a>(&'a self, arena: &'a Bump) -> ValueRef<'a> {
180 match self {
181 Value::Null => ValueRef::Null,
182 Value::Bool(b) => ValueRef::Bool(*b),
183 Value::Int(n) => ValueRef::Int(*n),
184 Value::Float(f) => ValueRef::Float(*f),
185 Value::Str(s) => ValueRef::Str(s),
186 Value::List(l) => ValueRef::List(arena.alloc_slice_fill_iter(l.iter().map(|v| v.borrow(arena)))),
187 Value::Map(m) => ValueRef::Map(MapRef(arena.alloc_slice_fill_iter(m.iter().map(|(k, v)| (k, v.borrow(arena)))))),
188 Value::Ref(r) => ValueRef::Ref { kind: &r.kind, id: &r.id },
189 Value::Tag(r) => ValueRef::Tag { kind: &r.kind, id: &r.id },
190 Value::Res(r) => ValueRef::Res { set: &r.set, key: &r.key },
191 Value::Lang(k) => ValueRef::Lang(k),
192 Value::Text(s) => ValueRef::Text(s),
193 Value::Image(s) => ValueRef::Image(s),
194 Value::Color(c) => ValueRef::Color(*c),
195 Value::Bytes(b) => ValueRef::Bytes(b),
196 }
197 }
198}