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