1use 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#[derive(Debug)]
30pub struct ChannelHandle {
31 pub sender: UnboundedSender<Value>,
33 pub receiver: AsyncMutex<UnboundedReceiver<Value>>,
36}
37
38impl ChannelHandle {
39 #[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#[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 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#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
105pub struct BockString(String);
106
107impl BockString {
108 #[must_use]
110 pub fn new(s: impl Into<String>) -> Self {
111 BockString(s.into())
112 }
113
114 #[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#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
143pub struct RecordValue {
144 pub type_name: String,
146 pub fields: BTreeMap<String, Value>,
148}
149
150#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
154pub struct EnumValue {
155 pub type_name: String,
157 pub variant: String,
159 pub payload: Option<Box<Value>>,
161}
162
163static NEXT_FN_ID: AtomicU64 = AtomicU64::new(1);
167
168#[derive(Debug, Clone)]
174pub struct FnValue {
175 pub id: u64,
177 pub name: Option<String>,
179}
180
181impl FnValue {
182 #[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 #[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 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
225static NEXT_ITER_ID: AtomicU64 = AtomicU64::new(1);
229
230#[derive(Debug)]
238pub enum IteratorKind {
239 List { items: Vec<Value>, pos: usize },
241 Range {
243 current: i64,
244 end: i64,
245 inclusive: bool,
246 step: i64,
247 },
248 Set { items: Vec<Value>, pos: usize },
250 MapEntries {
252 items: Vec<(Value, Value)>,
253 pos: usize,
254 },
255 Map {
257 source: Arc<Mutex<IteratorKind>>,
258 func: FnValue,
259 },
260 Filter {
262 source: Arc<Mutex<IteratorKind>>,
263 pred: FnValue,
264 },
265 Take {
267 source: Arc<Mutex<IteratorKind>>,
268 remaining: usize,
269 },
270 Skip {
272 source: Arc<Mutex<IteratorKind>>,
273 to_skip: usize,
274 skipped: bool,
275 },
276 Enumerate {
278 source: Arc<Mutex<IteratorKind>>,
279 index: usize,
280 },
281 Zip {
283 a: Arc<Mutex<IteratorKind>>,
284 b: Arc<Mutex<IteratorKind>>,
285 },
286 Chain {
288 a: Arc<Mutex<IteratorKind>>,
289 b: Arc<Mutex<IteratorKind>>,
290 first_done: bool,
291 },
292}
293
294#[derive(Debug)]
300pub enum IteratorNext {
301 Some(Value),
303 Done,
305 NeedsMapCallback { value: Value, func: FnValue },
308 NeedsFilterCallback { value: Value, func: FnValue },
311}
312
313impl IteratorKind {
314 #[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 };
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 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#[derive(Debug, Clone)]
478pub struct IteratorValue {
479 pub id: u64,
481 pub kind: Arc<Mutex<IteratorKind>>,
483}
484
485impl IteratorValue {
486 #[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#[derive(Debug, Clone)]
525pub enum Value {
526 Int(i64),
528 Float(OrdF64),
530 Bool(bool),
532 String(BockString),
534 Char(char),
536 Void,
538 List(Vec<Value>),
540 Map(BTreeMap<Value, Value>),
542 Set(BTreeSet<Value>),
544 Tuple(Vec<Value>),
546 Record(RecordValue),
548 Enum(EnumValue),
550 Function(FnValue),
552 Optional(Option<Box<Value>>),
554 Result(std::result::Result<Box<Value>, Box<Value>>),
556 Range {
558 start: i64,
559 end: i64,
560 inclusive: bool,
561 step: i64,
562 },
563 Iterator(IteratorValue),
565 StringBuilder(Arc<Mutex<String>>),
567 Future(FutureHandle),
574 Duration(i64),
576 Instant(std::time::Instant),
578 Channel(Arc<ChannelHandle>),
582}
583
584pub 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
636fn 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 (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 _ => 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 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
893fn 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#[cfg(test)]
917mod tests {
918 use super::*;
919
920 #[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 #[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 #[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 #[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 #[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 assert!(Value::Void < Value::Bool(false));
1053 assert!(Value::Bool(false) < Value::Int(0));
1054 }
1055
1056 #[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 #[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 #[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 #[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}