Skip to main content

jetro_core/eval/
value.rs

1/// Internal value type for the v2 evaluator.
2///
3/// Every compound node (Arr, Obj) is `Arc`-wrapped so that `Val::clone()`
4/// is a single atomic refcount bump — no deep copies during traversal.
5///
6/// The API boundary (`evaluate()`) converts `&serde_json::Value → Val`
7/// once on entry and `Val → serde_json::Value` once on exit.
8use std::borrow::Cow;
9use std::sync::Arc;
10use indexmap::IndexMap;
11use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer};
12use serde::de::{self, Deserialize, Deserializer, MapAccess, SeqAccess, Visitor};
13use serde_json::{Map, Number};
14
15// ── Core type ─────────────────────────────────────────────────────────────────
16//
17// `IntVec` / `FloatVec` are columnar variants: mono-typed numeric arrays
18// stored as `Vec<i64>` / `Vec<f64>` instead of `Vec<Val>`.  This cuts output
19// bandwidth 3x (8B/elem vs 24B Val enum) on producers that emit homogeneous
20// numeric arrays (`range()`, `accumulate` typed fast-path, `from_json` of
21// all-int seq).  Consumers either handle them directly (typed aggregates,
22// serde) or materialize on demand via `as_vals() -> Cow<[Val]>`.
23
24#[derive(Clone, Debug)]
25pub enum Val {
26    Null,
27    Bool(bool),
28    Int(i64),
29    Float(f64),
30    Str(Arc<str>),
31    /// Borrowed slice into a parent `Arc<str>` — zero-alloc view.
32    /// Produced by slice/split-first/substring to avoid a fresh heap
33    /// allocation per row.  Treat identically to `Str` at all semantic
34    /// boundaries (display, serialize, compare, hash).
35    StrSlice(crate::strref::StrRef),
36    Arr(Arc<Vec<Val>>),
37    IntVec(Arc<Vec<i64>>),
38    FloatVec(Arc<Vec<f64>>),
39    StrVec(Arc<Vec<Arc<str>>>),
40    /// Columnar lane of borrowed-slice string views.  Each element is a
41    /// `StrRef` (parent Arc + byte range); emitted by map-slice / split
42    /// fusions to avoid per-row `Val` enum tag + per-row heap allocation.
43    /// Serializes directly as JSON array of strings via `ValRef`.
44    StrSliceVec(Arc<Vec<crate::strref::StrRef>>),
45    Obj(Arc<IndexMap<Arc<str>, Val>>),
46    /// Inline small object — flat `(key, value)` pair slice, no hashtable.
47    /// Used for per-row `map({k1, k2, ..})` projections and similar hot
48    /// loops where the allocating an `Arc<IndexMap>` per row dominates.
49    /// Lookup is linear scan (fine for ≤8 entries); insertion-order
50    /// preserved.  Promote to `Obj` if growth / key churn demands it.
51    ObjSmall(Arc<[(Arc<str>, Val)]>),
52    /// Columnar array-of-objects lane — struct-of-arrays with shared key
53    /// schema.  Each row is an object with the exact same keys in the same
54    /// order; keys stored once in `keys`, row values in `rows[i]`.  Used
55    /// by `map({k1, k2, ..})` projections that produce a uniform-shape
56    /// array.  Serialize iterates once over rows without per-row Arc
57    /// allocation or hashtable reconstruction.
58    ObjVec(Arc<ObjVecData>),
59}
60
61#[derive(Debug)]
62pub struct ObjVecData {
63    pub keys: Arc<[Arc<str>]>,
64    pub rows: Vec<Vec<Val>>,
65}
66
67impl Val {
68    /// Unified borrowed `&str` view that works for both `Val::Str` and
69    /// `Val::StrSlice`.  Returns `None` for non-string variants.
70    #[inline]
71    pub fn as_str_ref(&self) -> Option<&str> {
72        match self {
73            Val::Str(s)      => Some(s.as_ref()),
74            Val::StrSlice(r) => Some(r.as_str()),
75            _                => None,
76        }
77    }
78
79    /// Extract an owning `Arc<str>` — cheap Arc bump for `Val::Str` /
80    /// `Val::StrSlice` covering the full parent, allocates a fresh
81    /// buffer for a partial `StrSlice`.  Returns `None` for non-string
82    /// variants.
83    #[inline]
84    pub fn to_arc_str(&self) -> Option<Arc<str>> {
85        match self {
86            Val::Str(s)      => Some(Arc::clone(s)),
87            Val::StrSlice(r) => Some(r.to_arc()),
88            _                => None,
89        }
90    }
91}
92
93// ── Constants (avoid heap allocation for common nulls) ────────────────────────
94
95thread_local! {
96    static NULL_VAL: Val = Val::Null;
97    /// Per-thread key intern cache — shared across `visit_map` / `From<&Value>`
98    /// calls within a single deserialize to avoid allocating a fresh
99    /// `Arc<str>` for every repeated key across rows of an array.
100    /// Scoped keys live until the cache hits its capacity limit; common
101    /// short keys like "id", "grp", "status" get reused for the entire
102    /// array walk.
103    static KEY_INTERN: std::cell::RefCell<std::collections::HashMap<Box<str>, Arc<str>>> =
104        std::cell::RefCell::new(std::collections::HashMap::with_capacity(64));
105}
106
107/// Intern an object key for the current thread.  Returns a clone of a
108/// cached `Arc<str>` when the key has already been seen; otherwise
109/// allocates once and caches.  Capped at a soft limit to avoid
110/// unbounded growth on pathological docs.
111#[inline]
112pub fn intern_key(k: &str) -> Arc<str> {
113    const CAP: usize = 4096;
114    KEY_INTERN.with(|cell| {
115        let mut m = cell.borrow_mut();
116        if let Some(a) = m.get(k) {
117            return Arc::clone(a);
118        }
119        if m.len() >= CAP {
120            // Fall back to a fresh Arc without caching — prevents
121            // unbounded growth on docs with wildly varying keys.
122            return Arc::<str>::from(k);
123        }
124        let a: Arc<str> = Arc::<str>::from(k);
125        m.insert(k.into(), Arc::clone(&a));
126        a
127    })
128}
129
130// ── Cheap structural operations ───────────────────────────────────────────────
131
132impl Val {
133    /// O(1) field lookup — returns a clone of the child (cheap: Arc bump for Arr/Obj, copy for scalars).
134    #[inline]
135    pub fn get_field(&self, key: &str) -> Val {
136        match self {
137            Val::Obj(m) => m.get(key).cloned().unwrap_or(Val::Null),
138            Val::ObjSmall(pairs) => {
139                for (k, v) in pairs.iter() {
140                    if k.as_ref() == key { return v.clone(); }
141                }
142                Val::Null
143            }
144            _ => Val::Null,
145        }
146    }
147
148    /// O(1) index — returns a clone of the element (cheap: Arc bump for Arr/Obj).
149    #[inline]
150    pub fn get_index(&self, i: i64) -> Val {
151        match self {
152            Val::Arr(a) => {
153                let idx = if i < 0 {
154                    a.len().saturating_sub(i.unsigned_abs() as usize)
155                } else { i as usize };
156                a.get(idx).cloned().unwrap_or(Val::Null)
157            }
158            Val::IntVec(a) => {
159                let idx = if i < 0 {
160                    a.len().saturating_sub(i.unsigned_abs() as usize)
161                } else { i as usize };
162                a.get(idx).copied().map(Val::Int).unwrap_or(Val::Null)
163            }
164            Val::FloatVec(a) => {
165                let idx = if i < 0 {
166                    a.len().saturating_sub(i.unsigned_abs() as usize)
167                } else { i as usize };
168                a.get(idx).copied().map(Val::Float).unwrap_or(Val::Null)
169            }
170            Val::StrVec(a) => {
171                let idx = if i < 0 {
172                    a.len().saturating_sub(i.unsigned_abs() as usize)
173                } else { i as usize };
174                a.get(idx).cloned().map(Val::Str).unwrap_or(Val::Null)
175            }
176            _ => Val::Null,
177        }
178    }
179
180    #[inline] pub fn is_null(&self)   -> bool { matches!(self, Val::Null) }
181    #[inline] pub fn is_bool(&self)   -> bool { matches!(self, Val::Bool(_)) }
182    #[inline] pub fn is_number(&self) -> bool { matches!(self, Val::Int(_) | Val::Float(_)) }
183    #[inline] pub fn is_string(&self) -> bool { matches!(self, Val::Str(_)) }
184    #[inline] pub fn is_array(&self)  -> bool { matches!(self, Val::Arr(_) | Val::IntVec(_) | Val::FloatVec(_) | Val::StrVec(_) | Val::StrSliceVec(_)) }
185    #[inline] pub fn is_object(&self) -> bool { matches!(self, Val::Obj(_) | Val::ObjSmall(_)) }
186
187    /// Array length — also works on columnar variants.
188    #[inline]
189    pub fn arr_len(&self) -> Option<usize> {
190        match self {
191            Val::Arr(a)          => Some(a.len()),
192            Val::IntVec(a)       => Some(a.len()),
193            Val::FloatVec(a)     => Some(a.len()),
194            Val::StrVec(a)       => Some(a.len()),
195            Val::StrSliceVec(a)  => Some(a.len()),
196            Val::ObjVec(d)       => Some(d.rows.len()),
197            _ => None,
198        }
199    }
200
201    #[inline]
202    pub fn as_bool(&self) -> Option<bool> {
203        if let Val::Bool(b) = self { Some(*b) } else { None }
204    }
205
206    #[inline]
207    pub fn as_i64(&self) -> Option<i64> {
208        match self { Val::Int(n) => Some(*n), Val::Float(f) => Some(*f as i64), _ => None }
209    }
210
211    #[inline]
212    pub fn as_f64(&self) -> Option<f64> {
213        match self { Val::Float(f) => Some(*f), Val::Int(n) => Some(*n as f64), _ => None }
214    }
215
216    #[inline]
217    pub fn as_str(&self) -> Option<&str> {
218        if let Val::Str(s) = self { Some(s) } else { None }
219    }
220
221    #[inline]
222    pub fn as_array(&self) -> Option<&[Val]> {
223        if let Val::Arr(a) = self { Some(a) } else { None }
224    }
225
226    /// Materialize any array-like (including columnar) as a `Cow<[Val]>`.
227    /// Borrowed for `Val::Arr`; owned allocation for `Val::IntVec`/`FloatVec`.
228    pub fn as_vals(&self) -> Option<Cow<'_, [Val]>> {
229        match self {
230            Val::Arr(a)      => Some(Cow::Borrowed(a.as_slice())),
231            Val::IntVec(a)   => Some(Cow::Owned(a.iter().map(|n| Val::Int(*n)).collect())),
232            Val::FloatVec(a) => Some(Cow::Owned(a.iter().map(|f| Val::Float(*f)).collect())),
233            Val::StrVec(a)   => Some(Cow::Owned(a.iter().map(|s| Val::Str(s.clone())).collect())),
234            _ => None,
235        }
236    }
237
238    /// Force-materialize a columnar variant to `Val::Arr`.  No-op for `Arr`.
239    pub fn into_arr(self) -> Val {
240        match self {
241            Val::IntVec(a) => {
242                let v: Vec<Val> = a.iter().map(|n| Val::Int(*n)).collect();
243                Val::arr(v)
244            }
245            Val::FloatVec(a) => {
246                let v: Vec<Val> = a.iter().map(|f| Val::Float(*f)).collect();
247                Val::arr(v)
248            }
249            Val::StrVec(a) => {
250                let v: Vec<Val> = a.iter().map(|s| Val::Str(s.clone())).collect();
251                Val::arr(v)
252            }
253            other => other,
254        }
255    }
256
257    pub fn as_array_mut(&mut self) -> Option<&mut Vec<Val>> {
258        if let Val::Arr(a) = self { Some(Arc::make_mut(a)) } else { None }
259    }
260
261    #[inline]
262    pub fn as_object(&self) -> Option<&IndexMap<Arc<str>, Val>> {
263        if let Val::Obj(m) = self { Some(m) } else { None }
264    }
265
266    pub fn as_object_mut(&mut self) -> Option<&mut IndexMap<Arc<str>, Val>> {
267        if let Val::Obj(m) = self { Some(Arc::make_mut(m)) } else { None }
268    }
269
270    /// Read-only get (serde_json compat shim).
271    pub fn get(&self, key: &str) -> Option<&Val> {
272        match self {
273            Val::Obj(m) => m.get(key),
274            _           => None,
275        }
276    }
277
278    pub fn type_name(&self) -> &'static str {
279        match self {
280            Val::Null    => "null",
281            Val::Bool(_) => "bool",
282            Val::Int(_) | Val::Float(_) => "number",
283            Val::Str(_) | Val::StrSlice(_) => "string",
284            Val::Arr(_) | Val::IntVec(_) | Val::FloatVec(_) | Val::StrVec(_) | Val::StrSliceVec(_) | Val::ObjVec(_) => "array",
285            Val::Obj(_) | Val::ObjSmall(_) => "object",
286        }
287    }
288
289    /// Consume self and produce a mutable Vec (clone only if shared).
290    /// Columnar variants are materialized into `Vec<Val>`.
291    pub fn into_vec(self) -> Option<Vec<Val>> {
292        match self {
293            Val::Arr(a) => Some(Arc::try_unwrap(a).unwrap_or_else(|a| (*a).clone())),
294            Val::IntVec(a) => Some(a.iter().map(|n| Val::Int(*n)).collect()),
295            Val::FloatVec(a) => Some(a.iter().map(|f| Val::Float(*f)).collect()),
296            Val::StrVec(a) => Some(a.iter().map(|s| Val::Str(s.clone())).collect()),
297            _ => None,
298        }
299    }
300
301    /// Consume self and produce a mutable map (clone only if shared).
302    pub fn into_map(self) -> Option<IndexMap<Arc<str>, Val>> {
303        if let Val::Obj(m) = self {
304            Some(Arc::try_unwrap(m).unwrap_or_else(|m| (*m).clone()))
305        } else { None }
306    }
307
308    /// Build a Val::Arr from a Vec without an extra allocation.
309    #[inline]
310    pub fn arr(v: Vec<Val>) -> Self { Val::Arr(Arc::new(v)) }
311
312    /// Build a columnar `Val::IntVec` from a `Vec<i64>`.
313    #[inline]
314    pub fn int_vec(v: Vec<i64>) -> Self { Val::IntVec(Arc::new(v)) }
315
316    /// Build a columnar `Val::FloatVec` from a `Vec<f64>`.
317    #[inline]
318    pub fn float_vec(v: Vec<f64>) -> Self { Val::FloatVec(Arc::new(v)) }
319
320    /// Build a columnar `Val::StrVec` from a `Vec<Arc<str>>`.
321    #[inline]
322    pub fn str_vec(v: Vec<Arc<str>>) -> Self { Val::StrVec(Arc::new(v)) }
323
324    /// Build a Val::Obj from an IndexMap without an extra allocation.
325    #[inline]
326    pub fn obj(m: IndexMap<Arc<str>, Val>) -> Self { Val::Obj(Arc::new(m)) }
327
328    /// Intern a string key.
329    #[inline]
330    pub fn key(s: &str) -> Arc<str> { Arc::from(s) }
331}
332
333// ── serde_json::Value ↔ Val conversions ───────────────────────────────────────
334
335impl From<&serde_json::Value> for Val {
336    fn from(v: &serde_json::Value) -> Self {
337        match v {
338            serde_json::Value::Null      => Val::Null,
339            serde_json::Value::Bool(b)   => Val::Bool(*b),
340            serde_json::Value::Number(n) => {
341                if let Some(i) = n.as_i64() { Val::Int(i) }
342                else { Val::Float(n.as_f64().unwrap_or(0.0)) }
343            }
344            serde_json::Value::String(s) => Val::Str(Arc::from(s.as_str())),
345            serde_json::Value::Array(a)  => {
346                // Columnar fast-path: homogeneous all-int arrays become
347                // `Val::IntVec`.  Saves 3x storage for big numeric docs.
348                let all_i64 = !a.is_empty() && a.iter().all(|v| matches!(v,
349                    serde_json::Value::Number(n) if n.is_i64()));
350                if all_i64 {
351                    let out: Vec<i64> = a.iter().filter_map(|v|
352                        if let serde_json::Value::Number(n) = v { n.as_i64() } else { None }
353                    ).collect();
354                    return Val::IntVec(Arc::new(out));
355                }
356                // Homogeneous all-string arrays promote to Val::StrVec for
357                // columnar filter/contains fast paths.
358                let all_str = !a.is_empty() && a.iter()
359                    .all(|v| matches!(v, serde_json::Value::String(_)));
360                if all_str {
361                    let out: Vec<Arc<str>> = a.iter().filter_map(|v|
362                        if let serde_json::Value::String(s) = v { Some(Arc::from(s.as_str())) } else { None }
363                    ).collect();
364                    return Val::StrVec(Arc::new(out));
365                }
366                Val::Arr(Arc::new(a.iter().map(Val::from).collect()))
367            }
368            serde_json::Value::Object(m) => Val::Obj(Arc::new(
369                m.iter().map(|(k, v)| (intern_key(k.as_str()), Val::from(v))).collect()
370            )),
371        }
372    }
373}
374
375impl From<Val> for serde_json::Value {
376    fn from(v: Val) -> Self {
377        match v {
378            Val::Null    => serde_json::Value::Null,
379            Val::Bool(b) => serde_json::Value::Bool(b),
380            Val::Int(n)  => serde_json::Value::Number(n.into()),
381            Val::Float(f) => serde_json::Value::Number(
382                Number::from_f64(f).unwrap_or_else(|| 0.into())
383            ),
384            Val::Str(s)       => serde_json::Value::String(s.to_string()),
385            Val::StrSlice(r)  => serde_json::Value::String(r.as_str().to_string()),
386            Val::Arr(a)  => {
387                let mut out: Vec<serde_json::Value> = Vec::with_capacity(a.len());
388                match Arc::try_unwrap(a) {
389                    Ok(vec) => for item in vec { out.push(item.into()); }
390                    Err(a)  => for item in a.iter() { out.push(item.clone().into()); }
391                }
392                serde_json::Value::Array(out)
393            }
394            Val::IntVec(a) => {
395                let out: Vec<serde_json::Value> =
396                    a.iter().map(|n| serde_json::Value::Number((*n).into())).collect();
397                serde_json::Value::Array(out)
398            }
399            Val::FloatVec(a) => {
400                let out: Vec<serde_json::Value> = a.iter().map(|f|
401                    serde_json::Value::Number(Number::from_f64(*f).unwrap_or_else(|| 0.into()))
402                ).collect();
403                serde_json::Value::Array(out)
404            }
405            Val::StrVec(a) => {
406                let out: Vec<serde_json::Value> =
407                    a.iter().map(|s| serde_json::Value::String(s.to_string())).collect();
408                serde_json::Value::Array(out)
409            }
410            Val::StrSliceVec(a) => {
411                let out: Vec<serde_json::Value> =
412                    a.iter().map(|r| serde_json::Value::String(r.as_str().to_string())).collect();
413                serde_json::Value::Array(out)
414            }
415            Val::ObjVec(d) => {
416                let mut out: Vec<serde_json::Value> = Vec::with_capacity(d.rows.len());
417                for row in &d.rows {
418                    let mut map: Map<String, serde_json::Value> = Map::with_capacity(d.keys.len());
419                    for (k, v) in d.keys.iter().zip(row.iter()) {
420                        map.insert(k.to_string(), v.clone().into());
421                    }
422                    out.push(serde_json::Value::Object(map));
423                }
424                serde_json::Value::Array(out)
425            }
426            Val::Obj(m)  => {
427                let mut map: Map<String, serde_json::Value> = Map::with_capacity(m.len());
428                match Arc::try_unwrap(m) {
429                    Ok(im) => for (k, v) in im { map.insert(k.to_string(), v.into()); }
430                    Err(m) => for (k, v) in m.iter() { map.insert(k.to_string(), v.clone().into()); }
431                }
432                serde_json::Value::Object(map)
433            }
434            Val::ObjSmall(pairs) => {
435                let mut map: Map<String, serde_json::Value> = Map::with_capacity(pairs.len());
436                for (k, v) in pairs.iter() {
437                    map.insert(k.to_string(), v.clone().into());
438                }
439                serde_json::Value::Object(map)
440            }
441        }
442    }
443}
444
445// ── Lazy serde adapter ────────────────────────────────────────────────────────
446//
447// `ValRef<'a>` serialises a borrowed `Val` directly to the output byte
448// stream, skipping the intermediate `serde_json::Value` tree that
449// `From<Val> for serde_json::Value` builds.  For Obj-heavy results this
450// elides N key-string clones + the `Map` rebuild per call.
451//
452// Non-finite floats (NaN/±Inf) are coerced to `0` to match the existing
453// `From<Val>` impl, which falls back to `0.into()` when `Number::from_f64`
454// returns `None`.
455
456pub struct ValRef<'a>(pub &'a Val);
457
458impl<'a> Serialize for ValRef<'a> {
459    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
460        match self.0 {
461            Val::Null    => s.serialize_unit(),
462            Val::Bool(b) => s.serialize_bool(*b),
463            Val::Int(n)  => s.serialize_i64(*n),
464            Val::Float(f) => {
465                if f.is_finite() { s.serialize_f64(*f) } else { s.serialize_i64(0) }
466            }
467            Val::Str(v)       => s.serialize_str(v),
468            Val::StrSlice(r)  => s.serialize_str(r.as_str()),
469            Val::Arr(a)  => {
470                let mut seq = s.serialize_seq(Some(a.len()))?;
471                for item in a.iter() { seq.serialize_element(&ValRef(item))?; }
472                seq.end()
473            }
474            Val::IntVec(a) => {
475                let mut seq = s.serialize_seq(Some(a.len()))?;
476                for n in a.iter() { seq.serialize_element(n)?; }
477                seq.end()
478            }
479            Val::FloatVec(a) => {
480                let mut seq = s.serialize_seq(Some(a.len()))?;
481                for f in a.iter() {
482                    if f.is_finite() { seq.serialize_element(f)?; }
483                    else { seq.serialize_element(&0i64)?; }
484                }
485                seq.end()
486            }
487            Val::StrVec(a) => {
488                let mut seq = s.serialize_seq(Some(a.len()))?;
489                for v in a.iter() { seq.serialize_element(v.as_ref())?; }
490                seq.end()
491            }
492            Val::StrSliceVec(a) => {
493                let mut seq = s.serialize_seq(Some(a.len()))?;
494                for r in a.iter() { seq.serialize_element(r.as_str())?; }
495                seq.end()
496            }
497            Val::ObjVec(d) => {
498                let mut seq = s.serialize_seq(Some(d.rows.len()))?;
499                // Serialise each row as a map with the shared key schema.
500                // Walks keys + row in lock-step; no per-row hashtable.
501                struct RowRef<'a> { keys: &'a [Arc<str>], row: &'a [Val] }
502                impl<'a> Serialize for RowRef<'a> {
503                    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
504                        let mut m = s.serialize_map(Some(self.keys.len()))?;
505                        for (k, v) in self.keys.iter().zip(self.row.iter()) {
506                            m.serialize_entry(k.as_ref(), &ValRef(v))?;
507                        }
508                        m.end()
509                    }
510                }
511                for row in &d.rows {
512                    seq.serialize_element(&RowRef { keys: &d.keys, row })?;
513                }
514                seq.end()
515            }
516            Val::Obj(m)  => {
517                let mut map = s.serialize_map(Some(m.len()))?;
518                for (k, v) in m.iter() {
519                    map.serialize_entry(k.as_ref(), &ValRef(v))?;
520                }
521                map.end()
522            }
523            Val::ObjSmall(pairs) => {
524                let mut map = s.serialize_map(Some(pairs.len()))?;
525                for (k, v) in pairs.iter() {
526                    map.serialize_entry(k.as_ref(), &ValRef(v))?;
527                }
528                map.end()
529            }
530        }
531    }
532}
533
534impl Val {
535    /// Serialise `self` as JSON bytes without building an intermediate
536    /// `serde_json::Value` tree.  Preferred over `serde_json::to_vec(&Value::from(val))`
537    /// for Obj-heavy results.
538    pub fn to_json_vec(&self) -> Vec<u8> {
539        serde_json::to_vec(&ValRef(self)).unwrap_or_default()
540    }
541
542    /// Stream `self` as JSON into an `io::Write` sink.
543    pub fn write_json<W: std::io::Write>(&self, w: W) -> serde_json::Result<()> {
544        serde_json::to_writer(w, &ValRef(self))
545    }
546
547    /// Parse JSON text into `Val` directly — one pass, no intermediate
548    /// `serde_json::Value` tree.  Preferred over the
549    /// `serde_json::from_str -> serde_json::Value -> Val::from` round-trip
550    /// for hot `from_json` paths.
551    pub fn from_json_str(s: &str) -> serde_json::Result<Val> {
552        let mut de = serde_json::Deserializer::from_str(s);
553        let v = Val::deserialize(&mut de)?;
554        de.end()?;
555        Ok(v)
556    }
557
558    pub fn from_json_slice(b: &[u8]) -> serde_json::Result<Val> {
559        let mut de = serde_json::Deserializer::from_slice(b);
560        let v = Val::deserialize(&mut de)?;
561        de.end()?;
562        Ok(v)
563    }
564
565    /// Parse JSON via simd-json (SIMD-accelerated structural scanner).
566    /// Requires the `simd-json` feature.  Input bytes are mutated in-place
567    /// by the simd-json parser — caller must own a writable buffer.
568    /// Falls back to `from_json_slice` on parse error from the simd path.
569    #[cfg(feature = "simd-json")]
570    pub fn from_json_simd(bytes: &mut [u8]) -> Result<Val, String> {
571        simd_json::serde::from_slice::<Val>(bytes).map_err(|e| e.to_string())
572    }
573}
574
575// ── Direct Deserialize ────────────────────────────────────────────────────────
576//
577// Avoids the intermediate `serde_json::Value` tree that `b_from_json` used
578// to build.  Preserves order by using IndexMap directly in the visitor.
579
580struct ValVisitor;
581
582impl<'de> Visitor<'de> for ValVisitor {
583    type Value = Val;
584
585    fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
586        f.write_str("any JSON value")
587    }
588
589    fn visit_unit<E: de::Error>(self) -> Result<Val, E> { Ok(Val::Null) }
590    fn visit_none<E: de::Error>(self) -> Result<Val, E> { Ok(Val::Null) }
591    fn visit_some<D: Deserializer<'de>>(self, d: D) -> Result<Val, D::Error> {
592        Val::deserialize(d)
593    }
594    fn visit_bool<E: de::Error>(self, b: bool) -> Result<Val, E> { Ok(Val::Bool(b)) }
595    fn visit_i64<E: de::Error>(self, n: i64) -> Result<Val, E>  { Ok(Val::Int(n)) }
596    fn visit_u64<E: de::Error>(self, n: u64) -> Result<Val, E>  {
597        if n <= i64::MAX as u64 { Ok(Val::Int(n as i64)) } else { Ok(Val::Float(n as f64)) }
598    }
599    fn visit_f64<E: de::Error>(self, f: f64) -> Result<Val, E>  { Ok(Val::Float(f)) }
600    fn visit_str<E: de::Error>(self, s: &str) -> Result<Val, E> { Ok(Val::Str(Arc::from(s))) }
601    fn visit_string<E: de::Error>(self, s: String) -> Result<Val, E> { Ok(Val::Str(Arc::from(s.as_str()))) }
602    fn visit_borrowed_str<E: de::Error>(self, s: &'de str) -> Result<Val, E> { Ok(Val::Str(Arc::from(s))) }
603
604    fn visit_seq<A: SeqAccess<'de>>(self, mut a: A) -> Result<Val, A::Error> {
605        // Speculative columnar path: lock the lane on the first element.
606        // While every subsequent element matches the lane, push into the
607        // typed vec; on first mismatch, migrate to `Vec<Val>`.  Empty arrays
608        // default to generic Val::Arr (no lane to commit to).
609        enum Lane { Unset, Int(Vec<i64>), Str(Vec<Arc<str>>) }
610        let cap = a.size_hint().unwrap_or(0);
611        let mut lane: Lane = Lane::Unset;
612        let mut fallback: Option<Vec<Val>> = None;
613        while let Some(item) = a.next_element::<Val>()? {
614            if let Some(v) = fallback.as_mut() { v.push(item); continue; }
615            match (&mut lane, item) {
616                (Lane::Unset, Val::Int(n)) => lane = Lane::Int(vec![n]),
617                (Lane::Unset, Val::Str(s)) => lane = Lane::Str(vec![s]),
618                (Lane::Unset, other) => {
619                    let mut v: Vec<Val> = Vec::with_capacity(cap);
620                    v.push(other);
621                    fallback = Some(v);
622                }
623                (Lane::Int(xs), Val::Int(n)) => xs.push(n),
624                (Lane::Str(xs), Val::Str(s)) => xs.push(s),
625                (lane_ref, other) => {
626                    let mut v: Vec<Val> = Vec::with_capacity(cap);
627                    match std::mem::replace(lane_ref, Lane::Unset) {
628                        Lane::Int(xs) => for n in xs { v.push(Val::Int(n)); }
629                        Lane::Str(xs) => for s in xs { v.push(Val::Str(s)); }
630                        Lane::Unset   => {}
631                    }
632                    v.push(other);
633                    fallback = Some(v);
634                }
635            }
636        }
637        Ok(match fallback {
638            Some(v) => Val::arr(v),
639            None => match lane {
640                Lane::Int(xs) => Val::IntVec(Arc::new(xs)),
641                Lane::Str(xs) => Val::StrVec(Arc::new(xs)),
642                Lane::Unset   => Val::arr(Vec::new()),
643            },
644        })
645    }
646    fn visit_map<A: MapAccess<'de>>(self, mut m: A) -> Result<Val, A::Error> {
647        let mut out: IndexMap<Arc<str>, Val> =
648            IndexMap::with_capacity(m.size_hint().unwrap_or(0));
649        while let Some((k, v)) = m.next_entry::<String, Val>()? {
650            out.insert(intern_key(k.as_str()), v);
651        }
652        Ok(Val::obj(out))
653    }
654}
655
656impl<'de> serde::Deserialize<'de> for Val {
657    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Val, D::Error> {
658        d.deserialize_any(ValVisitor)
659    }
660}
661
662#[cfg(test)]
663mod valref_tests {
664    use super::*;
665
666    fn roundtrip(js: &str) {
667        let v: serde_json::Value = serde_json::from_str(js).unwrap();
668        let val = Val::from(&v);
669        let via_tree = serde_json::to_vec(&serde_json::Value::from(val.clone())).unwrap();
670        let via_ref  = val.to_json_vec();
671        // Both paths must serialise to byte-identical JSON (IndexMap and
672        // serde_json::Map both preserve insertion order).
673        assert_eq!(via_tree, via_ref, "payload: {js}");
674    }
675
676    #[test]
677    fn valref_parity_scalars()  { roundtrip(r#"null"#); roundtrip(r#"true"#); roundtrip(r#"42"#); roundtrip(r#"3.14"#); roundtrip(r#""hi""#); }
678
679    #[test]
680    fn valref_parity_array()    { roundtrip(r#"[1,2,3,"x",null,true,4.5]"#); }
681
682    #[test]
683    fn valref_parity_object()   { roundtrip(r#"{"a":1,"b":"x","c":[1,2],"d":{"nested":true}}"#); }
684
685    #[test]
686    fn valref_parity_deep() {
687        roundtrip(r#"{"orders":[{"id":1,"items":[{"sku":"A","qty":2}]},{"id":2,"items":[]}]}"#);
688    }
689
690    #[test]
691    fn valref_nan_inf_coerced_to_zero() {
692        let val = Val::Float(f64::NAN);
693        assert_eq!(val.to_json_vec(), b"0");
694        let val = Val::Float(f64::INFINITY);
695        assert_eq!(val.to_json_vec(), b"0");
696    }
697}
698
699// ── PartialEq for comparison ──────────────────────────────────────────────────
700
701impl PartialEq for Val {
702    fn eq(&self, other: &Self) -> bool {
703        match (self, other) {
704            (Val::Null,    Val::Null)    => true,
705            (Val::Bool(a), Val::Bool(b)) => a == b,
706            (Val::Str(a),  Val::Str(b))      => a == b,
707            (Val::Str(a),  Val::StrSlice(b)) => a.as_ref() == b.as_str(),
708            (Val::StrSlice(a), Val::Str(b))  => a.as_str() == b.as_ref(),
709            (Val::StrSlice(a), Val::StrSlice(b)) => a.as_str() == b.as_str(),
710            (Val::Int(a),  Val::Int(b))  => a == b,
711            (Val::Float(a), Val::Float(b)) => a == b,
712            (Val::Int(a),  Val::Float(b)) => (*a as f64) == *b,
713            (Val::Float(a), Val::Int(b))  => *a == (*b as f64),
714            (Val::IntVec(a), Val::IntVec(b)) => a == b,
715            (Val::FloatVec(a), Val::FloatVec(b)) => a == b,
716            (Val::StrVec(a), Val::StrVec(b)) => a == b,
717            _ => false,
718        }
719    }
720}
721
722impl Eq for Val {}
723
724impl std::hash::Hash for Val {
725    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
726        match self {
727            Val::Null       => 0u8.hash(state),
728            Val::Bool(b)    => { 1u8.hash(state); b.hash(state); }
729            Val::Int(n)     => { 2u8.hash(state); n.hash(state); }
730            Val::Float(f)   => { 2u8.hash(state); f.to_bits().hash(state); }
731            Val::Str(s)       => { 3u8.hash(state); s.hash(state); }
732            Val::StrSlice(r)  => { 3u8.hash(state); r.as_str().hash(state); }
733            Val::Arr(a)     => { 4u8.hash(state); (Arc::as_ptr(a) as usize).hash(state); }
734            Val::IntVec(a)  => { 4u8.hash(state); (Arc::as_ptr(a) as usize).hash(state); }
735            Val::FloatVec(a) => { 4u8.hash(state); (Arc::as_ptr(a) as usize).hash(state); }
736            Val::StrVec(a)  => { 4u8.hash(state); (Arc::as_ptr(a) as usize).hash(state); }
737            Val::StrSliceVec(a) => { 4u8.hash(state); (Arc::as_ptr(a) as usize).hash(state); }
738            Val::ObjVec(d)      => { 5u8.hash(state); (Arc::as_ptr(d) as usize).hash(state); }
739            Val::Obj(m)       => { 5u8.hash(state); (Arc::as_ptr(m) as usize).hash(state); }
740            Val::ObjSmall(p)  => { 5u8.hash(state); (p.as_ptr() as usize).hash(state); }
741        }
742    }
743}
744
745// ── Display ───────────────────────────────────────────────────────────────────
746
747impl std::fmt::Display for Val {
748    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
749        match self {
750            Val::Null      => write!(f, "null"),
751            Val::Bool(b)   => write!(f, "{}", b),
752            Val::Int(n)    => write!(f, "{}", n),
753            Val::Float(fl) => write!(f, "{}", fl),
754            Val::Str(s)       => write!(f, "{}", s),
755            Val::StrSlice(r)  => write!(f, "{}", r.as_str()),
756            other => {
757                let bytes = serde_json::to_vec(&ValRef(other)).unwrap_or_default();
758                f.write_str(std::str::from_utf8(&bytes).unwrap_or(""))
759            }
760        }
761    }
762}