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