Skip to main content

cljrs_value/
value.rs

1use std::cmp::Ordering;
2use std::fmt;
3use std::sync::{Arc, Mutex};
4
5use crate::collections::{
6    PersistentArrayMap, PersistentHashMap, PersistentHashSet, PersistentList, PersistentQueue,
7    PersistentVector, SortedMap, SortedSet, TransientMap, TransientSet, TransientVector,
8};
9use crate::error::{ExceptionInfo, ValueError};
10use crate::hash::{
11    ClojureHash, hash_combine_ordered, hash_combine_unordered, hash_i64, hash_string, hash_u128,
12};
13use crate::keyword::Keyword;
14use crate::regex::{Matcher, Pattern};
15use crate::resource::ResourceHandle;
16use crate::shared::SharedAtom;
17use crate::symbol::Symbol;
18use crate::types::{
19    Agent, Atom, BoundFn, CljxCons, CljxFn, CljxFuture, CljxPromise, Delay, LazySeq, MultiFn,
20    Namespace, NativeFn, Protocol, ProtocolFn, Var, Volatile,
21};
22use cljrs_gc::{GcPtr, MarkVisitor, Trace};
23use num_bigint::BigInt;
24use num_traits::ToPrimitive;
25
26/// A GC-traced mutable array of Values (backs `object-array`).
27#[derive(Debug)]
28pub struct ObjectArray(pub Mutex<Vec<Value>>);
29
30impl ObjectArray {
31    pub fn new(v: Vec<Value>) -> Self {
32        Self(Mutex::new(v))
33    }
34}
35
36impl Trace for ObjectArray {
37    fn trace(&self, visitor: &mut MarkVisitor) {
38        {
39            let guard = self.0.lock().unwrap();
40            for v in guard.iter() {
41                v.trace(visitor);
42            }
43        }
44    }
45
46    fn gc_size_extra(&self) -> usize {
47        let guard = self.0.lock().unwrap();
48        guard.capacity() * std::mem::size_of::<Value>()
49    }
50}
51
52/// The central runtime type: every Clojure value is a `Value`.
53///
54/// Small scalars (`Nil`, `Bool`, `Long`, `Double`, `Char`) are stored inline.
55/// All heap-allocated types go behind `GcPtr` so that `clone()` is O(1).
56#[derive(Clone, Debug)]
57pub enum Value {
58    // ── Scalars ───────────────────────────────────────────────────────────────
59    Nil,
60    Bool(bool),
61    Long(i64),
62    Double(f64),
63    BigInt(GcPtr<BigInt>),
64    BigDecimal(GcPtr<bigdecimal::BigDecimal>),
65    Ratio(GcPtr<num_rational::Ratio<BigInt>>),
66    Char(char),
67    Str(GcPtr<String>),
68    Uuid(u128),
69    Pattern(GcPtr<Pattern>),
70    Matcher(GcPtr<Matcher>),
71
72    // ── Identifiers ───────────────────────────────────────────────────────────
73    Symbol(GcPtr<Symbol>),
74    Keyword(GcPtr<Keyword>),
75
76    // ── Collections ───────────────────────────────────────────────────────────
77    List(GcPtr<PersistentList>),
78    Vector(GcPtr<PersistentVector>),
79    /// Small maps (≤8 entries) are stored as an ArrayMap; larger ones as a HashMap.
80    /// Also contains sorted map.
81    Map(MapValue),
82    Set(SetValue),
83    Queue(GcPtr<PersistentQueue>),
84
85    // Transients
86    TransientMap(GcPtr<TransientMap>),
87    TransientSet(GcPtr<TransientSet>),
88    TransientVector(GcPtr<TransientVector>),
89
90    // Arrays
91    IntArray(GcPtr<Mutex<Vec<i32>>>),
92    LongArray(GcPtr<Mutex<Vec<i64>>>),
93    ShortArray(GcPtr<Mutex<Vec<i16>>>),
94    ByteArray(GcPtr<Mutex<Vec<i8>>>),
95    FloatArray(GcPtr<Mutex<Vec<f32>>>),
96    DoubleArray(GcPtr<Mutex<Vec<f64>>>),
97    BooleanArray(GcPtr<Mutex<Vec<bool>>>),
98    CharArray(GcPtr<Mutex<Vec<char>>>),
99    ObjectArray(GcPtr<ObjectArray>),
100
101    // ── Functions ─────────────────────────────────────────────────────────────
102    NativeFunction(GcPtr<NativeFn>),
103    Fn(GcPtr<CljxFn>),
104    Macro(GcPtr<CljxFn>),
105    BoundFn(GcPtr<BoundFn>),
106
107    // ── Mutable state ─────────────────────────────────────────────────────────
108    Var(GcPtr<Var>),
109    Atom(GcPtr<Atom>),
110    /// Cross-isolate mutable reference backed by `Arc<ArcSwap<SharedValue>>`.
111    /// Unlike `Atom`, a `SharedAtom` can cross the isolate boundary (the `Arc`
112    /// is cloned, not deep-copied) and its contents are lock-free CAS-swapped.
113    SharedAtom(std::sync::Arc<SharedAtom>),
114    /// Immutable refcounted byte buffer (the BEAM off-heap-binary trick).
115    /// Shared without copy across the isolate boundary; refcount drops to zero
116    /// only when every isolate releases its reference.
117    ByteBlob(std::sync::Arc<[u8]>),
118
119    // ── Reduced (early termination sentinel for reduce/transduce) ───────────
120    Reduced(Box<Value>),
121
122    // ── Other ─────────────────────────────────────────────────────────────────
123    Namespace(GcPtr<Namespace>),
124
125    // ── Lazy sequences ────────────────────────────────────────────────────────
126    /// A deferred sequence cell — realized at most once.
127    LazySeq(GcPtr<LazySeq>),
128    /// A realized cons cell whose tail may itself be lazy.
129    Cons(GcPtr<CljxCons>),
130
131    // ── Protocols & Multimethods ──────────────────────────────────────────────
132    Protocol(GcPtr<Protocol>),
133    ProtocolFn(GcPtr<ProtocolFn>),
134    MultiFn(GcPtr<MultiFn>),
135
136    // ── Concurrency primitives ────────────────────────────────────────────────
137    Volatile(GcPtr<Volatile>),
138    Delay(GcPtr<Delay>),
139    Promise(GcPtr<CljxPromise>),
140    Future(GcPtr<CljxFuture>),
141    Agent(GcPtr<Agent>),
142
143    // ── Records / reify instances ─────────────────────────────────────────────
144    TypeInstance(GcPtr<TypeInstance>),
145
146    // ── Native Rust objects (GcPtr-managed, for interop) ─────────────────────
147    NativeObject(GcPtr<crate::native_object::NativeObjectBox>),
148
149    // ── I/O resources (Arc-ref-counted, NOT GcPtr) ───────────────────────────
150    Resource(ResourceHandle),
151
152    // ── Metadata wrapper ─────────────────────────────────────────────────────
153    /// A value with attached metadata. Transparent for equality, hashing, display.
154    WithMeta(Box<Value>, Box<Value>),
155
156    // Errors
157    Error(GcPtr<ExceptionInfo>),
158}
159
160/// A map value: either a small array-map or a HAMT-based hash-map.
161#[derive(Clone, Debug)]
162pub enum MapValue {
163    Array(GcPtr<PersistentArrayMap>),
164    Hash(GcPtr<PersistentHashMap>),
165    Sorted(GcPtr<SortedMap>),
166}
167
168impl MapValue {
169    pub fn empty() -> Self {
170        MapValue::Array(GcPtr::new(PersistentArrayMap::empty()))
171    }
172
173    /// Build a map from pre-evaluated key-value pairs.
174    ///
175    /// Chooses the optimal representation based on size: ArrayMap for small
176    /// maps (≤8 entries), HashTrieMap for larger ones. This avoids N
177    /// intermediate allocations that `empty() + assoc + assoc + ...` would
178    /// create.
179    pub fn from_pairs(pairs: Vec<(Value, Value)>) -> Self {
180        use crate::collections::array_map::AssocResult;
181
182        // Check for duplicates by building through assoc (last wins).
183        match PersistentArrayMap::from_pairs(pairs) {
184            AssocResult::Array(m) => MapValue::Array(GcPtr::new(m)),
185            AssocResult::Promote(pairs) => {
186                MapValue::Hash(GcPtr::new(PersistentHashMap::from_pairs(pairs)))
187            }
188        }
189    }
190
191    /// Build a map from a flat evaluated entries vector `[k0, v0, k1, v1, ...]`.
192    ///
193    /// Similar to `from_pairs` but takes flat key-value entries. Handles
194    /// duplicate keys (last wins via assoc). Avoids intermediate allocations.
195    pub fn from_flat_entries(entries: Vec<Value>) -> Self {
196        debug_assert!(entries.len().is_multiple_of(2));
197        // We need to handle duplicate keys, so build through assoc.
198        let pairs: Vec<(Value, Value)> = entries
199            .chunks(2)
200            .map(|chunk| (chunk[0].clone(), chunk[1].clone()))
201            .collect();
202        Self::from_pairs(pairs)
203    }
204
205    pub fn get(&self, key: &Value) -> Option<Value> {
206        match self {
207            MapValue::Array(m) => m.get().get(key).cloned(),
208            MapValue::Hash(m) => m.get().get(key).cloned(),
209            MapValue::Sorted(m) => m.get().get(key).cloned(),
210        }
211    }
212
213    pub fn count(&self) -> usize {
214        match self {
215            MapValue::Array(m) => m.get().count(),
216            MapValue::Hash(m) => m.get().count(),
217            MapValue::Sorted(m) => m.get().count(),
218        }
219    }
220
221    pub fn assoc(&self, k: Value, v: Value) -> Self {
222        match self {
223            MapValue::Array(m) => match m.get().assoc(k, v) {
224                crate::collections::array_map::AssocResult::Array(new_m) => {
225                    MapValue::Array(GcPtr::new(new_m))
226                }
227                crate::collections::array_map::AssocResult::Promote(pairs) => {
228                    let hm = PersistentHashMap::from_pairs(pairs);
229                    MapValue::Hash(GcPtr::new(hm))
230                }
231            },
232            MapValue::Hash(m) => MapValue::Hash(GcPtr::new(m.get().assoc(k, v))),
233            MapValue::Sorted(m) => MapValue::Sorted(GcPtr::new(m.get().assoc(k, v))),
234        }
235    }
236
237    pub fn dissoc(&self, key: &Value) -> Self {
238        match self {
239            MapValue::Array(m) => MapValue::Array(GcPtr::new(m.get().dissoc(key))),
240            MapValue::Hash(m) => MapValue::Hash(GcPtr::new(m.get().dissoc(key))),
241            MapValue::Sorted(m) => MapValue::Sorted(GcPtr::new(m.get().dissoc(key))),
242        }
243    }
244
245    pub fn contains_key(&self, key: &Value) -> bool {
246        match self {
247            MapValue::Array(m) => m.get().contains_key(key),
248            MapValue::Hash(m) => m.get().contains_key(key),
249            MapValue::Sorted(m) => m.get().contains_key(key),
250        }
251    }
252
253    /// Iterate over all `(key, value)` pairs.
254    pub fn for_each<F: FnMut(&Value, &Value)>(&self, mut f: F) {
255        match self {
256            MapValue::Array(m) => {
257                for (k, v) in m.get().iter() {
258                    f(k, v);
259                }
260            }
261            MapValue::Hash(m) => {
262                for (k, v) in m.get().iter() {
263                    f(k, v);
264                }
265            }
266            MapValue::Sorted(m) => {
267                for (k, v) in m.get().iter() {
268                    f(k, v);
269                }
270            }
271        }
272    }
273
274    /// Iterate over key/value pairs.
275    pub fn iter(&self) -> Box<dyn Iterator<Item = (&Value, &Value)> + '_> {
276        match self {
277            MapValue::Array(m) => Box::new(m.get().iter()),
278            MapValue::Hash(m) => Box::new(m.get().iter()),
279            MapValue::Sorted(m) => Box::new(m.get().iter()),
280        }
281    }
282}
283
284/// A set value, either a hash set or a sorted set.
285#[derive(Clone, Debug)]
286pub enum SetValue {
287    Hash(GcPtr<PersistentHashSet>),
288    Sorted(GcPtr<SortedSet>),
289}
290
291impl SetValue {
292    pub fn empty() -> Self {
293        Self::Hash(GcPtr::new(PersistentHashSet::empty()))
294    }
295
296    pub fn count(&self) -> usize {
297        match self {
298            SetValue::Hash(m) => m.get().count(),
299            SetValue::Sorted(m) => m.get().count(),
300        }
301    }
302
303    pub fn is_empty(&self) -> bool {
304        match self {
305            SetValue::Hash(m) => m.get().is_empty(),
306            SetValue::Sorted(m) => m.get().is_empty(),
307        }
308    }
309
310    pub fn contains(&self, key: &Value) -> bool {
311        match self {
312            SetValue::Hash(m) => m.get().contains(key),
313            SetValue::Sorted(m) => m.get().contains(key),
314        }
315    }
316
317    pub fn conj(&self, value: Value) -> Self {
318        match self {
319            SetValue::Hash(m) => SetValue::Hash(GcPtr::new(m.get().conj(value))),
320            SetValue::Sorted(m) => SetValue::Sorted(GcPtr::new(m.get().conj(value))),
321        }
322    }
323
324    pub fn conj_mut(&mut self, value: Value) -> &mut Self {
325        match self {
326            SetValue::Hash(m) => {
327                m.get_mut().conj_mut(value);
328            }
329            SetValue::Sorted(s) => {
330                s.get_mut().conj_mut(value);
331            }
332        }
333        self
334    }
335
336    pub fn disj(&self, value: &Value) -> Self {
337        match self {
338            SetValue::Hash(m) => SetValue::Hash(GcPtr::new(m.get().disj(value))),
339            SetValue::Sorted(m) => SetValue::Sorted(GcPtr::new(m.get().disj(value))),
340        }
341    }
342
343    pub fn iter(&self) -> Box<dyn Iterator<Item = &Value> + '_> {
344        match self {
345            SetValue::Hash(s) => Box::new(s.get().iter()),
346            SetValue::Sorted(s) => Box::new(s.get().iter()),
347        }
348    }
349}
350
351impl cljrs_gc::Trace for SetValue {
352    fn trace(&self, visitor: &mut cljrs_gc::MarkVisitor) {
353        use cljrs_gc::GcVisitor as _;
354        match self {
355            SetValue::Hash(s) => visitor.visit(s),
356            SetValue::Sorted(s) => visitor.visit(s),
357        }
358    }
359}
360
361// ── Equality ──────────────────────────────────────────────────────────────────
362
363impl Eq for Value {}
364
365impl PartialEq for Value {
366    fn eq(&self, other: &Self) -> bool {
367        // Strip metadata — it is ignored for equality in Clojure.
368        if let Value::WithMeta(inner, _) = self {
369            return inner.as_ref() == other;
370        }
371        if let Value::WithMeta(inner, _) = other {
372            return self == inner.as_ref();
373        }
374        // Unwrap Reduced for equality.
375        if let Value::Reduced(inner) = self {
376            return inner.as_ref() == other;
377        }
378        if let Value::Reduced(inner) = other {
379            return self == inner.as_ref();
380        }
381        // Identity shortcut: same GcPtr → equal without realizing.
382        // Required for infinite lazy seqs: (let [r (range)] (= r r)) must not hang.
383        if let (Value::LazySeq(a), Value::LazySeq(b)) = (self, other)
384            && GcPtr::ptr_eq(a, b)
385        {
386            return true;
387        }
388        // Realize lazy sequences before comparing.
389        // A lazy-seq that realizes to nil is an empty sequence, which is equal
390        // to both nil and any empty sequential collection (matching Clojure).
391        if let Value::LazySeq(ls) = self {
392            let realized = ls.get().realize();
393            if realized == Value::Nil && other.is_sequential() {
394                return value_to_seq_vec(other).is_empty();
395            }
396            return realized == *other;
397        }
398        if let Value::LazySeq(ls) = other {
399            let realized = ls.get().realize();
400            if realized == Value::Nil && self.is_sequential() {
401                return value_to_seq_vec(self).is_empty();
402            }
403            return *self == realized;
404        }
405        match (self, other) {
406            (Value::Nil, Value::Nil) => true,
407            (Value::Bool(a), Value::Bool(b)) => a == b,
408            // Numeric cross-type equality.
409            (Value::Long(a), Value::Long(b)) => a == b,
410            (Value::Long(a), Value::BigInt(b)) => BigInt::from(*a) == *b.get(),
411            (Value::BigInt(a), Value::Long(b)) => *a.get() == BigInt::from(*b),
412            (Value::BigInt(a), Value::BigInt(b)) => a.get() == b.get(),
413            (Value::Double(a), Value::Double(b)) => a == b, // NaN != NaN
414            (Value::Long(a), Value::Double(b)) => b.fract() == 0.0 && b.to_i64() == Some(*a),
415            (Value::Double(a), Value::Long(b)) => a.fract() == 0.0 && a.to_i64() == Some(*b),
416            (Value::BigDecimal(a), Value::BigDecimal(b)) => a.get() == b.get(),
417            (Value::Ratio(a), Value::Ratio(b)) => a.get() == b.get(),
418            (Value::Char(a), Value::Char(b)) => a == b,
419            (Value::Str(a), Value::Str(b)) => a.get() == b.get(),
420            (Value::Symbol(a), Value::Symbol(b)) => a.get() == b.get(),
421            (Value::Keyword(a), Value::Keyword(b)) => a.get() == b.get(),
422            // Collection equality.
423            (Value::List(a), Value::List(b)) => a.get() == b.get(),
424            (Value::Vector(a), Value::Vector(b)) => a.get() == b.get(),
425            (Value::Set(a), Value::Set(b)) => sets_equal(a, b),
426            (Value::Queue(a), Value::Queue(b)) => a.get() == b.get(),
427            (Value::Map(a), Value::Map(b)) => maps_equal(a, b),
428            // Sequential cross-type equality: '(1 2) == [1 2].
429            (Value::List(_), Value::Vector(_)) | (Value::Vector(_), Value::List(_)) => {
430                seq_equal(self, other)
431            }
432            // Cons cells: compare element by element.
433            (Value::Cons(_), _) | (_, Value::Cons(_)) => seq_equal(self, other),
434            // Pointer equality for functions.
435            (Value::Fn(a), Value::Fn(b)) => std::ptr::eq(a.get() as *const _, b.get() as *const _),
436            (Value::Macro(a), Value::Macro(b)) => {
437                std::ptr::eq(a.get() as *const _, b.get() as *const _)
438            }
439            (Value::NativeFunction(a), Value::NativeFunction(b)) => {
440                std::ptr::eq(a.get() as *const _, b.get() as *const _)
441            }
442            // Pointer equality for protocol/multimethod objects.
443            (Value::Protocol(a), Value::Protocol(b)) => {
444                std::ptr::eq(a.get() as *const _, b.get() as *const _)
445            }
446            (Value::ProtocolFn(a), Value::ProtocolFn(b)) => {
447                std::ptr::eq(a.get() as *const _, b.get() as *const _)
448            }
449            (Value::MultiFn(a), Value::MultiFn(b)) => {
450                std::ptr::eq(a.get() as *const _, b.get() as *const _)
451            }
452            // Pointer equality for concurrency primitives.
453            (Value::Volatile(a), Value::Volatile(b)) => {
454                std::ptr::eq(a.get() as *const _, b.get() as *const _)
455            }
456            (Value::Delay(a), Value::Delay(b)) => {
457                std::ptr::eq(a.get() as *const _, b.get() as *const _)
458            }
459            (Value::Promise(a), Value::Promise(b)) => {
460                std::ptr::eq(a.get() as *const _, b.get() as *const _)
461            }
462            (Value::Future(a), Value::Future(b)) => {
463                std::ptr::eq(a.get() as *const _, b.get() as *const _)
464            }
465            (Value::Agent(a), Value::Agent(b)) => {
466                std::ptr::eq(a.get() as *const _, b.get() as *const _)
467            }
468            (Value::Atom(a), Value::Atom(b)) => {
469                std::ptr::eq(a.get() as *const _, b.get() as *const _)
470            }
471            (Value::Var(a), Value::Var(b)) => {
472                std::ptr::eq(a.get() as *const _, b.get() as *const _)
473            }
474            (Value::Namespace(a), Value::Namespace(b)) => {
475                std::ptr::eq(a.get() as *const _, b.get() as *const _)
476            }
477            // UUID equality: same u128 value.
478            (Value::Uuid(a), Value::Uuid(b)) => a == b,
479            // Regex pattern equality: compare source string (matches Clojure JVM behavior
480            // where two patterns are equal iff their source strings are equal).
481            (Value::Pattern(a), Value::Pattern(b)) => a.get().as_str() == b.get().as_str(),
482            // NativeObject equality: pointer identity.
483            (Value::NativeObject(a), Value::NativeObject(b)) => {
484                std::ptr::eq(a.get() as *const _, b.get() as *const _)
485            }
486            // Resource equality: pointer identity.
487            (Value::Resource(a), Value::Resource(b)) => Arc::ptr_eq(&a.0, &b.0),
488            // Record equality: same tag and same fields.
489            (Value::TypeInstance(a), Value::TypeInstance(b)) => {
490                a.get().type_tag == b.get().type_tag && maps_equal(&a.get().fields, &b.get().fields)
491            }
492            (Value::Error(a), Value::Error(b)) => {
493                std::ptr::eq(a.get() as *const _, b.get() as *const _)
494            }
495            // SharedAtom: pointer identity (same Arc → same atom).
496            (Value::SharedAtom(a), Value::SharedAtom(b)) => Arc::ptr_eq(a, b),
497            // ByteBlob: pointer identity (same Arc → same underlying buffer).
498            (Value::ByteBlob(a), Value::ByteBlob(b)) => Arc::ptr_eq(a, b),
499            _ => false,
500        }
501    }
502}
503
504fn maps_equal(a: &MapValue, b: &MapValue) -> bool {
505    if a.count() != b.count() {
506        return false;
507    }
508    let mut equal = true;
509    a.for_each(|k, v| {
510        if equal {
511            match b.get(k) {
512                Some(bv) if &bv == v => {}
513                _ => equal = false,
514            }
515        }
516    });
517    equal
518}
519
520fn sets_equal(a: &SetValue, b: &SetValue) -> bool {
521    if a.count() != b.count() {
522        return false;
523    }
524    for k in a.iter() {
525        if !b.contains(k) {
526            return false;
527        }
528    }
529    true
530}
531
532fn seq_equal(a: &Value, b: &Value) -> bool {
533    let a_items = value_to_seq_vec(a);
534    let b_items = value_to_seq_vec(b);
535    a_items.len() == b_items.len() && a_items.iter().zip(b_items.iter()).all(|(x, y)| x == y)
536}
537
538fn value_to_seq_vec(v: &Value) -> Vec<Value> {
539    // Iteratively unwrap lazy seqs.
540    let mut v = v.clone();
541    while let Value::LazySeq(ls) = &v {
542        v = ls.get().realize();
543    }
544    match &v {
545        Value::List(l) => l.get().iter().cloned().collect(),
546        Value::Vector(v) => v.get().iter().cloned().collect(),
547        Value::LazySeq(_) => unreachable!("unwrapped above"),
548        Value::Cons(c) => {
549            let mut result = vec![c.get().head.clone()];
550            let mut tail = c.get().tail.clone();
551            loop {
552                match tail {
553                    Value::Nil => break,
554                    Value::List(l) => {
555                        result.extend(l.get().iter().cloned());
556                        break;
557                    }
558                    Value::Cons(next_c) => {
559                        result.push(next_c.get().head.clone());
560                        tail = next_c.get().tail.clone();
561                    }
562                    Value::LazySeq(ls) => {
563                        tail = ls.get().realize();
564                    }
565                    _ => break,
566                }
567            }
568            result
569        }
570        _ => vec![],
571    }
572}
573
574// ── Hashing ───────────────────────────────────────────────────────────────────
575
576impl ClojureHash for Value {
577    fn clojure_hash(&self) -> u32 {
578        match self {
579            Value::WithMeta(inner, _) => inner.clojure_hash(),
580            Value::Reduced(inner) => inner.clojure_hash(),
581            Value::Nil => 0,
582            Value::Bool(b) => {
583                if *b { 1231 } else { 1237 } // Java Boolean.hashCode
584            }
585            Value::Long(n) => hash_i64(*n),
586            Value::Double(f) => {
587                // Whole-number doubles hash like their Long equivalent.
588                if f.fract() == 0.0
589                    && f.is_finite()
590                    && let Some(n) = num_traits::ToPrimitive::to_i64(f)
591                {
592                    return hash_i64(n);
593                }
594                hash_i64(f.to_bits() as i64)
595            }
596            Value::BigInt(n) => {
597                // Hash like Long if it fits.
598                if let Some(l) = n.get().to_i64() {
599                    return hash_i64(l);
600                }
601                // Otherwise hash the decimal string (simplified).
602                hash_string(&n.get().to_string())
603            }
604            Value::Char(c) => *c as u32,
605            Value::Str(s) => hash_string(s.get()),
606            Value::Pattern(r) => hash_string(r.get().as_str()),
607            Value::Matcher(m) => hash_string(m.get().pattern.get().as_str()),
608            Value::Keyword(k) => hash_string(&k.get().to_string()),
609            Value::Symbol(s) => hash_string(&s.get().to_string()),
610            Value::Uuid(u) => hash_u128(*u),
611            Value::NativeObject(obj) => {
612                let ptr = obj.get() as *const _ as usize;
613                hash_i64(ptr as i64)
614            }
615            Value::Resource(r) => {
616                let ptr = Arc::as_ptr(&r.0) as *const () as usize;
617                hash_i64(ptr as i64)
618            }
619            Value::List(l) => {
620                let mut h: u32 = 1;
621                for v in l.get().iter() {
622                    h = hash_combine_ordered(h, v.clojure_hash());
623                }
624                h
625            }
626            Value::Vector(v) => {
627                let mut h: u32 = 1;
628                for item in v.get().iter() {
629                    h = hash_combine_ordered(h, item.clojure_hash());
630                }
631                h
632            }
633            Value::Map(m) => {
634                let mut h: u32 = 0;
635                m.for_each(|k, v| {
636                    h = hash_combine_unordered(
637                        h,
638                        hash_combine_ordered(k.clojure_hash(), v.clojure_hash()),
639                    );
640                });
641                h
642            }
643            Value::Set(s) => {
644                let mut h: u32 = 0;
645                for k in s.iter() {
646                    h = hash_combine_unordered(h, k.clojure_hash());
647                }
648                h
649            }
650            Value::TransientMap(m) => m.get().clojure_hash(),
651            Value::TransientSet(s) => s.get().clojure_hash(),
652            Value::TransientVector(v) => v.get().clojure_hash(),
653
654            // Arrays
655            Value::BooleanArray(a) => {
656                let mut h: u32 = 0;
657                for b in a.get().lock().unwrap().iter() {
658                    h = hash_combine_ordered(h, if *b { 1231 } else { 1237 })
659                }
660                h
661            }
662            Value::ByteArray(a) => {
663                let mut h: u32 = 0;
664                for b in a.get().lock().unwrap().iter() {
665                    h = hash_combine_ordered(h, *b as u32)
666                }
667                h
668            }
669            Value::ShortArray(a) => {
670                let mut h: u32 = 0;
671                for item in a.get().lock().unwrap().iter() {
672                    h = hash_combine_ordered(h, *item as u32)
673                }
674                h
675            }
676            Value::IntArray(a) => {
677                let mut h: u32 = 0;
678                for item in a.get().lock().unwrap().iter() {
679                    h = hash_combine_ordered(h, *item as u32)
680                }
681                h
682            }
683            Value::CharArray(a) => {
684                let mut h: u32 = 0;
685                for item in a.get().lock().unwrap().iter() {
686                    h = hash_combine_ordered(h, *item as u32)
687                }
688                h
689            }
690            Value::LongArray(a) => {
691                let mut h: u32 = 0;
692                for item in a.get().lock().unwrap().iter() {
693                    let v = *item;
694                    h = hash_combine_ordered(h, hash_i64(v));
695                }
696                h
697            }
698            Value::FloatArray(a) => {
699                let mut h: u32 = 0;
700                for item in a.get().lock().unwrap().iter() {
701                    let f = *item;
702                    h = hash_combine_ordered(
703                        h,
704                        if f.fract() == 0.0
705                            && f.is_finite()
706                            && let Some(n) = ToPrimitive::to_i64(item)
707                        {
708                            hash_i64(n)
709                        } else {
710                            hash_i64(f.to_bits() as i64)
711                        },
712                    )
713                }
714                h
715            }
716            Value::DoubleArray(a) => {
717                let mut h: u32 = 0;
718                for item in a.get().lock().unwrap().iter() {
719                    let f = *item;
720                    h = hash_combine_ordered(
721                        h,
722                        if f.fract() == 0.0
723                            && f.is_finite()
724                            && let Some(n) = ToPrimitive::to_i64(item)
725                        {
726                            hash_i64(n)
727                        } else {
728                            hash_i64(f.to_bits() as i64)
729                        },
730                    )
731                }
732                h
733            }
734            Value::ObjectArray(a) => {
735                let mut h: u32 = 0;
736                for item in a.get().0.lock().unwrap().iter() {
737                    h = hash_combine_ordered(h, item.clojure_hash())
738                }
739                h
740            }
741
742            Value::SharedAtom(a) => Arc::as_ptr(a) as u32,
743            Value::ByteBlob(b) => {
744                let mut h: u32 = 0;
745                for byte in b.iter() {
746                    h = hash_combine_ordered(h, hash_i64(*byte as i64));
747                }
748                h
749            }
750
751            // For non-data types, use pointer identity.
752            Value::Fn(f) => f.get() as *const _ as u32,
753            Value::BoundFn(f) => f.get() as *const _ as u32,
754            Value::NativeFunction(f) => f.get() as *const _ as u32,
755            Value::Var(v) => v.get() as *const _ as u32,
756            Value::Atom(a) => a.get() as *const _ as u32,
757            Value::Namespace(n) => n.get() as *const _ as u32,
758            Value::Queue(q) => {
759                let mut h: u32 = 1;
760                for v in q.get().iter() {
761                    h = hash_combine_ordered(h, v.clojure_hash());
762                }
763                h
764            }
765            Value::Macro(f) => f.get() as *const _ as u32,
766            Value::BigDecimal(d) => hash_string(&d.get().to_string()),
767            Value::Ratio(r) => hash_string(&r.get().to_string()),
768            Value::LazySeq(ls) => ls.get().realize().clojure_hash(),
769            Value::Protocol(p) => p.get() as *const _ as u32,
770            Value::ProtocolFn(pf) => pf.get() as *const _ as u32,
771            Value::MultiFn(mf) => mf.get() as *const _ as u32,
772            Value::Cons(_) => {
773                // Hash like an ordered sequence.
774                let mut h: u32 = 1;
775                for v in value_to_seq_vec(self) {
776                    h = hash_combine_ordered(h, v.clojure_hash());
777                }
778                h
779            }
780            // Pointer identity for concurrency primitives.
781            Value::Volatile(v) => v.get() as *const _ as u32,
782            Value::Delay(d) => d.get() as *const _ as u32,
783            Value::Promise(p) => p.get() as *const _ as u32,
784            Value::Future(fu) => fu.get() as *const _ as u32,
785            Value::Agent(a) => a.get() as *const _ as u32,
786            // Record hash: combine type tag hash with fields hash.
787            Value::TypeInstance(ti) => {
788                let tag_hash = hash_string(&ti.get().type_tag);
789                let mut fields_hash: u32 = 0;
790                ti.get().fields.for_each(|k, v| {
791                    fields_hash = hash_combine_unordered(
792                        fields_hash,
793                        hash_combine_ordered(k.clojure_hash(), v.clojure_hash()),
794                    );
795                });
796                hash_combine_ordered(tag_hash, fields_hash)
797            }
798            Value::Error(e) => e.get().clojure_hash(),
799        }
800    }
801}
802
803// Implement std::hash::Hash by delegating to ClojureHash.
804impl std::hash::Hash for Value {
805    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
806        self.clojure_hash().hash(state);
807    }
808}
809
810// ── Display / pr-str ──────────────────────────────────────────────────────────
811
812impl fmt::Display for Value {
813    /// Prints in `pr-str` style (readable): strings are quoted, chars use `\` notation.
814    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
815        pr_str(self, f, true)
816    }
817}
818
819/// A wrapper for printing a Value non-readably (for `str`, `println`).
820pub struct PrintValue<'a>(pub &'a Value);
821
822impl fmt::Display for PrintValue<'_> {
823    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
824        pr_str(self.0, f, false)
825    }
826}
827
828/// Print a value.  `readably = true` quotes strings and escapes chars.
829pub fn pr_str(v: &Value, f: &mut fmt::Formatter<'_>, readably: bool) -> fmt::Result {
830    match v {
831        Value::WithMeta(inner, _) => pr_str(inner, f, readably),
832        Value::Reduced(inner) => {
833            write!(f, "#reduced ")?;
834            pr_str(inner, f, readably)
835        }
836        Value::Nil => write!(f, "nil"),
837        Value::Bool(b) => write!(f, "{b}"),
838        Value::Long(n) => write!(f, "{n}"),
839        Value::Double(d) => {
840            if d.is_infinite() {
841                if readably {
842                    if *d > 0.0 {
843                        write!(f, "##Inf")
844                    } else {
845                        write!(f, "##-Inf")
846                    }
847                } else if *d > 0.0 {
848                    write!(f, "Infinity")
849                } else {
850                    write!(f, "-Infinity")
851                }
852            } else if d.is_nan() {
853                if readably {
854                    write!(f, "##NaN")
855                } else {
856                    write!(f, "NaN")
857                }
858            } else if d.fract() == 0.0 && d.abs() < 1e15 {
859                write!(f, "{d:.1}")
860            } else {
861                write!(f, "{d}")
862            }
863        }
864        Value::BigInt(n) => {
865            if readably {
866                write!(f, "{}N", n.get())
867            } else {
868                write!(f, "{}", n.get())
869            }
870        }
871        Value::BigDecimal(d) => {
872            let dec = d.get();
873            let s = format!("{}", dec);
874            // bigdecimal Display omits trailing zeros for zero values (e.g. 0.0 → "0").
875            // Preserve scale: if the value has fractional digits but displays without a dot, add them.
876            if !s.contains('.') && dec.fractional_digit_count() > 0 {
877                let zeros = "0".repeat(dec.fractional_digit_count() as usize);
878                if readably {
879                    write!(f, "{s}.{zeros}M")
880                } else {
881                    write!(f, "{s}.{zeros}")
882                }
883            } else if readably {
884                write!(f, "{s}M")
885            } else {
886                write!(f, "{s}")
887            }
888        }
889        Value::Ratio(r) => write!(f, "{}", r.get()),
890        Value::Uuid(u) => {
891            let uuid = uuid::Uuid::from_u128(*u);
892            if readably {
893                write!(f, "#uuid \"{}\"", uuid)
894            } else {
895                write!(f, "{}", uuid)
896            }
897        }
898        Value::Char(c) => {
899            if readably {
900                match c {
901                    '\n' => write!(f, "\\newline"),
902                    '\t' => write!(f, "\\tab"),
903                    ' ' => write!(f, "\\space"),
904                    '\r' => write!(f, "\\return"),
905                    c => write!(f, "\\{c}"),
906                }
907            } else {
908                write!(f, "{c}")
909            }
910        }
911        Value::Str(s) => {
912            if readably {
913                write!(f, "\"")?;
914                for c in s.get().chars() {
915                    match c {
916                        '"' => write!(f, "\\\"")?,
917                        '\\' => write!(f, "\\\\")?,
918                        '\n' => write!(f, "\\n")?,
919                        '\t' => write!(f, "\\t")?,
920                        '\r' => write!(f, "\\r")?,
921                        c => write!(f, "{c}")?,
922                    }
923                }
924                write!(f, "\"")
925            } else {
926                write!(f, "{}", s.get())
927            }
928        }
929        Value::Pattern(r) => {
930            if readably {
931                write!(f, "#\"")?;
932                write!(f, "{}", r.get().as_str())?;
933                write!(f, "\"")
934            } else {
935                write!(f, "#<{}>", r.get())
936            }
937        }
938        Value::Matcher(_) => write!(f, "#<Matcher>"),
939        Value::Symbol(s) => write!(f, "{}", s.get()),
940        Value::Keyword(k) => write!(f, "{}", k.get()),
941        Value::List(l) => {
942            write!(f, "(")?;
943            let mut first = true;
944            for item in l.get().iter() {
945                if !first {
946                    write!(f, " ")?;
947                }
948                pr_str(item, f, readably)?;
949                first = false;
950            }
951            write!(f, ")")
952        }
953        Value::Vector(v) => {
954            write!(f, "[")?;
955            let mut first = true;
956            for item in v.get().iter() {
957                if !first {
958                    write!(f, " ")?;
959                }
960                pr_str(item, f, readably)?;
961                first = false;
962            }
963            write!(f, "]")
964        }
965        Value::Map(m) => {
966            write!(f, "{{")?;
967            let mut first = true;
968            m.for_each(|k, v| {
969                // Ignore fmt errors inside the closure — limitations of fmt.
970                if !first {
971                    let _ = write!(f, ", ");
972                }
973                let _ = pr_str(k, f, readably);
974                let _ = write!(f, " ");
975                let _ = pr_str(v, f, readably);
976                first = false;
977            });
978            write!(f, "}}")
979        }
980        Value::Set(s) => {
981            write!(f, "#{{")?;
982            let mut first = true;
983            for item in s.iter() {
984                if !first {
985                    write!(f, " ")?;
986                }
987                pr_str(item, f, readably)?;
988                first = false;
989            }
990            write!(f, "}}")
991        }
992        Value::BooleanArray(_)
993        | Value::ByteArray(_)
994        | Value::ShortArray(_)
995        | Value::IntArray(_)
996        | Value::LongArray(_)
997        | Value::CharArray(_)
998        | Value::FloatArray(_)
999        | Value::DoubleArray(_)
1000        | Value::ObjectArray(_) => write!(f, "#[array]"),
1001        Value::Queue(q) => {
1002            // Printed as a list with a type tag.
1003            write!(f, "#queue (")?;
1004            let mut first = true;
1005            for item in q.get().iter() {
1006                if !first {
1007                    write!(f, " ")?;
1008                }
1009                pr_str(item, f, readably)?;
1010                first = false;
1011            }
1012            write!(f, ")")
1013        }
1014        Value::LazySeq(ls) => pr_str(&ls.get().realize(), f, readably),
1015        Value::Cons(c) => {
1016            write!(f, "(")?;
1017            pr_str(&c.get().head, f, readably)?;
1018            let mut tail = c.get().tail.clone();
1019            loop {
1020                match tail {
1021                    Value::Nil => break,
1022                    Value::List(l) => {
1023                        for item in l.get().iter() {
1024                            write!(f, " ")?;
1025                            pr_str(item, f, readably)?;
1026                        }
1027                        break;
1028                    }
1029                    Value::Cons(next_c) => {
1030                        write!(f, " ")?;
1031                        pr_str(&next_c.get().head, f, readably)?;
1032                        tail = next_c.get().tail.clone();
1033                    }
1034                    Value::LazySeq(ls) => {
1035                        tail = ls.get().realize();
1036                    }
1037                    other => {
1038                        write!(f, " . ")?;
1039                        pr_str(&other, f, readably)?;
1040                        break;
1041                    }
1042                }
1043            }
1044            write!(f, ")")
1045        }
1046        Value::NativeFunction(nf) => write!(f, "#<NativeFn {}>", nf.get().name),
1047        Value::BoundFn(_) => write!(f, "#<BoundFn>"),
1048        Value::Fn(fun) => match &fun.get().name {
1049            Some(n) => write!(f, "#<Fn {n}>"),
1050            None => write!(f, "#<Fn>"),
1051        },
1052        Value::Macro(m) => match &m.get().name {
1053            Some(n) => write!(f, "#<Macro {n}>"),
1054            None => write!(f, "#<Macro>"),
1055        },
1056        Value::Var(v) => write!(f, "#'{}/{}", v.get().namespace, v.get().name),
1057        Value::Atom(a) => write!(f, "#<Atom {}>", a.get().deref()),
1058        Value::SharedAtom(a) => {
1059            write!(f, "#<SharedAtom {}>", a.deref_val().type_name())
1060        }
1061        Value::ByteBlob(b) => write!(f, "#<ByteBlob {} bytes>", b.len()),
1062        Value::Namespace(n) => write!(f, "#<Namespace {}>", n.get().name),
1063        Value::Protocol(p) => write!(f, "#<Protocol {}>", p.get().name),
1064        Value::ProtocolFn(pf) => {
1065            write!(
1066                f,
1067                "#<fn {}/{}>",
1068                pf.get().protocol.get().name,
1069                pf.get().method_name
1070            )
1071        }
1072        Value::MultiFn(mf) => write!(f, "#<MultiFn {}>", mf.get().name),
1073        Value::Volatile(_) => write!(f, "#<Volatile>"),
1074        Value::Delay(_) => write!(f, "#<Delay>"),
1075        Value::Promise(_) => write!(f, "#<Promise>"),
1076        Value::Future(_) => write!(f, "#<Future>"),
1077        Value::Agent(_) => write!(f, "#<Agent>"),
1078        Value::TypeInstance(ti) => {
1079            let ti = ti.get();
1080            write!(f, "#{}{{", ti.type_tag)?;
1081            let mut first = true;
1082            ti.fields.for_each(|k, v| {
1083                if !first {
1084                    let _ = write!(f, ", ");
1085                }
1086                let _ = pr_str(k, f, readably);
1087                let _ = write!(f, " ");
1088                let _ = pr_str(v, f, readably);
1089                first = false;
1090            });
1091            write!(f, "}}")
1092        }
1093        Value::NativeObject(obj) => {
1094            write!(f, "#<{} {:?}>", obj.get().type_tag(), obj.get().inner())
1095        }
1096        Value::Resource(r) => {
1097            if r.is_closed() {
1098                write!(f, "#<{} (closed)>", r.resource_type())
1099            } else {
1100                write!(f, "#<{}>", r.resource_type())
1101            }
1102        }
1103        Value::TransientMap(_) => write!(f, "#<TransientMap>"),
1104        Value::TransientSet(_) => write!(f, "#<TransientSet>"),
1105        Value::TransientVector(_) => write!(f, "#<TransientVector>"),
1106        Value::Error(e) => {
1107            write!(f, "#error ")?;
1108            let map = e.get().to_map().map_err(|_| fmt::Error {})?;
1109            pr_str(&map, f, readably)
1110        }
1111    }
1112}
1113
1114// ── Keyword-argument rest normalization ──────────────────────────────────────
1115
1116impl Value {
1117    /// Normalize a variadic rest sequence into the value a *map-shaped* rest
1118    /// pattern (`[& {:keys [a b]}]`) destructures against.
1119    ///
1120    /// This is Clojure's `seq-to-map-for-destructuring`, and every execution
1121    /// tier must agree on it — the tree-walker calls it from `bind_fn_params`,
1122    /// the IR interpreter and the compiled tiers reach it through
1123    /// `KnownFn::KwargsMap` / `rt_kwargs_map`.  A divergence here is issue
1124    /// #368.
1125    ///
1126    /// - Zero or one argument: the lone value *is* the map, returned verbatim.
1127    ///   `(f {:a 1})` therefore keeps the caller's map identity — a sorted map
1128    ///   stays sorted, metadata stays attached — and `(f)` / `(f nil)` bind
1129    ///   `nil`, which reads like an empty map for every `:keys` lookup.
1130    /// - Otherwise the arguments are alternating key/value pairs, optionally
1131    ///   followed by a trailing map whose entries win over the pairs before it
1132    ///   (Clojure 1.11's keyword-argument calling convention).
1133    ///
1134    /// An odd argument count with no trailing map is a caller error, reported
1135    /// the way Clojure reports it rather than dropping the dangling key.
1136    pub fn from_kwargs_rest(mut entries: Vec<Value>) -> Result<Value, ValueError> {
1137        if entries.len() < 2 {
1138            return Ok(entries.pop().unwrap_or(Value::Nil));
1139        }
1140
1141        // A trailing map is only a trailing map when what precedes it pairs up
1142        // evenly; `(f :a {:x 1})` passes a map as `:a`'s *value*.  Match through
1143        // any `WithMeta` wrapper — a map carrying metadata is still a map.
1144        let trailing = match entries.last().map(Value::unwrap_meta) {
1145            Some(Value::Map(_)) if !entries.len().is_multiple_of(2) => entries.pop(),
1146            _ => None,
1147        };
1148
1149        if !entries.len().is_multiple_of(2) {
1150            let key = entries.last().expect("odd length implies a last entry");
1151            return Err(ValueError::Other(format!(
1152                "No value supplied for key: {}",
1153                PrintValue(key)
1154            )));
1155        }
1156
1157        let mut result = MapValue::from_flat_entries(entries);
1158        if let Some(Value::Map(map)) = trailing.as_ref().map(Value::unwrap_meta) {
1159            for (key, value) in map.iter() {
1160                result = result.assoc(key.clone(), value.clone());
1161            }
1162        }
1163        Ok(Value::Map(result))
1164    }
1165}
1166
1167// ── Metadata helpers ─────────────────────────────────────────────────────────
1168
1169impl Value {
1170    /// Strip any `WithMeta` wrapper, returning the underlying value.
1171    pub fn unwrap_meta(&self) -> &Value {
1172        match self {
1173            Value::WithMeta(inner, _) => inner.unwrap_meta(),
1174            other => other,
1175        }
1176    }
1177
1178    /// Return metadata if present, or `None`.
1179    pub fn get_meta(&self) -> Option<&Value> {
1180        match self {
1181            Value::WithMeta(_, meta) => Some(meta),
1182            _ => None,
1183        }
1184    }
1185
1186    /// Return a new value with metadata attached.
1187    pub fn with_meta(self, meta: Value) -> Value {
1188        match self {
1189            Value::WithMeta(inner, _) => Value::WithMeta(inner, Box::new(meta)),
1190            other => Value::WithMeta(Box::new(other), Box::new(meta)),
1191        }
1192    }
1193}
1194
1195// ── type_name helper ──────────────────────────────────────────────────────────
1196
1197impl Value {
1198    /// A human-readable type name for error messages.
1199    pub fn type_name(&self) -> &'static str {
1200        match self {
1201            Value::WithMeta(inner, _) => inner.type_name(),
1202            Value::Reduced(_) => "reduced",
1203            Value::Nil => "nil",
1204            Value::Bool(_) => "boolean",
1205            Value::Long(_) => "long",
1206            Value::Double(_) => "double",
1207            Value::BigInt(_) => "bigint",
1208            Value::BigDecimal(_) => "bigdecimal",
1209            Value::Ratio(_) => "ratio",
1210            Value::Char(_) => "char",
1211            Value::Str(_) => "string",
1212            Value::Pattern(_) => "pattern",
1213            Value::Matcher(_) => "matcher",
1214            Value::Symbol(_) => "symbol",
1215            Value::Keyword(_) => "keyword",
1216            Value::Uuid(_) => "uuid",
1217            Value::List(_) => "list",
1218            Value::Vector(_) => "vector",
1219            Value::Map(_) => "map",
1220            Value::Set(_) => "set",
1221            Value::Queue(_) => "queue",
1222            Value::NativeFunction(_)
1223            | Value::Fn(_)
1224            | Value::BoundFn(_)
1225            | Value::Macro(_)
1226            | Value::ProtocolFn(_)
1227            | Value::MultiFn(_) => "fn",
1228            Value::Var(_) => "var",
1229            Value::Atom(_) => "atom",
1230            Value::SharedAtom(_) => "shared-atom",
1231            Value::ByteBlob(_) => "byte-blob",
1232            Value::Namespace(_) => "namespace",
1233            Value::LazySeq(_) => "lazyseq",
1234            Value::Cons(_) => "cons",
1235            Value::Protocol(_) => "protocol",
1236            Value::Volatile(_) => "volatile",
1237            Value::Delay(_) => "delay",
1238            Value::Promise(_) => "promise",
1239            Value::Future(_) => "future",
1240            Value::Agent(_) => "agent",
1241            Value::TypeInstance(_) => "record",
1242            Value::NativeObject(_) => "native-object",
1243            Value::BooleanArray(_) => "boolean-array",
1244            Value::ByteArray(_) => "byte-array",
1245            Value::ShortArray(_) => "short-array",
1246            Value::IntArray(_) => "int-array",
1247            Value::LongArray(_) => "long-array",
1248            Value::FloatArray(_) => "float-array",
1249            Value::DoubleArray(_) => "double-array",
1250            Value::CharArray(_) => "char-array",
1251            Value::ObjectArray(_) => "object-array",
1252            Value::Resource(r) => r.resource_type(),
1253            Value::TransientMap(_) => "transient-map",
1254            Value::TransientSet(_) => "transient-set",
1255            Value::TransientVector(_) => "transient-vector",
1256            Value::Error(_) => "error",
1257        }
1258    }
1259
1260    /// Convenience: wrap a `&str` in `Value::Str`.
1261    pub fn string(s: impl Into<String>) -> Self {
1262        Value::Str(GcPtr::new(s.into()))
1263    }
1264
1265    /// Convenience: build a `[key val]` map entry (a tagged 2-element vector).
1266    pub fn map_entry(key: Value, val: Value) -> Self {
1267        Value::Vector(GcPtr::new(PersistentVector::map_entry(key, val)))
1268    }
1269
1270    /// True only for map entries (`[k v]` pairs from seq'ing a map, `find`,
1271    /// or the `map-entry` constructor) — not for plain 2-element vectors.
1272    pub fn is_map_entry(&self) -> bool {
1273        matches!(self.unwrap_meta(), Value::Vector(v) if v.get().is_map_entry())
1274    }
1275
1276    /// Convenience: wrap a `Symbol`.
1277    pub fn symbol(s: Symbol) -> Self {
1278        Value::Symbol(GcPtr::new(s))
1279    }
1280
1281    /// Convenience: wrap a `Keyword`.
1282    pub fn keyword(k: Keyword) -> Self {
1283        Value::Keyword(GcPtr::new(k))
1284    }
1285
1286    /// True for sequential collections (list, vector, lazy seq, cons).
1287    pub fn is_sequential(&self) -> bool {
1288        matches!(
1289            self,
1290            Value::List(_) | Value::Vector(_) | Value::LazySeq(_) | Value::Cons(_)
1291        )
1292    }
1293
1294    /// True for any collection.
1295    pub fn is_coll(&self) -> bool {
1296        self.unwrap_meta().is_coll_inner()
1297    }
1298
1299    fn is_coll_inner(&self) -> bool {
1300        matches!(
1301            self,
1302            Value::List(_)
1303                | Value::Vector(_)
1304                | Value::Map(_)
1305                | Value::Set(_)
1306                | Value::Queue(_)
1307                | Value::LazySeq(_)
1308                | Value::Cons(_)
1309        )
1310    }
1311}
1312
1313impl cljrs_gc::Trace for Value {
1314    fn trace(&self, visitor: &mut cljrs_gc::MarkVisitor) {
1315        use cljrs_gc::GcVisitor as _;
1316        match self {
1317            Value::Reduced(inner) => inner.trace(visitor),
1318            Value::WithMeta(inner, meta) => {
1319                inner.trace(visitor);
1320                meta.trace(visitor);
1321            }
1322            Value::Nil
1323            | Value::Bool(_)
1324            | Value::Long(_)
1325            | Value::Double(_)
1326            | Value::Char(_)
1327            | Value::Uuid(_) => {}
1328            Value::BigInt(p) => visitor.visit(p),
1329            Value::BigDecimal(p) => visitor.visit(p),
1330            Value::Ratio(p) => visitor.visit(p),
1331            Value::Str(p) => visitor.visit(p),
1332            Value::Pattern(p) => visitor.visit(p),
1333            Value::Matcher(m) => visitor.visit(m),
1334            Value::Symbol(p) => visitor.visit(p),
1335            Value::Keyword(p) => visitor.visit(p),
1336            Value::List(p) => visitor.visit(p),
1337            Value::Vector(p) => visitor.visit(p),
1338            Value::Map(m) => m.trace(visitor),
1339            Value::Set(s) => s.trace(visitor),
1340            Value::Queue(p) => visitor.visit(p),
1341            Value::NativeFunction(p) => visitor.visit(p),
1342            Value::BoundFn(p) => visitor.visit(p),
1343            Value::Fn(p) | Value::Macro(p) => visitor.visit(p),
1344            Value::Var(p) => visitor.visit(p),
1345            Value::Atom(p) => visitor.visit(p),
1346            Value::Namespace(p) => visitor.visit(p),
1347            Value::LazySeq(p) => visitor.visit(p),
1348            Value::Cons(p) => visitor.visit(p),
1349            Value::Protocol(p) => visitor.visit(p),
1350            Value::ProtocolFn(p) => visitor.visit(p),
1351            Value::MultiFn(p) => visitor.visit(p),
1352            Value::Volatile(p) => visitor.visit(p),
1353            Value::Delay(p) => visitor.visit(p),
1354            Value::Promise(p) => visitor.visit(p),
1355            Value::Future(p) => visitor.visit(p),
1356            Value::Agent(p) => visitor.visit(p),
1357            Value::TypeInstance(p) => visitor.visit(p),
1358            Value::ObjectArray(p) => visitor.visit(p),
1359            // Primitive arrays have no child Values, but their boxes live on
1360            // the GC heap and must themselves be marked.
1361            Value::BooleanArray(p) => visitor.visit(p),
1362            Value::ByteArray(p) => visitor.visit(p),
1363            Value::ShortArray(p) => visitor.visit(p),
1364            Value::IntArray(p) => visitor.visit(p),
1365            Value::LongArray(p) => visitor.visit(p),
1366            Value::FloatArray(p) => visitor.visit(p),
1367            Value::DoubleArray(p) => visitor.visit(p),
1368            Value::CharArray(p) => visitor.visit(p),
1369            Value::NativeObject(p) => visitor.visit(p),
1370            // Resource, SharedAtom, and ByteBlob are Arc-ref-counted outside the
1371            // GC heap — nothing to trace through the GC visitor.
1372            Value::Resource(_) | Value::SharedAtom(_) | Value::ByteBlob(_) => {}
1373            Value::TransientMap(m) => visitor.visit(m),
1374            Value::TransientVector(p) => visitor.visit(p),
1375            Value::TransientSet(m) => visitor.visit(m),
1376            Value::Error(e) => visitor.visit(e),
1377        }
1378    }
1379}
1380
1381impl cljrs_gc::Trace for MapValue {
1382    fn trace(&self, visitor: &mut cljrs_gc::MarkVisitor) {
1383        use cljrs_gc::GcVisitor as _;
1384        match self {
1385            MapValue::Array(p) => visitor.visit(p),
1386            MapValue::Hash(p) => visitor.visit(p),
1387            MapValue::Sorted(p) => visitor.visit(p),
1388        }
1389    }
1390}
1391
1392// ── TypeInstance ──────────────────────────────────────────────────────────────
1393
1394/// A record or reify instance.  `type_tag` identifies the concrete type;
1395/// `fields` holds the key/value pairs (keyword → value).
1396#[derive(Clone, Debug)]
1397pub struct TypeInstance {
1398    pub type_tag: Arc<str>,
1399    pub fields: MapValue,
1400    /// Mutable `deftype` fields (`^:unsynchronized-mutable` /
1401    /// `^:volatile-mutable`), held in an interior-mutable cell — an `Atom` over
1402    /// a keyword→value map — so `set!` can update them in place. `None` for
1403    /// `defrecord`, `reify`, and immutable `deftype`s. Instances are `!Send`,
1404    /// so one shared cell needs no stronger volatility than an `Atom`.
1405    pub mutable: Option<GcPtr<crate::types::Atom>>,
1406}
1407
1408impl cljrs_gc::Trace for TypeInstance {
1409    fn trace(&self, visitor: &mut cljrs_gc::MarkVisitor) {
1410        use cljrs_gc::GcVisitor as _;
1411        self.fields.trace(visitor);
1412        if let Some(m) = &self.mutable {
1413            visitor.visit(m);
1414        }
1415    }
1416}
1417
1418#[allow(clippy::items_after_test_module)]
1419#[cfg(test)]
1420mod tests {
1421    use super::*;
1422
1423    fn kw(s: &str) -> Value {
1424        Value::keyword(Keyword::simple(s))
1425    }
1426    #[allow(dead_code)]
1427    fn sym(s: &str) -> Value {
1428        Value::symbol(Symbol::simple(s))
1429    }
1430    fn int(n: i64) -> Value {
1431        Value::Long(n)
1432    }
1433    fn s(v: &str) -> Value {
1434        Value::string(v)
1435    }
1436
1437    // ── Equality ──────────────────────────────────────────────────────────────
1438
1439    #[test]
1440    fn test_nil_eq() {
1441        assert_eq!(Value::Nil, Value::Nil);
1442        assert_ne!(Value::Nil, int(0));
1443    }
1444
1445    #[test]
1446    fn test_numeric_cross_type() {
1447        let big1 = Value::BigInt(GcPtr::new(BigInt::from(1i64)));
1448        assert_eq!(int(1), big1.clone());
1449        assert_eq!(big1, int(1));
1450        // 1.0 == 1
1451        assert_eq!(Value::Double(1.0), int(1));
1452        assert_eq!(int(1), Value::Double(1.0));
1453        // 1.5 != 1
1454        assert_ne!(Value::Double(1.5), int(1));
1455    }
1456
1457    #[test]
1458    fn test_nan_not_equal_to_itself() {
1459        let nan = Value::Double(f64::NAN);
1460        assert_ne!(nan, nan.clone());
1461    }
1462
1463    #[test]
1464    fn test_string_equality() {
1465        assert_eq!(s("hello"), s("hello"));
1466        assert_ne!(s("hello"), s("world"));
1467    }
1468
1469    #[test]
1470    fn test_list_vector_seq_equality() {
1471        let list = Value::List(GcPtr::new(PersistentList::from_iter([int(1), int(2)])));
1472        let vec = Value::Vector(GcPtr::new(PersistentVector::from_iter([int(1), int(2)])));
1473        // Clojure: (= '(1 2) [1 2]) => true
1474        assert_eq!(list, vec);
1475    }
1476
1477    #[test]
1478    fn test_map_equality_order_independent() {
1479        let mut a = MapValue::empty();
1480        a = a.assoc(kw("a"), int(1));
1481        a = a.assoc(kw("b"), int(2));
1482
1483        let mut b = MapValue::empty();
1484        b = b.assoc(kw("b"), int(2));
1485        b = b.assoc(kw("a"), int(1));
1486
1487        assert_eq!(Value::Map(a), Value::Map(b));
1488    }
1489
1490    // ── Hashing ───────────────────────────────────────────────────────────────
1491
1492    #[test]
1493    fn test_hash_consistency() {
1494        let big1 = Value::BigInt(GcPtr::new(BigInt::from(1i64)));
1495        assert_eq!(int(1).clojure_hash(), big1.clojure_hash());
1496    }
1497
1498    #[test]
1499    fn test_hash_whole_double() {
1500        // (= 1 1.0) → true, so (hash 1) == (hash 1.0)
1501        assert_eq!(int(1).clojure_hash(), Value::Double(1.0).clojure_hash());
1502    }
1503
1504    // ── Display ───────────────────────────────────────────────────────────────
1505
1506    #[test]
1507    fn test_pr_str_nil() {
1508        assert_eq!(Value::Nil.to_string(), "nil");
1509    }
1510
1511    #[test]
1512    fn test_pr_str_string() {
1513        assert_eq!(s("hello").to_string(), "\"hello\"");
1514        assert_eq!(s("a\"b").to_string(), "\"a\\\"b\"");
1515    }
1516
1517    #[test]
1518    fn test_pr_str_char() {
1519        assert_eq!(Value::Char('a').to_string(), "\\a");
1520        assert_eq!(Value::Char('\n').to_string(), "\\newline");
1521    }
1522
1523    #[test]
1524    fn test_pr_str_list() {
1525        let l = Value::List(GcPtr::new(PersistentList::from_iter([int(1), int(2)])));
1526        assert_eq!(l.to_string(), "(1 2)");
1527    }
1528
1529    #[test]
1530    fn test_pr_str_vector() {
1531        let v = Value::Vector(GcPtr::new(PersistentVector::from_iter([int(1), int(2)])));
1532        assert_eq!(v.to_string(), "[1 2]");
1533    }
1534
1535    #[test]
1536    #[allow(clippy::approx_constant)]
1537    fn test_pr_str_double() {
1538        assert_eq!(Value::Double(1.0).to_string(), "1.0");
1539        assert_eq!(Value::Double(3.14).to_string(), "3.14");
1540        assert_eq!(Value::Double(f64::INFINITY).to_string(), "##Inf");
1541        assert_eq!(Value::Double(f64::NEG_INFINITY).to_string(), "##-Inf");
1542        assert_eq!(Value::Double(f64::NAN).to_string(), "##NaN");
1543    }
1544
1545    // ── Keyword-argument rest normalization ──────────────────────────────────
1546
1547    fn kwargs(entries: Vec<Value>) -> Value {
1548        Value::from_kwargs_rest(entries).expect("well-formed kwargs")
1549    }
1550
1551    fn map_of(entries: Vec<Value>) -> Value {
1552        Value::Map(MapValue::from_flat_entries(entries))
1553    }
1554
1555    #[test]
1556    fn kwargs_rest_empty_and_lone_values_pass_through() {
1557        // `(f)` and `(f nil)` both bind nil, as in Clojure — `:as` sees the
1558        // rest value itself, so an empty map here would be observable.
1559        assert_eq!(kwargs(vec![]), Value::Nil);
1560        assert_eq!(kwargs(vec![Value::Nil]), Value::Nil);
1561        // A lone argument is the map verbatim, whatever it is: no rebuild, so
1562        // map identity (and with it sortedness and metadata) survives, and a
1563        // non-map is handed on for `get` to return nil against.
1564        assert_eq!(kwargs(vec![kw("a")]), kw("a"));
1565        let sorted = Value::Map(MapValue::Sorted(GcPtr::new(SortedMap::from_pairs(vec![
1566            (kw("b"), int(1)),
1567            (kw("a"), int(2)),
1568        ]))));
1569        assert!(matches!(
1570            kwargs(vec![sorted.clone()]),
1571            Value::Map(MapValue::Sorted(_))
1572        ));
1573        let with_meta = map_of(vec![kw("a"), int(1)]).with_meta(map_of(vec![kw("t"), int(1)]));
1574        assert_eq!(kwargs(vec![with_meta.clone()]), with_meta);
1575    }
1576
1577    #[test]
1578    fn kwargs_rest_pairs_build_a_map() {
1579        assert_eq!(
1580            kwargs(vec![kw("a"), int(1), kw("b"), int(2)]),
1581            map_of(vec![kw("a"), int(1), kw("b"), int(2)])
1582        );
1583        // Duplicate keys: last wins, as for a map literal built by assoc.
1584        assert_eq!(
1585            kwargs(vec![kw("a"), int(1), kw("a"), int(2)]),
1586            map_of(vec![kw("a"), int(2)])
1587        );
1588    }
1589
1590    #[test]
1591    fn kwargs_rest_trailing_map_merges_and_wins() {
1592        // `(f :a 1 {:b 2})` — the trailing map's entries join the pairs...
1593        assert_eq!(
1594            kwargs(vec![kw("a"), int(1), map_of(vec![kw("b"), int(2)])]),
1595            map_of(vec![kw("a"), int(1), kw("b"), int(2)])
1596        );
1597        // ...and beat them on a clash.
1598        assert_eq!(
1599            kwargs(vec![kw("a"), int(1), map_of(vec![kw("a"), int(9)])]),
1600            map_of(vec![kw("a"), int(9)])
1601        );
1602        // A map carrying metadata is still a trailing map: `with_meta` wraps
1603        // rather than annotates, so matching the raw `Value` would miss it.
1604        let meta_map = map_of(vec![kw("b"), int(2)]).with_meta(map_of(vec![kw("t"), int(1)]));
1605        assert_eq!(
1606            kwargs(vec![kw("a"), int(1), meta_map]),
1607            map_of(vec![kw("a"), int(1), kw("b"), int(2)])
1608        );
1609    }
1610
1611    #[test]
1612    fn kwargs_rest_map_in_value_position_is_not_a_trailing_map() {
1613        // Even arity: the map is `:a`'s value, not a trailing map to merge.
1614        let inner = map_of(vec![kw("x"), int(1)]);
1615        assert_eq!(
1616            kwargs(vec![kw("a"), inner.clone()]),
1617            map_of(vec![kw("a"), inner])
1618        );
1619    }
1620
1621    #[test]
1622    fn kwargs_rest_dangling_key_is_an_error() {
1623        // Clojure's message, and an error rather than the silently dropped
1624        // argument a bare `chunks(2)` would produce.
1625        let err = Value::from_kwargs_rest(vec![kw("a"), int(1), kw("b")])
1626            .expect_err("odd arity with no trailing map");
1627        assert_eq!(err.to_string(), "No value supplied for key: :b");
1628    }
1629}
1630
1631// Ord impl for Value
1632
1633impl PartialOrd for Value {
1634    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1635        Some(self.cmp(other))
1636    }
1637}
1638
1639impl Ord for Value {
1640    fn cmp(&self, other: &Self) -> Ordering {
1641        // Strip metadata for comparison.
1642        let a = self.unwrap_meta();
1643        let b = other.unwrap_meta();
1644        if !std::ptr::eq(a, self) || !std::ptr::eq(b, other) {
1645            return a.cmp(b);
1646        }
1647        // Same-type fast paths first, then cross-type numeric, then type-discriminant fallback.
1648        match (self, other) {
1649            // ── Nil ──
1650            (Value::Nil, Value::Nil) => Ordering::Equal,
1651
1652            // ── Booleans ──
1653            (Value::Bool(a), Value::Bool(b)) => a.cmp(b),
1654
1655            // ── Numerics (same type) ──
1656            (Value::Long(a), Value::Long(b)) => a.cmp(b),
1657            (Value::Double(a), Value::Double(b)) => total_cmp_f64(*a, *b),
1658            (Value::BigInt(a), Value::BigInt(b)) => a.get().cmp(b.get()),
1659            (Value::BigDecimal(a), Value::BigDecimal(b)) => {
1660                // BigDecimal doesn't impl Ord; compare via PartialOrd then string fallback.
1661                a.get()
1662                    .partial_cmp(b.get())
1663                    .unwrap_or_else(|| a.get().to_string().cmp(&b.get().to_string()))
1664            }
1665            (Value::Ratio(a), Value::Ratio(b)) => a.get().cmp(b.get()),
1666
1667            // ── Cross-type numerics (promote to common type) ──
1668            (Value::Long(a), Value::Double(b)) => total_cmp_f64(*a as f64, *b),
1669            (Value::Double(a), Value::Long(b)) => total_cmp_f64(*a, *b as f64),
1670            (Value::Long(a), Value::BigInt(b)) => BigInt::from(*a).cmp(b.get()),
1671            (Value::BigInt(a), Value::Long(b)) => a.get().cmp(&BigInt::from(*b)),
1672            (Value::Long(a), Value::Ratio(b)) => {
1673                num_rational::Ratio::from(BigInt::from(*a)).cmp(b.get())
1674            }
1675            (Value::Ratio(a), Value::Long(b)) => {
1676                a.get().cmp(&num_rational::Ratio::from(BigInt::from(*b)))
1677            }
1678            (Value::BigInt(a), Value::Ratio(b)) => {
1679                num_rational::Ratio::from(a.get().clone()).cmp(b.get())
1680            }
1681            (Value::Ratio(a), Value::BigInt(b)) => {
1682                a.get().cmp(&num_rational::Ratio::from(b.get().clone()))
1683            }
1684            (Value::Double(a), Value::BigInt(b)) => {
1685                total_cmp_f64(*a, b.get().to_f64().unwrap_or(f64::MAX))
1686            }
1687            (Value::BigInt(a), Value::Double(b)) => {
1688                total_cmp_f64(a.get().to_f64().unwrap_or(f64::MAX), *b)
1689            }
1690            (Value::Double(a), Value::Ratio(b)) => {
1691                total_cmp_f64(*a, b.get().to_f64().unwrap_or(f64::MAX))
1692            }
1693            (Value::Ratio(a), Value::Double(b)) => {
1694                total_cmp_f64(a.get().to_f64().unwrap_or(f64::MAX), *b)
1695            }
1696            (Value::Long(a), Value::BigDecimal(b)) => {
1697                let ad = bigdecimal::BigDecimal::from(*a);
1698                ad.partial_cmp(b.get())
1699                    .unwrap_or_else(|| ad.to_string().cmp(&b.get().to_string()))
1700            }
1701            (Value::BigDecimal(a), Value::Long(b)) => {
1702                let bd = bigdecimal::BigDecimal::from(*b);
1703                a.get()
1704                    .partial_cmp(&bd)
1705                    .unwrap_or_else(|| a.get().to_string().cmp(&bd.to_string()))
1706            }
1707            (Value::Double(a), Value::BigDecimal(b)) => {
1708                match bigdecimal::BigDecimal::try_from(*a) {
1709                    Ok(ad) => ad
1710                        .partial_cmp(b.get())
1711                        .unwrap_or_else(|| ad.to_string().cmp(&b.get().to_string())),
1712                    Err(_) => {
1713                        // NaN or infinity
1714                        if a.is_nan() {
1715                            Ordering::Greater
1716                        } else if *a < 0.0 {
1717                            Ordering::Less
1718                        } else {
1719                            Ordering::Greater
1720                        }
1721                    }
1722                }
1723            }
1724            (Value::BigDecimal(a), Value::Double(b)) => {
1725                match bigdecimal::BigDecimal::try_from(*b) {
1726                    Ok(bd) => a
1727                        .get()
1728                        .partial_cmp(&bd)
1729                        .unwrap_or_else(|| a.get().to_string().cmp(&bd.to_string())),
1730                    Err(_) => {
1731                        if b.is_nan() {
1732                            Ordering::Less
1733                        } else if *b < 0.0 {
1734                            Ordering::Greater
1735                        } else {
1736                            Ordering::Less
1737                        }
1738                    }
1739                }
1740            }
1741            (Value::BigInt(a), Value::BigDecimal(b)) => {
1742                let ad = bigdecimal::BigDecimal::from(a.get().clone());
1743                ad.partial_cmp(b.get())
1744                    .unwrap_or_else(|| ad.to_string().cmp(&b.get().to_string()))
1745            }
1746            (Value::BigDecimal(a), Value::BigInt(b)) => {
1747                let bd = bigdecimal::BigDecimal::from(b.get().clone());
1748                a.get()
1749                    .partial_cmp(&bd)
1750                    .unwrap_or_else(|| a.get().to_string().cmp(&bd.to_string()))
1751            }
1752            (Value::Ratio(a), Value::BigDecimal(b)) => {
1753                let af = a.get().to_f64().unwrap_or(f64::MAX);
1754                match bigdecimal::BigDecimal::try_from(af) {
1755                    Ok(ad) => ad
1756                        .partial_cmp(b.get())
1757                        .unwrap_or_else(|| ad.to_string().cmp(&b.get().to_string())),
1758                    Err(_) => Ordering::Greater,
1759                }
1760            }
1761            (Value::BigDecimal(a), Value::Ratio(b)) => {
1762                let bf = b.get().to_f64().unwrap_or(f64::MAX);
1763                match bigdecimal::BigDecimal::try_from(bf) {
1764                    Ok(bd) => a
1765                        .get()
1766                        .partial_cmp(&bd)
1767                        .unwrap_or_else(|| a.get().to_string().cmp(&bd.to_string())),
1768                    Err(_) => Ordering::Less,
1769                }
1770            }
1771
1772            // ── Characters ──
1773            (Value::Char(a), Value::Char(b)) => a.cmp(b),
1774
1775            // ── Strings ──
1776            (Value::Str(a), Value::Str(b)) => a.get().cmp(b.get()),
1777
1778            // ── Symbols ──
1779            (Value::Symbol(a), Value::Symbol(b)) => cmp_ns_name(
1780                &a.get().namespace,
1781                &a.get().name,
1782                &b.get().namespace,
1783                &b.get().name,
1784            ),
1785
1786            // ── Keywords ──
1787            (Value::Keyword(a), Value::Keyword(b)) => cmp_ns_name(
1788                &a.get().namespace,
1789                &a.get().name,
1790                &b.get().namespace,
1791                &b.get().name,
1792            ),
1793
1794            // ── Sequential collections: element-by-element ──
1795            (Value::Vector(a), Value::Vector(b)) => iter_cmp(a.get().iter(), b.get().iter()),
1796            (Value::List(a), Value::List(b)) => iter_cmp(a.get().iter(), b.get().iter()),
1797
1798            // ── Sets: compare by size, then elements ──
1799            (Value::Set(a), Value::Set(b)) => a.count().cmp(&b.count()),
1800
1801            // ── Maps: compare by size ──
1802            (Value::Map(a), Value::Map(b)) => a.count().cmp(&b.count()),
1803
1804            // ── Different types: order by type discriminant for a consistent total order ──
1805            _ => type_discriminant(self).cmp(&type_discriminant(other)),
1806        }
1807    }
1808}
1809
1810/// Compare two iterators of Values element-by-element.
1811fn iter_cmp<'a>(
1812    mut a: impl Iterator<Item = &'a Value>,
1813    mut b: impl Iterator<Item = &'a Value>,
1814) -> Ordering {
1815    loop {
1816        match (a.next(), b.next()) {
1817            (None, None) => return Ordering::Equal,
1818            (None, Some(_)) => return Ordering::Less,
1819            (Some(_), None) => return Ordering::Greater,
1820            (Some(x), Some(y)) => {
1821                let c = x.cmp(y);
1822                if c != Ordering::Equal {
1823                    return c;
1824                }
1825            }
1826        }
1827    }
1828}
1829
1830/// Total ordering for f64: NaN sorts after everything else, otherwise use IEEE total_order.
1831fn total_cmp_f64(a: f64, b: f64) -> Ordering {
1832    a.total_cmp(&b)
1833}
1834
1835/// Compare namespace-qualified names: namespace first (None < Some), then name.
1836fn cmp_ns_name(
1837    ns_a: &Option<Arc<str>>,
1838    name_a: &Arc<str>,
1839    ns_b: &Option<Arc<str>>,
1840    name_b: &Arc<str>,
1841) -> Ordering {
1842    match (ns_a, ns_b) {
1843        (None, None) => name_a.cmp(name_b),
1844        (None, Some(_)) => Ordering::Less,
1845        (Some(_), None) => Ordering::Greater,
1846        (Some(a), Some(b)) => a.cmp(b).then_with(|| name_a.cmp(name_b)),
1847    }
1848}
1849
1850/// Assign a stable integer to each Value variant for cross-type ordering.
1851fn type_discriminant(v: &Value) -> u8 {
1852    match v {
1853        Value::WithMeta(inner, _) => type_discriminant(inner),
1854        Value::Reduced(inner) => type_discriminant(inner),
1855        Value::Nil => 0,
1856        Value::Bool(_) => 1,
1857        Value::Long(_)
1858        | Value::Double(_)
1859        | Value::BigInt(_)
1860        | Value::BigDecimal(_)
1861        | Value::Ratio(_) => 2,
1862        Value::Char(_) => 3,
1863        Value::Str(_) => 4,
1864        Value::Symbol(_) => 5,
1865        Value::Keyword(_) => 6,
1866        Value::List(_) => 7,
1867        Value::Vector(_) => 8,
1868        Value::Map(_) => 9,
1869        Value::Set(_) => 10,
1870        Value::Queue(_) => 11,
1871        Value::LazySeq(_) => 12,
1872        Value::Cons(_) => 13,
1873        Value::NativeFunction(_) => 14,
1874        Value::BoundFn(_) => 14,
1875        Value::Fn(_) => 15,
1876        Value::Macro(_) => 16,
1877        Value::Var(_) => 17,
1878        Value::Atom(_) => 18,
1879        Value::SharedAtom(_) => 46,
1880        Value::ByteBlob(_) => 47,
1881        Value::Namespace(_) => 19,
1882        Value::Protocol(_) => 20,
1883        Value::ProtocolFn(_) => 21,
1884        Value::MultiFn(_) => 22,
1885        Value::Volatile(_) => 23,
1886        Value::Delay(_) => 24,
1887        Value::Promise(_) => 25,
1888        Value::Future(_) => 26,
1889        Value::Agent(_) => 27,
1890        Value::TypeInstance(_) => 28,
1891        Value::BooleanArray(_) => 29,
1892        Value::ByteArray(_) => 30,
1893        Value::ShortArray(_) => 31,
1894        Value::IntArray(_) => 32,
1895        Value::LongArray(_) => 33,
1896        Value::CharArray(_) => 34,
1897        Value::FloatArray(_) => 35,
1898        Value::DoubleArray(_) => 36,
1899        Value::ObjectArray(_) => 37,
1900        Value::Uuid(_) => 38,
1901        Value::NativeObject(_) => 43,
1902        Value::Resource(_) => 39,
1903        Value::TransientMap(_) => 40,
1904        Value::TransientSet(_) => 41,
1905        Value::TransientVector(_) => 42,
1906        Value::Pattern(_) => 43,
1907        Value::Matcher(_) => 44,
1908        Value::Error(_) => 45,
1909    }
1910}