Skip to main content

bock_interp/
value.rs

1//! Runtime value representation for the Bock interpreter.
2//!
3//! Every Bock type maps to a [`Value`] variant. Collections that require
4//! ordering ([`BTreeMap`], [`BTreeSet`]) are supported via [`OrdF64`], a
5//! total-order wrapper for `f64`.
6
7use std::collections::{BTreeMap, BTreeSet};
8use std::fmt;
9use std::hash::{Hash, Hasher};
10use std::sync::atomic::{AtomicU64, Ordering as AtomicOrdering};
11use std::sync::{Arc, Mutex};
12
13use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
14use tokio::sync::Mutex as AsyncMutex;
15use tokio::task::JoinHandle;
16
17use crate::error::RuntimeError;
18
19// ─── ChannelHandle ───────────────────────────────────────────────────────────
20
21/// Shared state for an unbounded MPSC channel of [`Value`]s.
22///
23/// The `Channel[T]` runtime type holds both a sender and a receiver. Both
24/// ends of the channel share a single `Arc<ChannelHandle>`, so cloning or
25/// passing a channel around does not duplicate the underlying queue.
26///
27/// `Channel.new()` returns a pair of clones of the same handle so that
28/// `send` and `recv` both operate on the same underlying mpsc.
29#[derive(Debug)]
30pub struct ChannelHandle {
31    /// The sending end; clones share the same underlying producer.
32    pub sender: UnboundedSender<Value>,
33    /// The receiving end behind an async mutex so a single consumer at a time
34    /// can `.recv().await`.
35    pub receiver: AsyncMutex<UnboundedReceiver<Value>>,
36}
37
38impl ChannelHandle {
39    /// Create a new unbounded channel handle.
40    #[must_use]
41    pub fn new() -> Arc<Self> {
42        let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
43        Arc::new(ChannelHandle {
44            sender: tx,
45            receiver: AsyncMutex::new(rx),
46        })
47    }
48}
49
50// ─── OrdF64 ───────────────────────────────────────────────────────────────────
51
52/// A total-order wrapper for `f64`.
53///
54/// Uses [`f64::total_cmp`] (stable since Rust 1.62) which defines:
55/// `-NaN < -Inf < … < -0.0 < +0.0 < … < +Inf < +NaN`.
56///
57/// This is necessary because [`BTreeMap`] and [`BTreeSet`] require [`Ord`],
58/// but raw `f64` only implements [`PartialOrd`].
59#[derive(Debug, Clone, Copy)]
60pub struct OrdF64(pub f64);
61
62impl PartialEq for OrdF64 {
63    fn eq(&self, other: &Self) -> bool {
64        self.0.total_cmp(&other.0) == std::cmp::Ordering::Equal
65    }
66}
67
68impl Eq for OrdF64 {}
69
70impl PartialOrd for OrdF64 {
71    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
72        Some(self.cmp(other))
73    }
74}
75
76impl Ord for OrdF64 {
77    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
78        self.0.total_cmp(&other.0)
79    }
80}
81
82impl Hash for OrdF64 {
83    fn hash<H: Hasher>(&self, state: &mut H) {
84        // Consistent with total_cmp equality: equal values share the same bit pattern.
85        self.0.to_bits().hash(state);
86    }
87}
88
89impl fmt::Display for OrdF64 {
90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        write!(f, "{}", self.0)
92    }
93}
94
95impl From<f64> for OrdF64 {
96    fn from(v: f64) -> Self {
97        OrdF64(v)
98    }
99}
100
101// ─── BockString ──────────────────────────────────────────────────────────────
102
103/// An Bock string value.
104#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
105pub struct BockString(String);
106
107impl BockString {
108    /// Create an [`BockString`] from any string-like value.
109    #[must_use]
110    pub fn new(s: impl Into<String>) -> Self {
111        BockString(s.into())
112    }
113
114    /// View as a `str` slice.
115    #[must_use]
116    pub fn as_str(&self) -> &str {
117        &self.0
118    }
119}
120
121impl fmt::Display for BockString {
122    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123        write!(f, "{}", self.0)
124    }
125}
126
127impl From<String> for BockString {
128    fn from(s: String) -> Self {
129        BockString(s)
130    }
131}
132
133impl From<&str> for BockString {
134    fn from(s: &str) -> Self {
135        BockString(s.to_owned())
136    }
137}
138
139// ─── RecordValue ─────────────────────────────────────────────────────────────
140
141/// A record (struct) value: a named type with named fields.
142#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
143pub struct RecordValue {
144    /// The record's type name.
145    pub type_name: String,
146    /// Fields stored in sorted key order for deterministic comparison.
147    pub fields: BTreeMap<String, Value>,
148}
149
150// ─── EnumValue ───────────────────────────────────────────────────────────────
151
152/// An enum (sum type) value: a named variant with an optional payload.
153#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
154pub struct EnumValue {
155    /// The enum type name.
156    pub type_name: String,
157    /// The variant name.
158    pub variant: String,
159    /// Optional payload for variants that carry data.
160    pub payload: Option<Box<Value>>,
161}
162
163// ─── FnValue ─────────────────────────────────────────────────────────────────
164
165/// Global unique-ID counter for function instances.
166static NEXT_FN_ID: AtomicU64 = AtomicU64::new(1);
167
168/// A function value.
169///
170/// Functions are equal only to themselves (compared by [`id`](FnValue::id)).
171/// Attempting to **order** function values — e.g. by using one as a map key or
172/// set element — is a **runtime error** and will panic with a clear message.
173#[derive(Debug, Clone)]
174pub struct FnValue {
175    /// Unique identifier assigned at creation.
176    pub id: u64,
177    /// Optional human-readable name, for display.
178    pub name: Option<String>,
179}
180
181impl FnValue {
182    /// Create an anonymous function value with a fresh unique identity.
183    #[must_use]
184    pub fn new_anonymous() -> Self {
185        FnValue {
186            id: NEXT_FN_ID.fetch_add(1, AtomicOrdering::Relaxed),
187            name: None,
188        }
189    }
190
191    /// Create a named function value with a fresh unique identity.
192    #[must_use]
193    pub fn new_named(name: impl Into<String>) -> Self {
194        FnValue {
195            id: NEXT_FN_ID.fetch_add(1, AtomicOrdering::Relaxed),
196            name: Some(name.into()),
197        }
198    }
199}
200
201impl PartialEq for FnValue {
202    /// Functions are equal iff they share the same identity.
203    fn eq(&self, other: &Self) -> bool {
204        self.id == other.id
205    }
206}
207
208impl Eq for FnValue {}
209
210impl Hash for FnValue {
211    fn hash<H: Hasher>(&self, state: &mut H) {
212        self.id.hash(state);
213    }
214}
215
216impl fmt::Display for FnValue {
217    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218        match &self.name {
219            Some(n) => write!(f, "<fn {n}>"),
220            None => write!(f, "<fn #{}>", self.id),
221        }
222    }
223}
224
225// ─── IteratorValue ────────────────────────────────────────────────────────────
226
227/// Global unique-ID counter for iterator instances.
228static NEXT_ITER_ID: AtomicU64 = AtomicU64::new(1);
229
230/// The internal state of a lazy iterator.
231///
232/// Each variant wraps a source iterator (or raw data) and computes values
233/// on demand via [`IteratorKind::next`]. Combinators like `map` and `filter`
234/// require interpreter support to invoke Bock closures — these store the
235/// function value but their `next()` returns a special
236/// [`IteratorNext::NeedsCallback`] signal.
237#[derive(Debug)]
238pub enum IteratorKind {
239    /// Iterate over a list of values.
240    List { items: Vec<Value>, pos: usize },
241    /// Iterate over an integer range.
242    Range {
243        current: i64,
244        end: i64,
245        inclusive: bool,
246        step: i64,
247    },
248    /// Iterate over set elements.
249    Set { items: Vec<Value>, pos: usize },
250    /// Iterate over map entries as (key, value) tuples.
251    MapEntries {
252        items: Vec<(Value, Value)>,
253        pos: usize,
254    },
255    /// Lazy map combinator — requires interpreter callback.
256    Map {
257        source: Arc<Mutex<IteratorKind>>,
258        func: FnValue,
259    },
260    /// Lazy filter combinator — requires interpreter callback.
261    Filter {
262        source: Arc<Mutex<IteratorKind>>,
263        pred: FnValue,
264    },
265    /// Take at most N elements.
266    Take {
267        source: Arc<Mutex<IteratorKind>>,
268        remaining: usize,
269    },
270    /// Skip the first N elements.
271    Skip {
272        source: Arc<Mutex<IteratorKind>>,
273        to_skip: usize,
274        skipped: bool,
275    },
276    /// Attach an index to each element.
277    Enumerate {
278        source: Arc<Mutex<IteratorKind>>,
279        index: usize,
280    },
281    /// Zip two iterators together.
282    Zip {
283        a: Arc<Mutex<IteratorKind>>,
284        b: Arc<Mutex<IteratorKind>>,
285    },
286    /// Chain two iterators sequentially.
287    Chain {
288        a: Arc<Mutex<IteratorKind>>,
289        b: Arc<Mutex<IteratorKind>>,
290        first_done: bool,
291    },
292}
293
294/// Result of calling [`IteratorKind::next`].
295///
296/// Most combinators can compute the next value directly, but `map` and `filter`
297/// need the interpreter to invoke an Bock closure. They return `NeedsCallback`
298/// with the source value and the function to call.
299#[derive(Debug)]
300pub enum IteratorNext {
301    /// A value was produced.
302    Some(Value),
303    /// The iterator is exhausted.
304    Done,
305    /// The combinator needs the interpreter to call `func(value)` and feed the
306    /// result back. Used by `Map`.
307    NeedsMapCallback { value: Value, func: FnValue },
308    /// The combinator needs the interpreter to call `pred(value)` and feed
309    /// back whether to keep this element. Used by `Filter`.
310    NeedsFilterCallback { value: Value, func: FnValue },
311}
312
313impl IteratorKind {
314    /// Advance the iterator and return the next value.
315    ///
316    /// For combinators that need Bock function calls (map, filter), this
317    /// returns [`IteratorNext::NeedsMapCallback`] or
318    /// [`IteratorNext::NeedsFilterCallback`] instead of a plain value.
319    #[allow(clippy::should_implement_trait)]
320    pub fn next(&mut self) -> IteratorNext {
321        match self {
322            IteratorKind::List { items, pos } => {
323                if *pos < items.len() {
324                    let val = items[*pos].clone();
325                    *pos += 1;
326                    IteratorNext::Some(val)
327                } else {
328                    IteratorNext::Done
329                }
330            }
331            IteratorKind::Range {
332                current,
333                end,
334                inclusive,
335                step,
336            } => {
337                let in_bounds = if *step > 0 {
338                    if *inclusive {
339                        *current <= *end
340                    } else {
341                        *current < *end
342                    }
343                } else if *step < 0 {
344                    if *inclusive {
345                        *current >= *end
346                    } else {
347                        *current > *end
348                    }
349                } else {
350                    false // zero step = no progress
351                };
352                if in_bounds {
353                    let val = *current;
354                    *current += *step;
355                    IteratorNext::Some(Value::Int(val))
356                } else {
357                    IteratorNext::Done
358                }
359            }
360            IteratorKind::Set { items, pos } => {
361                if *pos < items.len() {
362                    let val = items[*pos].clone();
363                    *pos += 1;
364                    IteratorNext::Some(val)
365                } else {
366                    IteratorNext::Done
367                }
368            }
369            IteratorKind::MapEntries { items, pos } => {
370                if *pos < items.len() {
371                    let (k, v) = items[*pos].clone();
372                    *pos += 1;
373                    IteratorNext::Some(Value::Tuple(vec![k, v]))
374                } else {
375                    IteratorNext::Done
376                }
377            }
378            IteratorKind::Map { source, func } => {
379                let mut src = source.lock().unwrap();
380                match src.next() {
381                    IteratorNext::Some(val) => IteratorNext::NeedsMapCallback {
382                        value: val,
383                        func: func.clone(),
384                    },
385                    IteratorNext::Done => IteratorNext::Done,
386                    // Propagate upstream callback requests
387                    other => other,
388                }
389            }
390            IteratorKind::Filter { source, pred } => {
391                let mut src = source.lock().unwrap();
392                match src.next() {
393                    IteratorNext::Some(val) => IteratorNext::NeedsFilterCallback {
394                        value: val,
395                        func: pred.clone(),
396                    },
397                    IteratorNext::Done => IteratorNext::Done,
398                    other => other,
399                }
400            }
401            IteratorKind::Take { source, remaining } => {
402                if *remaining == 0 {
403                    return IteratorNext::Done;
404                }
405                *remaining -= 1;
406                source.lock().unwrap().next()
407            }
408            IteratorKind::Skip {
409                source,
410                to_skip,
411                skipped,
412            } => {
413                if !*skipped {
414                    *skipped = true;
415                    let mut src = source.lock().unwrap();
416                    for _ in 0..*to_skip {
417                        match src.next() {
418                            IteratorNext::Done => return IteratorNext::Done,
419                            IteratorNext::Some(_) => {}
420                            other => return other,
421                        }
422                    }
423                }
424                source.lock().unwrap().next()
425            }
426            IteratorKind::Enumerate { source, index } => {
427                let mut src = source.lock().unwrap();
428                match src.next() {
429                    IteratorNext::Some(val) => {
430                        let idx = *index;
431                        *index += 1;
432                        IteratorNext::Some(Value::Tuple(vec![Value::Int(idx as i64), val]))
433                    }
434                    other => other,
435                }
436            }
437            IteratorKind::Zip { a, b } => {
438                let next_a = a.lock().unwrap().next();
439                match next_a {
440                    IteratorNext::Some(va) => {
441                        let next_b = b.lock().unwrap().next();
442                        match next_b {
443                            IteratorNext::Some(vb) => {
444                                IteratorNext::Some(Value::Tuple(vec![va, vb]))
445                            }
446                            IteratorNext::Done => IteratorNext::Done,
447                            other => other,
448                        }
449                    }
450                    IteratorNext::Done => IteratorNext::Done,
451                    other => other,
452                }
453            }
454            IteratorKind::Chain { a, b, first_done } => {
455                if !*first_done {
456                    let result = a.lock().unwrap().next();
457                    match result {
458                        IteratorNext::Done => {
459                            *first_done = true;
460                            b.lock().unwrap().next()
461                        }
462                        other => other,
463                    }
464                } else {
465                    b.lock().unwrap().next()
466                }
467            }
468        }
469    }
470}
471
472/// A lazy iterator value.
473///
474/// Iterators are identity-compared (like functions). Ordering is a runtime error.
475/// Interior mutability via [`Mutex`] allows `next()` to advance the state
476/// through shared references and across tasks.
477#[derive(Debug, Clone)]
478pub struct IteratorValue {
479    /// Unique identity for equality comparison.
480    pub id: u64,
481    /// The iterator state.
482    pub kind: Arc<Mutex<IteratorKind>>,
483}
484
485impl IteratorValue {
486    /// Create a new iterator value wrapping the given kind.
487    #[must_use]
488    pub fn new(kind: IteratorKind) -> Self {
489        IteratorValue {
490            id: NEXT_ITER_ID.fetch_add(1, AtomicOrdering::Relaxed),
491            kind: Arc::new(Mutex::new(kind)),
492        }
493    }
494}
495
496impl PartialEq for IteratorValue {
497    fn eq(&self, other: &Self) -> bool {
498        self.id == other.id
499    }
500}
501
502impl Eq for IteratorValue {}
503
504impl Hash for IteratorValue {
505    fn hash<H: Hasher>(&self, state: &mut H) {
506        self.id.hash(state);
507    }
508}
509
510impl fmt::Display for IteratorValue {
511    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
512        write!(f, "<iterator #{}>", self.id)
513    }
514}
515
516// ─── Value ───────────────────────────────────────────────────────────────────
517
518/// A runtime value in the Bock interpreter.
519///
520/// Every Bock type maps to a variant. Collections requiring total order
521/// ([`Map`](Value::Map), [`Set`](Value::Set)) work because [`Value`] implements
522/// [`Ord`] — with the single exception that ordering [`Function`](Value::Function)
523/// values is a runtime panic.
524#[derive(Debug, Clone)]
525pub enum Value {
526    /// 64-bit signed integer.
527    Int(i64),
528    /// 64-bit float with total ordering.
529    Float(OrdF64),
530    /// Boolean.
531    Bool(bool),
532    /// Unicode string.
533    String(BockString),
534    /// Unicode scalar character.
535    Char(char),
536    /// Unit / void.
537    Void,
538    /// Homogeneous list.
539    List(Vec<Value>),
540    /// Ordered key-value map (keys must not be functions).
541    Map(BTreeMap<Value, Value>),
542    /// Ordered set (elements must not be functions).
543    Set(BTreeSet<Value>),
544    /// Fixed-size heterogeneous tuple.
545    Tuple(Vec<Value>),
546    /// Record (struct) value.
547    Record(RecordValue),
548    /// Enum (sum type) value.
549    Enum(EnumValue),
550    /// Function value — equal only to itself; ordering is a runtime error.
551    Function(FnValue),
552    /// Optional value (`Some(v)` or `None`).
553    Optional(Option<Box<Value>>),
554    /// Result value (`Ok(v)` or `Err(e)`).
555    Result(std::result::Result<Box<Value>, Box<Value>>),
556    /// An integer range with a step (produced by `lo..hi` / `lo..=hi` / `.step()`).
557    Range {
558        start: i64,
559        end: i64,
560        inclusive: bool,
561        step: i64,
562    },
563    /// A lazy iterator value.
564    Iterator(IteratorValue),
565    /// Mutable string builder for efficient concatenation.
566    StringBuilder(Arc<Mutex<String>>),
567    /// A pending async computation.
568    ///
569    /// Created when an `async fn` is called; resolved by `await`.
570    /// The `JoinHandle` lives behind an `Arc<Mutex<Option<...>>>` so the
571    /// Future value can be cloned (handles share the same task) and the
572    /// handle can be `take()`-n on first await.
573    Future(FutureHandle),
574    /// A time duration as signed nanoseconds (±292 year range).
575    Duration(i64),
576    /// A monotonic point in time (per-process).
577    Instant(std::time::Instant),
578    /// An unbounded async channel. `Channel.new()` returns a tuple of two
579    /// clones of the same handle; `send` and `recv` both operate on the
580    /// shared mpsc queue.
581    Channel(Arc<ChannelHandle>),
582}
583
584/// Shared handle to a spawned async task. See [`Value::Future`].
585pub type FutureHandle = Arc<Mutex<Option<JoinHandle<Result<Value, RuntimeError>>>>>;
586
587impl PartialEq for Value {
588    fn eq(&self, other: &Self) -> bool {
589        match (self, other) {
590            (Value::Int(a), Value::Int(b)) => a == b,
591            (Value::Float(a), Value::Float(b)) => a == b,
592            (Value::Bool(a), Value::Bool(b)) => a == b,
593            (Value::String(a), Value::String(b)) => a == b,
594            (Value::Char(a), Value::Char(b)) => a == b,
595            (Value::Void, Value::Void) => true,
596            (Value::List(a), Value::List(b)) => a == b,
597            (Value::Map(a), Value::Map(b)) => a == b,
598            (Value::Set(a), Value::Set(b)) => a == b,
599            (Value::Tuple(a), Value::Tuple(b)) => a == b,
600            (Value::Record(a), Value::Record(b)) => a == b,
601            (Value::Enum(a), Value::Enum(b)) => a == b,
602            (Value::Function(a), Value::Function(b)) => a == b,
603            (Value::Optional(a), Value::Optional(b)) => a == b,
604            (Value::Result(a), Value::Result(b)) => match (a, b) {
605                (Ok(av), Ok(bv)) => av == bv,
606                (Err(ae), Err(be)) => ae == be,
607                _ => false,
608            },
609            (
610                Value::Range {
611                    start: s1,
612                    end: e1,
613                    inclusive: i1,
614                    step: st1,
615                },
616                Value::Range {
617                    start: s2,
618                    end: e2,
619                    inclusive: i2,
620                    step: st2,
621                },
622            ) => s1 == s2 && e1 == e2 && i1 == i2 && st1 == st2,
623            (Value::Iterator(a), Value::Iterator(b)) => a == b,
624            (Value::StringBuilder(a), Value::StringBuilder(b)) => Arc::ptr_eq(a, b),
625            (Value::Future(a), Value::Future(b)) => Arc::ptr_eq(a, b),
626            (Value::Duration(a), Value::Duration(b)) => a == b,
627            (Value::Instant(a), Value::Instant(b)) => a == b,
628            (Value::Channel(a), Value::Channel(b)) => Arc::ptr_eq(a, b),
629            _ => false,
630        }
631    }
632}
633
634impl Eq for Value {}
635
636/// Numeric discriminant used for cross-variant ordering.
637fn variant_ord(v: &Value) -> u8 {
638    match v {
639        Value::Void => 0,
640        Value::Bool(_) => 1,
641        Value::Int(_) => 2,
642        Value::Float(_) => 3,
643        Value::Char(_) => 4,
644        Value::String(_) => 5,
645        Value::Tuple(_) => 6,
646        Value::List(_) => 7,
647        Value::Set(_) => 8,
648        Value::Map(_) => 9,
649        Value::Record(_) => 10,
650        Value::Enum(_) => 11,
651        Value::Optional(_) => 12,
652        Value::Result(_) => 13,
653        Value::Function(_) => 14,
654        Value::Range { .. } => 15,
655        Value::Iterator(_) => 16,
656        Value::StringBuilder(_) => 17,
657        Value::Future(_) => 18,
658        Value::Duration(_) => 19,
659        Value::Instant(_) => 20,
660        Value::Channel(_) => 21,
661    }
662}
663
664impl Ord for Value {
665    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
666        use std::cmp::Ordering;
667
668        match (self, other) {
669            (Value::Void, Value::Void) => Ordering::Equal,
670            (Value::Bool(a), Value::Bool(b)) => a.cmp(b),
671            (Value::Int(a), Value::Int(b)) => a.cmp(b),
672            (Value::Float(a), Value::Float(b)) => a.cmp(b),
673            (Value::Char(a), Value::Char(b)) => a.cmp(b),
674            (Value::String(a), Value::String(b)) => a.cmp(b),
675            (Value::Tuple(a), Value::Tuple(b)) => a.cmp(b),
676            (Value::List(a), Value::List(b)) => a.cmp(b),
677            (Value::Set(a), Value::Set(b)) => a.cmp(b),
678            (Value::Map(a), Value::Map(b)) => a.cmp(b),
679            (Value::Record(a), Value::Record(b)) => a.cmp(b),
680            (Value::Enum(a), Value::Enum(b)) => a.cmp(b),
681            (Value::Optional(a), Value::Optional(b)) => a.cmp(b),
682            (Value::Result(a), Value::Result(b)) => match (a, b) {
683                (Ok(av), Ok(bv)) => av.cmp(bv),
684                (Err(ae), Err(be)) => ae.cmp(be),
685                (Ok(_), Err(_)) => Ordering::Less,
686                (Err(_), Ok(_)) => Ordering::Greater,
687            },
688            (
689                Value::Range {
690                    start: s1,
691                    end: e1,
692                    inclusive: i1,
693                    step: st1,
694                },
695                Value::Range {
696                    start: s2,
697                    end: e2,
698                    inclusive: i2,
699                    step: st2,
700                },
701            ) => (s1, e1, i1, st1).cmp(&(s2, e2, i2, st2)),
702            // SAFETY: Ord requires a total ordering but these types have no meaningful
703            // order. Reaching these arms indicates a program logic error (e.g. using
704            // functions as map keys). We use unreachable!() to signal the invariant.
705            (Value::Function(_), Value::Function(_)) => {
706                unreachable!("function values are not orderable and cannot be used as map keys or set elements")
707            }
708            (Value::Iterator(_), Value::Iterator(_)) => {
709                unreachable!("iterator values are not orderable and cannot be used as map keys or set elements")
710            }
711            (Value::StringBuilder(_), Value::StringBuilder(_)) => {
712                unreachable!("StringBuilder values are not orderable")
713            }
714            (Value::Future(_), Value::Future(_)) => {
715                unreachable!("Future values are not orderable")
716            }
717            (Value::Channel(_), Value::Channel(_)) => {
718                unreachable!("Channel values are not orderable")
719            }
720            (Value::Duration(a), Value::Duration(b)) => a.cmp(b),
721            (Value::Instant(a), Value::Instant(b)) => a.cmp(b),
722            // Different variants: order by discriminant.
723            _ => variant_ord(self).cmp(&variant_ord(other)),
724        }
725    }
726}
727
728impl PartialOrd for Value {
729    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
730        Some(self.cmp(other))
731    }
732}
733
734impl Hash for Value {
735    fn hash<H: Hasher>(&self, state: &mut H) {
736        variant_ord(self).hash(state);
737        match self {
738            Value::Int(v) => v.hash(state),
739            Value::Float(v) => v.hash(state),
740            Value::Bool(v) => v.hash(state),
741            Value::String(v) => v.hash(state),
742            Value::Char(v) => v.hash(state),
743            Value::Void => {}
744            Value::List(v) => v.hash(state),
745            Value::Tuple(v) => v.hash(state),
746            Value::Record(v) => v.hash(state),
747            Value::Enum(v) => v.hash(state),
748            Value::Function(v) => v.hash(state),
749            Value::Optional(v) => v.hash(state),
750            // BTreeSet/BTreeMap iterate in sorted order — hashing is deterministic.
751            Value::Set(v) => {
752                for item in v {
753                    item.hash(state);
754                }
755            }
756            Value::Map(v) => {
757                for (k, val) in v {
758                    k.hash(state);
759                    val.hash(state);
760                }
761            }
762            Value::Result(v) => match v {
763                Ok(inner) => {
764                    0u8.hash(state);
765                    inner.hash(state);
766                }
767                Err(inner) => {
768                    1u8.hash(state);
769                    inner.hash(state);
770                }
771            },
772            Value::Range {
773                start,
774                end,
775                inclusive,
776                step,
777            } => {
778                start.hash(state);
779                end.hash(state);
780                inclusive.hash(state);
781                step.hash(state);
782            }
783            Value::Iterator(v) => v.hash(state),
784            Value::StringBuilder(v) => v.lock().unwrap().hash(state),
785            Value::Future(v) => (Arc::as_ptr(v) as usize).hash(state),
786            Value::Duration(v) => v.hash(state),
787            Value::Instant(v) => v.hash(state),
788            Value::Channel(v) => (Arc::as_ptr(v) as usize).hash(state),
789        }
790    }
791}
792
793impl fmt::Display for Value {
794    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
795        match self {
796            Value::Int(v) => write!(f, "{v}"),
797            Value::Float(v) => write!(f, "{v}"),
798            Value::Bool(true) => write!(f, "true"),
799            Value::Bool(false) => write!(f, "false"),
800            Value::String(v) => write!(f, "{v}"),
801            Value::Char(v) => write!(f, "'{v}'"),
802            Value::Void => write!(f, "void"),
803            Value::List(items) => {
804                write!(f, "[")?;
805                for (i, item) in items.iter().enumerate() {
806                    if i > 0 {
807                        write!(f, ", ")?;
808                    }
809                    write!(f, "{item}")?;
810                }
811                write!(f, "]")
812            }
813            Value::Set(items) => {
814                write!(f, "{{")?;
815                for (i, item) in items.iter().enumerate() {
816                    if i > 0 {
817                        write!(f, ", ")?;
818                    }
819                    write!(f, "{item}")?;
820                }
821                write!(f, "}}")
822            }
823            Value::Map(items) => {
824                write!(f, "{{")?;
825                for (i, (k, v)) in items.iter().enumerate() {
826                    if i > 0 {
827                        write!(f, ", ")?;
828                    }
829                    write!(f, "{k}: {v}")?;
830                }
831                write!(f, "}}")
832            }
833            Value::Tuple(items) => {
834                write!(f, "(")?;
835                for (i, item) in items.iter().enumerate() {
836                    if i > 0 {
837                        write!(f, ", ")?;
838                    }
839                    write!(f, "{item}")?;
840                }
841                write!(f, ")")
842            }
843            Value::Record(r) => {
844                write!(f, "{} {{", r.type_name)?;
845                for (i, (k, v)) in r.fields.iter().enumerate() {
846                    if i > 0 {
847                        write!(f, ", ")?;
848                    }
849                    write!(f, "{k}: {v}")?;
850                }
851                write!(f, "}}")
852            }
853            Value::Enum(e) => {
854                write!(f, "{}.{}", e.type_name, e.variant)?;
855                if let Some(payload) = &e.payload {
856                    write!(f, "({payload})")?;
857                }
858                Ok(())
859            }
860            Value::Function(fn_val) => write!(f, "{fn_val}"),
861            Value::Optional(Some(v)) => write!(f, "Some({v})"),
862            Value::Optional(None) => write!(f, "None"),
863            Value::Result(Ok(v)) => write!(f, "Ok({v})"),
864            Value::Result(Err(e)) => write!(f, "Err({e})"),
865            Value::Range {
866                start,
867                end,
868                inclusive,
869                step,
870            } => {
871                if *step == 1 {
872                    if *inclusive {
873                        write!(f, "{start}..={end}")
874                    } else {
875                        write!(f, "{start}..{end}")
876                    }
877                } else if *inclusive {
878                    write!(f, "{start}..={end} step {step}")
879                } else {
880                    write!(f, "{start}..{end} step {step}")
881                }
882            }
883            Value::Iterator(v) => write!(f, "{v}"),
884            Value::StringBuilder(v) => write!(f, "<StringBuilder len={}>", v.lock().unwrap().len()),
885            Value::Future(_) => write!(f, "<future>"),
886            Value::Duration(nanos) => write!(f, "{}", format_duration(*nanos)),
887            Value::Instant(_) => write!(f, "<instant>"),
888            Value::Channel(_) => write!(f, "<channel>"),
889        }
890    }
891}
892
893/// Format a duration in nanoseconds using the most natural unit.
894fn format_duration(nanos: i64) -> String {
895    if nanos == 0 {
896        return "0s".to_string();
897    }
898    let sign = if nanos < 0 { "-" } else { "" };
899    let abs_nanos = nanos.unsigned_abs();
900    if abs_nanos >= 1_000_000_000 {
901        let secs = abs_nanos as f64 / 1_000_000_000.0;
902        format!("{sign}{secs}s")
903    } else if abs_nanos >= 1_000_000 {
904        let ms = abs_nanos as f64 / 1_000_000.0;
905        format!("{sign}{ms}ms")
906    } else if abs_nanos >= 1_000 {
907        let us = abs_nanos as f64 / 1_000.0;
908        format!("{sign}{us}µs")
909    } else {
910        format!("{sign}{abs_nanos}ns")
911    }
912}
913
914// ─── Tests ────────────────────────────────────────────────────────────────────
915
916#[cfg(test)]
917mod tests {
918    use super::*;
919
920    // ── OrdF64 ────────────────────────────────────────────────────────────────
921
922    #[test]
923    fn ordf64_total_order_neg_zero_vs_pos_zero() {
924        let neg = OrdF64(-0.0_f64);
925        let pos = OrdF64(0.0_f64);
926        assert!(neg < pos, "-0.0 should be less than +0.0 under total order");
927    }
928
929    #[test]
930    fn ordf64_nan_is_ordered() {
931        let nan = OrdF64(f64::NAN);
932        let inf = OrdF64(f64::INFINITY);
933        assert!(inf < nan, "+Inf should be less than +NaN under total order");
934    }
935
936    #[test]
937    fn ordf64_equality_uses_total_cmp() {
938        assert_ne!(OrdF64(-0.0), OrdF64(0.0));
939        assert_eq!(OrdF64(1.0), OrdF64(1.0));
940    }
941
942    // ── BockString ────────────────────────────────────────────────────────────
943
944    #[test]
945    fn bock_string_ord() {
946        let a = BockString::new("apple");
947        let b = BockString::new("banana");
948        assert!(a < b);
949    }
950
951    #[test]
952    fn bock_string_display() {
953        let s = BockString::new("hello");
954        assert_eq!(s.to_string(), "hello");
955    }
956
957    // ── Value equality ────────────────────────────────────────────────────────
958
959    #[test]
960    fn int_equality() {
961        assert_eq!(Value::Int(42), Value::Int(42));
962        assert_ne!(Value::Int(1), Value::Int(2));
963    }
964
965    #[test]
966    fn float_equality() {
967        assert_eq!(Value::Float(OrdF64(1.5)), Value::Float(OrdF64(1.5)));
968        assert_ne!(Value::Float(OrdF64(-0.0)), Value::Float(OrdF64(0.0)));
969    }
970
971    #[test]
972    fn bool_equality() {
973        assert_eq!(Value::Bool(true), Value::Bool(true));
974        assert_ne!(Value::Bool(true), Value::Bool(false));
975    }
976
977    #[test]
978    fn string_equality() {
979        assert_eq!(
980            Value::String(BockString::new("hi")),
981            Value::String(BockString::new("hi"))
982        );
983    }
984
985    #[test]
986    fn void_equality() {
987        assert_eq!(Value::Void, Value::Void);
988    }
989
990    #[test]
991    fn different_variants_not_equal() {
992        assert_ne!(Value::Int(0), Value::Bool(false));
993    }
994
995    // ── Function identity ─────────────────────────────────────────────────────
996
997    #[test]
998    fn fn_equality_by_identity() {
999        let f1 = FnValue::new_named("foo");
1000        let f2 = FnValue::new_named("foo");
1001        assert_eq!(f1, f1.clone());
1002        assert_ne!(f1, f2);
1003    }
1004
1005    #[test]
1006    fn fn_value_equality_by_identity() {
1007        let f1 = FnValue::new_anonymous();
1008        let f2 = FnValue::new_anonymous();
1009        let v1 = Value::Function(f1.clone());
1010        let v1_clone = Value::Function(f1);
1011        let v2 = Value::Function(f2);
1012        assert_eq!(v1, v1_clone);
1013        assert_ne!(v1_clone, v2);
1014    }
1015
1016    #[test]
1017    #[should_panic(expected = "function values are not orderable")]
1018    fn fn_value_ordering_panics() {
1019        let f1 = Value::Function(FnValue::new_anonymous());
1020        let f2 = Value::Function(FnValue::new_anonymous());
1021        let _ = f1.cmp(&f2);
1022    }
1023
1024    // ── Value ordering ────────────────────────────────────────────────────────
1025
1026    #[test]
1027    fn int_ordering() {
1028        assert!(Value::Int(1) < Value::Int(2));
1029        assert!(Value::Int(2) > Value::Int(1));
1030    }
1031
1032    #[test]
1033    fn bool_ordering() {
1034        assert!(Value::Bool(false) < Value::Bool(true));
1035    }
1036
1037    #[test]
1038    fn optional_none_less_than_some() {
1039        assert!(Value::Optional(None) < Value::Optional(Some(Box::new(Value::Int(0)))));
1040    }
1041
1042    #[test]
1043    fn result_ok_less_than_err() {
1044        let ok = Value::Result(Ok(Box::new(Value::Int(0))));
1045        let err = Value::Result(Err(Box::new(Value::Int(0))));
1046        assert!(ok < err);
1047    }
1048
1049    #[test]
1050    fn cross_variant_ordering_by_discriminant() {
1051        // Void (0) < Bool (1) < Int (2)
1052        assert!(Value::Void < Value::Bool(false));
1053        assert!(Value::Bool(false) < Value::Int(0));
1054    }
1055
1056    // ── Value in BTreeMap / BTreeSet ─────────────────────────────────────────
1057
1058    #[test]
1059    fn value_as_btreemap_key() {
1060        let mut map = BTreeMap::new();
1061        map.insert(Value::Int(1), Value::String(BockString::new("one")));
1062        map.insert(Value::Int(2), Value::String(BockString::new("two")));
1063        assert_eq!(
1064            map.get(&Value::Int(1)),
1065            Some(&Value::String(BockString::new("one")))
1066        );
1067    }
1068
1069    #[test]
1070    fn value_as_btreeset_element() {
1071        let mut set = BTreeSet::new();
1072        set.insert(Value::Int(3));
1073        set.insert(Value::Int(1));
1074        set.insert(Value::Int(2));
1075        let sorted: Vec<_> = set.iter().collect();
1076        assert_eq!(sorted[0], &Value::Int(1));
1077        assert_eq!(sorted[2], &Value::Int(3));
1078    }
1079
1080    #[test]
1081    fn float_as_btreeset_element() {
1082        let mut set = BTreeSet::new();
1083        set.insert(Value::Float(OrdF64(3.0)));
1084        set.insert(Value::Float(OrdF64(1.0)));
1085        set.insert(Value::Float(OrdF64(2.0)));
1086        let mut iter = set.iter();
1087        assert_eq!(iter.next(), Some(&Value::Float(OrdF64(1.0))));
1088    }
1089
1090    // ── Display ───────────────────────────────────────────────────────────────
1091
1092    #[test]
1093    fn display_primitives() {
1094        assert_eq!(Value::Int(42).to_string(), "42");
1095        assert_eq!(Value::Float(OrdF64(3.14)).to_string(), "3.14");
1096        assert_eq!(Value::Bool(true).to_string(), "true");
1097        assert_eq!(Value::Bool(false).to_string(), "false");
1098        assert_eq!(Value::String(BockString::new("hi")).to_string(), "hi");
1099        assert_eq!(Value::Char('x').to_string(), "'x'");
1100        assert_eq!(Value::Void.to_string(), "void");
1101    }
1102
1103    #[test]
1104    fn display_list() {
1105        let v = Value::List(vec![Value::Int(1), Value::Int(2), Value::Int(3)]);
1106        assert_eq!(v.to_string(), "[1, 2, 3]");
1107    }
1108
1109    #[test]
1110    fn display_tuple() {
1111        let v = Value::Tuple(vec![Value::Int(1), Value::Bool(true)]);
1112        assert_eq!(v.to_string(), "(1, true)");
1113    }
1114
1115    #[test]
1116    fn display_optional() {
1117        assert_eq!(
1118            Value::Optional(Some(Box::new(Value::Int(5)))).to_string(),
1119            "Some(5)"
1120        );
1121        assert_eq!(Value::Optional(None).to_string(), "None");
1122    }
1123
1124    #[test]
1125    fn display_result() {
1126        assert_eq!(
1127            Value::Result(Ok(Box::new(Value::Int(0)))).to_string(),
1128            "Ok(0)"
1129        );
1130        assert_eq!(
1131            Value::Result(Err(Box::new(Value::String(BockString::new("fail"))))).to_string(),
1132            "Err(fail)"
1133        );
1134    }
1135
1136    #[test]
1137    fn display_enum_without_payload() {
1138        let v = Value::Enum(EnumValue {
1139            type_name: "Color".into(),
1140            variant: "Red".into(),
1141            payload: None,
1142        });
1143        assert_eq!(v.to_string(), "Color.Red");
1144    }
1145
1146    #[test]
1147    fn display_enum_with_payload() {
1148        let v = Value::Enum(EnumValue {
1149            type_name: "Shape".into(),
1150            variant: "Circle".into(),
1151            payload: Some(Box::new(Value::Float(OrdF64(1.0)))),
1152        });
1153        assert_eq!(v.to_string(), "Shape.Circle(1)");
1154    }
1155
1156    #[test]
1157    fn display_record() {
1158        let mut fields = BTreeMap::new();
1159        fields.insert("x".to_string(), Value::Int(1));
1160        fields.insert("y".to_string(), Value::Int(2));
1161        let v = Value::Record(RecordValue {
1162            type_name: "Point".into(),
1163            fields,
1164        });
1165        assert_eq!(v.to_string(), "Point {x: 1, y: 2}");
1166    }
1167
1168    #[test]
1169    fn display_function_named() {
1170        let v = Value::Function(FnValue::new_named("add"));
1171        assert_eq!(v.to_string(), "<fn add>");
1172    }
1173
1174    // ── Clone ─────────────────────────────────────────────────────────────────
1175
1176    #[test]
1177    fn value_clone() {
1178        let original = Value::List(vec![Value::Int(1), Value::Bool(true)]);
1179        let cloned = original.clone();
1180        assert_eq!(original, cloned);
1181    }
1182
1183    // ── Nested values ─────────────────────────────────────────────────────────
1184
1185    #[test]
1186    fn nested_map_value() {
1187        let inner = Value::Map(BTreeMap::from([(Value::Int(1), Value::Bool(true))]));
1188        let outer = Value::List(vec![inner]);
1189        assert_eq!(outer.to_string(), "[{1: true}]");
1190    }
1191}