1use std::cell::RefCell;
15use std::fmt;
16use std::rc::Rc;
17
18use crate::major::Inj;
19use crate::ordered_map::OrderedMap;
20
21pub type VList = Rc<RefCell<Vec<Value>>>;
22pub type VMap = Rc<RefCell<OrderedMap<Value>>>;
23
24pub type NativeFn = Rc<dyn Fn(&Inj, &Value, &str, &Value) -> Value>;
28
29pub type ModifyFn = Rc<dyn Fn(&Value, &Value, &Value, &Inj, &Value)>;
31
32pub struct Sentinel {
34 pub tag: &'static str,
35}
36
37pub static SKIP: Sentinel = Sentinel { tag: "`$SKIP`" };
38pub static DELETE: Sentinel = Sentinel { tag: "`$DELETE`" };
39
40#[derive(Clone)]
41pub enum Value {
42 Noval,
43 Null,
44 Bool(bool),
45 Num(f64),
46 Str(String),
47 List(VList),
48 Map(VMap),
49 Func(NativeFn),
50 Sentinel(&'static Sentinel),
51}
52
53impl Value {
54 pub fn list(items: Vec<Value>) -> Value {
57 Value::List(Rc::new(RefCell::new(items)))
58 }
59
60 pub fn empty_list() -> Value {
61 Value::list(Vec::new())
62 }
63
64 pub fn map(entries: OrderedMap<Value>) -> Value {
65 Value::Map(Rc::new(RefCell::new(entries)))
66 }
67
68 pub fn empty_map() -> Value {
69 Value::map(OrderedMap::new())
70 }
71
72 pub fn map_of<I: IntoIterator<Item = (String, Value)>>(pairs: I) -> Value {
73 let mut m = OrderedMap::new();
74 for (k, v) in pairs {
75 m.insert(k, v);
76 }
77 Value::map(m)
78 }
79
80 pub fn func<F>(f: F) -> Value
81 where
82 F: Fn(&Inj, &Value, &str, &Value) -> Value + 'static,
83 {
84 Value::Func(Rc::new(f))
85 }
86
87 pub fn str<S: Into<String>>(s: S) -> Value {
88 Value::Str(s.into())
89 }
90
91 pub fn skip() -> Value {
92 Value::Sentinel(&SKIP)
93 }
94
95 pub fn delete() -> Value {
96 Value::Sentinel(&DELETE)
97 }
98
99 pub fn is_noval(&self) -> bool {
102 matches!(self, Value::Noval)
103 }
104
105 pub fn is_null(&self) -> bool {
106 matches!(self, Value::Null)
107 }
108
109 pub fn is_nullish(&self) -> bool {
111 matches!(self, Value::Noval | Value::Null)
112 }
113
114 pub fn is_skip(&self) -> bool {
115 matches!(self, Value::Sentinel(s) if std::ptr::eq(*s, &SKIP))
116 }
117
118 pub fn is_delete(&self) -> bool {
119 matches!(self, Value::Sentinel(s) if std::ptr::eq(*s, &DELETE))
120 }
121
122 pub fn as_str(&self) -> Option<&str> {
123 match self {
124 Value::Str(s) => Some(s.as_str()),
125 _ => None,
126 }
127 }
128
129 pub fn as_bool(&self) -> Option<bool> {
130 match self {
131 Value::Bool(b) => Some(*b),
132 _ => None,
133 }
134 }
135
136 pub fn as_num(&self) -> Option<f64> {
137 match self {
138 Value::Num(n) => Some(*n),
139 _ => None,
140 }
141 }
142
143 pub fn as_list(&self) -> Option<&VList> {
144 match self {
145 Value::List(l) => Some(l),
146 _ => None,
147 }
148 }
149
150 pub fn as_map(&self) -> Option<&VMap> {
151 match self {
152 Value::Map(m) => Some(m),
153 _ => None,
154 }
155 }
156
157 pub fn as_func(&self) -> Option<&NativeFn> {
158 match self {
159 Value::Func(f) => Some(f),
160 _ => None,
161 }
162 }
163
164 pub fn truthy(&self) -> bool {
166 match self {
167 Value::Noval | Value::Null => false,
168 Value::Bool(b) => *b,
169 Value::Num(n) => *n != 0.0 && !n.is_nan(),
170 Value::Str(s) => !s.is_empty(),
171 _ => true,
172 }
173 }
174}
175
176impl PartialEq for Value {
180 fn eq(&self, other: &Value) -> bool {
181 match (self, other) {
182 (Value::Noval, Value::Noval) => true,
183 (Value::Null, Value::Null) => true,
184 (Value::Bool(a), Value::Bool(b)) => a == b,
185 (Value::Num(a), Value::Num(b)) => a == b,
186 (Value::Str(a), Value::Str(b)) => a == b,
187 (Value::Sentinel(a), Value::Sentinel(b)) => std::ptr::eq(*a, *b),
188 (Value::List(a), Value::List(b)) => {
189 if Rc::ptr_eq(a, b) {
190 return true;
191 }
192 let a = a.borrow();
193 let b = b.borrow();
194 a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| x == y)
195 }
196 (Value::Map(a), Value::Map(b)) => {
197 if Rc::ptr_eq(a, b) {
198 return true;
199 }
200 let a = a.borrow();
201 let b = b.borrow();
202 a.len() == b.len()
203 && a.iter()
204 .all(|(k, v)| b.get(k).map(|w| v == w).unwrap_or(false))
205 }
206 _ => false,
207 }
208 }
209}
210
211impl fmt::Debug for Value {
212 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213 match self {
214 Value::Noval => write!(f, "Noval"),
215 Value::Null => write!(f, "Null"),
216 Value::Bool(b) => write!(f, "Bool({b})"),
217 Value::Num(n) => write!(f, "Num({n})"),
218 Value::Str(s) => write!(f, "Str({s:?})"),
219 Value::List(l) => write!(f, "List({:?})", l.borrow()),
220 Value::Map(m) => write!(f, "Map({:?})", m.borrow()),
221 Value::Func(_) => write!(f, "Func(..)"),
222 Value::Sentinel(s) => write!(f, "Sentinel({})", s.tag),
223 }
224 }
225}
226
227impl From<bool> for Value {
229 fn from(b: bool) -> Value {
230 Value::Bool(b)
231 }
232}
233impl From<i64> for Value {
234 fn from(n: i64) -> Value {
235 Value::Num(n as f64)
236 }
237}
238impl From<i32> for Value {
239 fn from(n: i32) -> Value {
240 Value::Num(n as f64)
241 }
242}
243impl From<usize> for Value {
244 fn from(n: usize) -> Value {
245 Value::Num(n as f64)
246 }
247}
248impl From<f64> for Value {
249 fn from(n: f64) -> Value {
250 Value::Num(n)
251 }
252}
253impl From<&str> for Value {
254 fn from(s: &str) -> Value {
255 Value::Str(s.to_string())
256 }
257}
258impl From<String> for Value {
259 fn from(s: String) -> Value {
260 Value::Str(s)
261 }
262}
263impl<T: Into<Value>> From<Vec<T>> for Value {
264 fn from(v: Vec<T>) -> Value {
265 Value::list(v.into_iter().map(Into::into).collect())
266 }
267}
268
269pub fn is_integer_f64(v: f64) -> bool {
276 v.is_finite() && v.fract() == 0.0
277}
278
279pub fn js_string(v: &Value) -> String {
281 match v {
282 Value::Noval => "undefined".to_string(),
283 Value::Null => "null".to_string(),
284 Value::Bool(b) => b.to_string(),
285 Value::Num(n) => num_to_string(*n),
286 Value::Str(s) => s.clone(),
287 Value::List(l) => l
289 .borrow()
290 .iter()
291 .map(|x| match x {
292 Value::Noval | Value::Null => String::new(),
293 _ => js_string(x),
294 })
295 .collect::<Vec<_>>()
296 .join(","),
297 Value::Map(_) => "[object Object]".to_string(),
298 Value::Func(_) => "function".to_string(),
299 Value::Sentinel(s) => s.tag.to_string(),
300 }
301}
302
303pub fn num_to_string(n: f64) -> String {
306 if n.is_nan() {
307 return "NaN".to_string();
308 }
309 if n.is_infinite() {
310 return if n > 0.0 { "Infinity" } else { "-Infinity" }.to_string();
311 }
312 if n == 0.0 {
313 return "0".to_string();
314 }
315 if n.fract() == 0.0 && n.abs() < 1e21 {
316 return format!("{}", n as i128);
318 }
319 let s = format!("{n}");
320 s
321}
322
323pub fn js_to_number(v: &Value) -> f64 {
325 match v {
326 Value::Noval => f64::NAN,
327 Value::Null => 0.0,
328 Value::Bool(b) => {
329 if *b {
330 1.0
331 } else {
332 0.0
333 }
334 }
335 Value::Num(n) => *n,
336 Value::Str(s) => js_string_to_number(s),
337 Value::List(l) => {
338 let b = l.borrow();
339 match b.len() {
340 0 => 0.0,
341 1 => js_to_number(&b[0]),
342 _ => f64::NAN,
343 }
344 }
345 _ => f64::NAN,
346 }
347}
348
349pub fn js_string_to_number(s: &str) -> f64 {
351 let t = s.trim();
352 if t.is_empty() {
353 return 0.0;
354 }
355 if let Some(hex) = t.strip_prefix("0x").or_else(|| t.strip_prefix("0X")) {
356 return i64::from_str_radix(hex, 16)
357 .map(|n| n as f64)
358 .unwrap_or(f64::NAN);
359 }
360 t.parse::<f64>().unwrap_or(f64::NAN)
361}
362
363pub fn js_to_int32(n: f64) -> i32 {
365 if !n.is_finite() {
366 return 0;
367 }
368 let trunc = n.trunc();
369 let m = trunc.rem_euclid(4294967296.0);
371 m as u32 as i32
372}