1#[cfg(not(feature = "std"))]
10use alloc::{format, string::{String, ToString}, vec::Vec};
11
12use crate::memory::{bop_alloc, bop_dealloc};
13
14#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
19pub struct BopStr(String);
20
21#[derive(Debug)]
22pub struct BopArray(Vec<Value>);
23
24#[derive(Debug)]
25pub struct BopDict(Vec<(String, Value)>);
26
27#[derive(Debug)]
30pub enum Value {
31 Number(f64),
32 Str(BopStr),
33 Bool(bool),
34 None,
35 Array(BopArray),
36 Dict(BopDict),
37}
38
39impl Value {
48 pub fn new_str(s: String) -> Self {
49 bop_alloc(s.capacity());
50 Value::Str(BopStr(s))
51 }
52
53 pub fn new_array(items: Vec<Value>) -> Self {
54 bop_alloc(items.capacity() * core::mem::size_of::<Value>());
55 Value::Array(BopArray(items))
56 }
57
58 pub fn new_dict(entries: Vec<(String, Value)>) -> Self {
59 let key_bytes: usize = entries.iter().map(|(k, _)| k.capacity()).sum();
60 bop_alloc(entries.capacity() * core::mem::size_of::<(String, Value)>() + key_bytes);
61 Value::Dict(BopDict(entries))
62 }
63}
64
65impl Clone for Value {
73 fn clone(&self) -> Self {
74 match self {
75 Value::Number(n) => Value::Number(*n),
76 Value::Bool(b) => Value::Bool(*b),
77 Value::None => Value::None,
78 Value::Str(s) => {
79 let cloned = s.0.clone();
80 bop_alloc(cloned.capacity());
81 Value::Str(BopStr(cloned))
82 }
83 Value::Array(arr) => {
84 let cloned = arr.0.clone(); bop_alloc(cloned.capacity() * core::mem::size_of::<Value>());
86 Value::Array(BopArray(cloned))
87 }
88 Value::Dict(d) => {
89 let cloned = d.0.clone(); let key_bytes: usize = cloned.iter().map(|(k, _)| k.capacity()).sum();
91 bop_alloc(cloned.capacity() * core::mem::size_of::<(String, Value)>() + key_bytes);
92 Value::Dict(BopDict(cloned))
93 }
94 }
95 }
96}
97
98impl Drop for Value {
101 fn drop(&mut self) {
102 match self {
103 Value::Str(s) => bop_dealloc(s.0.capacity()),
104 Value::Array(arr) => {
105 bop_dealloc(arr.0.capacity() * core::mem::size_of::<Value>());
106 }
107 Value::Dict(d) => {
108 let key_bytes: usize = d.0.iter().map(|(k, _)| k.capacity()).sum();
109 bop_dealloc(d.0.capacity() * core::mem::size_of::<(String, Value)>() + key_bytes);
110 }
111 _ => {}
112 }
113 }
114}
115
116impl core::fmt::Display for Value {
119 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
120 match self {
121 Value::Number(n) => {
122 if *n == (*n as i64 as f64) && *n - *n == 0.0 {
123 write!(f, "{}", *n as i64)
124 } else {
125 write!(f, "{}", n)
126 }
127 }
128 Value::Str(s) => write!(f, "{}", s.0),
129 Value::Bool(b) => write!(f, "{}", b),
130 Value::None => write!(f, "none"),
131 Value::Array(items) => {
132 write!(f, "[")?;
133 for (i, item) in items.0.iter().enumerate() {
134 if i > 0 {
135 write!(f, ", ")?;
136 }
137 write!(f, "{}", item.inspect())?;
138 }
139 write!(f, "]")
140 }
141 Value::Dict(entries) => {
142 write!(f, "{{")?;
143 for (i, (k, v)) in entries.0.iter().enumerate() {
144 if i > 0 {
145 write!(f, ", ")?;
146 }
147 write!(f, "\"{}\": {}", k, v.inspect())?;
148 }
149 write!(f, "}}")
150 }
151 }
152 }
153}
154
155impl core::fmt::Display for BopStr {
156 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
157 write!(f, "{}", self.0)
158 }
159}
160
161impl Value {
164 pub fn inspect(&self) -> String {
165 match self {
166 Value::Str(s) => format!("\"{}\"", s.0),
167 other => format!("{}", other),
168 }
169 }
170
171 pub fn type_name(&self) -> &'static str {
172 match self {
173 Value::Number(_) => "number",
174 Value::Str(_) => "string",
175 Value::Bool(_) => "bool",
176 Value::None => "none",
177 Value::Array(_) => "array",
178 Value::Dict(_) => "dict",
179 }
180 }
181
182 pub fn is_truthy(&self) -> bool {
183 match self {
184 Value::Bool(b) => *b,
185 Value::None => false,
186 Value::Number(n) => *n != 0.0,
187 Value::Str(s) => !s.0.is_empty(),
188 Value::Array(a) => !a.0.is_empty(),
189 Value::Dict(d) => !d.0.is_empty(),
190 }
191 }
192}
193
194impl BopStr {
197 pub fn as_str(&self) -> &str {
198 &self.0
199 }
200}
201
202impl core::ops::Deref for BopStr {
203 type Target = str;
204 fn deref(&self) -> &str {
205 &self.0
206 }
207}
208
209impl core::ops::Deref for BopArray {
210 type Target = [Value];
211 fn deref(&self) -> &[Value] {
212 &self.0
213 }
214}
215
216impl core::ops::Deref for BopDict {
217 type Target = [(String, Value)];
218 fn deref(&self) -> &[(String, Value)] {
219 &self.0
220 }
221}
222
223impl BopArray {
226 pub fn take(&mut self) -> Vec<Value> {
229 let taken = core::mem::take(&mut self.0);
230 bop_dealloc(taken.capacity() * core::mem::size_of::<Value>());
231 taken
232 }
233
234 pub fn set(&mut self, index: usize, val: Value) {
237 self.0[index] = val;
238 }
239}
240
241impl BopDict {
242 pub fn set_key(&mut self, key: &str, val: Value) {
246 if let Some(entry) = self.0.iter_mut().find(|(k, _)| k == key) {
247 entry.1 = val;
248 } else {
249 let old_cap = self.0.capacity();
250 let key = key.to_string();
251 bop_alloc(key.capacity());
252 self.0.push((key, val));
253 let new_cap = self.0.capacity();
254 if new_cap > old_cap {
255 bop_alloc((new_cap - old_cap) * core::mem::size_of::<(String, Value)>());
256 }
257 }
258 }
259}
260
261pub fn values_equal(a: &Value, b: &Value) -> bool {
264 match (a, b) {
265 (Value::Number(x), Value::Number(y)) => x == y,
266 (Value::Str(x), Value::Str(y)) => x == y,
267 (Value::Bool(x), Value::Bool(y)) => x == y,
268 (Value::None, Value::None) => true,
269 (Value::Array(x), Value::Array(y)) => {
270 x.len() == y.len() && x.iter().zip(y.iter()).all(|(a, b)| values_equal(a, b))
271 }
272 (Value::Dict(x), Value::Dict(y)) => {
273 x.len() == y.len()
274 && x.iter().all(|(k, v)| {
275 y.iter()
276 .find(|(k2, _)| k2 == k)
277 .is_some_and(|(_, v2)| values_equal(v, v2))
278 })
279 }
280 _ => false,
281 }
282}