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