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