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 Value {
588 #[must_use]
598 pub fn ordering(ord: std::cmp::Ordering) -> Self {
599 let variant = match ord {
600 std::cmp::Ordering::Less => "Less",
601 std::cmp::Ordering::Equal => "Equal",
602 std::cmp::Ordering::Greater => "Greater",
603 };
604 Value::Enum(EnumValue {
605 type_name: "Ordering".to_string(),
606 variant: variant.to_string(),
607 payload: None,
608 })
609 }
610}
611
612impl PartialEq for Value {
613 fn eq(&self, other: &Self) -> bool {
614 match (self, other) {
615 (Value::Int(a), Value::Int(b)) => a == b,
616 (Value::Float(a), Value::Float(b)) => a.0 == b.0,
628 (Value::Bool(a), Value::Bool(b)) => a == b,
629 (Value::String(a), Value::String(b)) => a == b,
630 (Value::Char(a), Value::Char(b)) => a == b,
631 (Value::Void, Value::Void) => true,
632 (Value::List(a), Value::List(b)) => a == b,
633 (Value::Map(a), Value::Map(b)) => a == b,
634 (Value::Set(a), Value::Set(b)) => a == b,
635 (Value::Tuple(a), Value::Tuple(b)) => a == b,
636 (Value::Record(a), Value::Record(b)) => a == b,
637 (Value::Enum(a), Value::Enum(b)) => a == b,
638 (Value::Function(a), Value::Function(b)) => a == b,
639 (Value::Optional(a), Value::Optional(b)) => a == b,
640 (Value::Result(a), Value::Result(b)) => match (a, b) {
641 (Ok(av), Ok(bv)) => av == bv,
642 (Err(ae), Err(be)) => ae == be,
643 _ => false,
644 },
645 (
646 Value::Range {
647 start: s1,
648 end: e1,
649 inclusive: i1,
650 step: st1,
651 },
652 Value::Range {
653 start: s2,
654 end: e2,
655 inclusive: i2,
656 step: st2,
657 },
658 ) => s1 == s2 && e1 == e2 && i1 == i2 && st1 == st2,
659 (Value::Iterator(a), Value::Iterator(b)) => a == b,
660 (Value::StringBuilder(a), Value::StringBuilder(b)) => Arc::ptr_eq(a, b),
661 (Value::Future(a), Value::Future(b)) => Arc::ptr_eq(a, b),
662 (Value::Duration(a), Value::Duration(b)) => a == b,
663 (Value::Instant(a), Value::Instant(b)) => a == b,
664 (Value::Channel(a), Value::Channel(b)) => Arc::ptr_eq(a, b),
665 _ => false,
666 }
667 }
668}
669
670impl Eq for Value {}
671
672fn variant_ord(v: &Value) -> u8 {
674 match v {
675 Value::Void => 0,
676 Value::Bool(_) => 1,
677 Value::Int(_) => 2,
678 Value::Float(_) => 3,
679 Value::Char(_) => 4,
680 Value::String(_) => 5,
681 Value::Tuple(_) => 6,
682 Value::List(_) => 7,
683 Value::Set(_) => 8,
684 Value::Map(_) => 9,
685 Value::Record(_) => 10,
686 Value::Enum(_) => 11,
687 Value::Optional(_) => 12,
688 Value::Result(_) => 13,
689 Value::Function(_) => 14,
690 Value::Range { .. } => 15,
691 Value::Iterator(_) => 16,
692 Value::StringBuilder(_) => 17,
693 Value::Future(_) => 18,
694 Value::Duration(_) => 19,
695 Value::Instant(_) => 20,
696 Value::Channel(_) => 21,
697 }
698}
699
700impl Ord for Value {
701 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
702 use std::cmp::Ordering;
703
704 match (self, other) {
705 (Value::Void, Value::Void) => Ordering::Equal,
706 (Value::Bool(a), Value::Bool(b)) => a.cmp(b),
707 (Value::Int(a), Value::Int(b)) => a.cmp(b),
708 (Value::Float(a), Value::Float(b)) => a.cmp(b),
709 (Value::Char(a), Value::Char(b)) => a.cmp(b),
710 (Value::String(a), Value::String(b)) => a.cmp(b),
711 (Value::Tuple(a), Value::Tuple(b)) => a.cmp(b),
712 (Value::List(a), Value::List(b)) => a.cmp(b),
713 (Value::Set(a), Value::Set(b)) => a.cmp(b),
714 (Value::Map(a), Value::Map(b)) => a.cmp(b),
715 (Value::Record(a), Value::Record(b)) => a.cmp(b),
716 (Value::Enum(a), Value::Enum(b)) => a.cmp(b),
717 (Value::Optional(a), Value::Optional(b)) => a.cmp(b),
718 (Value::Result(a), Value::Result(b)) => match (a, b) {
719 (Ok(av), Ok(bv)) => av.cmp(bv),
720 (Err(ae), Err(be)) => ae.cmp(be),
721 (Ok(_), Err(_)) => Ordering::Less,
722 (Err(_), Ok(_)) => Ordering::Greater,
723 },
724 (
725 Value::Range {
726 start: s1,
727 end: e1,
728 inclusive: i1,
729 step: st1,
730 },
731 Value::Range {
732 start: s2,
733 end: e2,
734 inclusive: i2,
735 step: st2,
736 },
737 ) => (s1, e1, i1, st1).cmp(&(s2, e2, i2, st2)),
738 (Value::Function(_), Value::Function(_)) => {
742 unreachable!("function values are not orderable and cannot be used as map keys or set elements")
743 }
744 (Value::Iterator(_), Value::Iterator(_)) => {
745 unreachable!("iterator values are not orderable and cannot be used as map keys or set elements")
746 }
747 (Value::StringBuilder(_), Value::StringBuilder(_)) => {
748 unreachable!("StringBuilder values are not orderable")
749 }
750 (Value::Future(_), Value::Future(_)) => {
751 unreachable!("Future values are not orderable")
752 }
753 (Value::Channel(_), Value::Channel(_)) => {
754 unreachable!("Channel values are not orderable")
755 }
756 (Value::Duration(a), Value::Duration(b)) => a.cmp(b),
757 (Value::Instant(a), Value::Instant(b)) => a.cmp(b),
758 _ => variant_ord(self).cmp(&variant_ord(other)),
760 }
761 }
762}
763
764impl PartialOrd for Value {
765 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
766 Some(self.cmp(other))
767 }
768}
769
770impl Hash for Value {
771 fn hash<H: Hasher>(&self, state: &mut H) {
772 variant_ord(self).hash(state);
773 match self {
774 Value::Int(v) => v.hash(state),
775 Value::Float(v) => v.hash(state),
776 Value::Bool(v) => v.hash(state),
777 Value::String(v) => v.hash(state),
778 Value::Char(v) => v.hash(state),
779 Value::Void => {}
780 Value::List(v) => v.hash(state),
781 Value::Tuple(v) => v.hash(state),
782 Value::Record(v) => v.hash(state),
783 Value::Enum(v) => v.hash(state),
784 Value::Function(v) => v.hash(state),
785 Value::Optional(v) => v.hash(state),
786 Value::Set(v) => {
788 for item in v {
789 item.hash(state);
790 }
791 }
792 Value::Map(v) => {
793 for (k, val) in v {
794 k.hash(state);
795 val.hash(state);
796 }
797 }
798 Value::Result(v) => match v {
799 Ok(inner) => {
800 0u8.hash(state);
801 inner.hash(state);
802 }
803 Err(inner) => {
804 1u8.hash(state);
805 inner.hash(state);
806 }
807 },
808 Value::Range {
809 start,
810 end,
811 inclusive,
812 step,
813 } => {
814 start.hash(state);
815 end.hash(state);
816 inclusive.hash(state);
817 step.hash(state);
818 }
819 Value::Iterator(v) => v.hash(state),
820 Value::StringBuilder(v) => v.lock().unwrap().hash(state),
821 Value::Future(v) => (Arc::as_ptr(v) as usize).hash(state),
822 Value::Duration(v) => v.hash(state),
823 Value::Instant(v) => v.hash(state),
824 Value::Channel(v) => (Arc::as_ptr(v) as usize).hash(state),
825 }
826 }
827}
828
829impl fmt::Display for Value {
830 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
831 match self {
832 Value::Int(v) => write!(f, "{v}"),
833 Value::Float(v) => write!(f, "{v}"),
834 Value::Bool(true) => write!(f, "true"),
835 Value::Bool(false) => write!(f, "false"),
836 Value::String(v) => write!(f, "{v}"),
837 Value::Char(v) => write!(f, "'{v}'"),
838 Value::Void => write!(f, "void"),
839 Value::List(items) => {
840 write!(f, "[")?;
841 for (i, item) in items.iter().enumerate() {
842 if i > 0 {
843 write!(f, ", ")?;
844 }
845 write!(f, "{item}")?;
846 }
847 write!(f, "]")
848 }
849 Value::Set(items) => {
850 write!(f, "{{")?;
851 for (i, item) in items.iter().enumerate() {
852 if i > 0 {
853 write!(f, ", ")?;
854 }
855 write!(f, "{item}")?;
856 }
857 write!(f, "}}")
858 }
859 Value::Map(items) => {
860 write!(f, "{{")?;
861 for (i, (k, v)) in items.iter().enumerate() {
862 if i > 0 {
863 write!(f, ", ")?;
864 }
865 write!(f, "{k}: {v}")?;
866 }
867 write!(f, "}}")
868 }
869 Value::Tuple(items) => {
870 write!(f, "(")?;
871 for (i, item) in items.iter().enumerate() {
872 if i > 0 {
873 write!(f, ", ")?;
874 }
875 write!(f, "{item}")?;
876 }
877 write!(f, ")")
878 }
879 Value::Record(r) => {
880 write!(f, "{} {{", r.type_name)?;
881 for (i, (k, v)) in r.fields.iter().enumerate() {
882 if i > 0 {
883 write!(f, ", ")?;
884 }
885 write!(f, "{k}: {v}")?;
886 }
887 write!(f, "}}")
888 }
889 Value::Enum(e) => {
890 write!(f, "{}.{}", e.type_name, e.variant)?;
891 if let Some(payload) = &e.payload {
892 write!(f, "({payload})")?;
893 }
894 Ok(())
895 }
896 Value::Function(fn_val) => write!(f, "{fn_val}"),
897 Value::Optional(Some(v)) => write!(f, "Some({v})"),
898 Value::Optional(None) => write!(f, "None"),
899 Value::Result(Ok(v)) => write!(f, "Ok({v})"),
900 Value::Result(Err(e)) => write!(f, "Err({e})"),
901 Value::Range {
902 start,
903 end,
904 inclusive,
905 step,
906 } => {
907 if *step == 1 {
908 if *inclusive {
909 write!(f, "{start}..={end}")
910 } else {
911 write!(f, "{start}..{end}")
912 }
913 } else if *inclusive {
914 write!(f, "{start}..={end} step {step}")
915 } else {
916 write!(f, "{start}..{end} step {step}")
917 }
918 }
919 Value::Iterator(v) => write!(f, "{v}"),
920 Value::StringBuilder(v) => write!(f, "<StringBuilder len={}>", v.lock().unwrap().len()),
921 Value::Future(_) => write!(f, "<future>"),
922 Value::Duration(nanos) => write!(f, "{}", format_duration(*nanos)),
923 Value::Instant(_) => write!(f, "<instant>"),
924 Value::Channel(_) => write!(f, "<channel>"),
925 }
926 }
927}
928
929fn format_duration(nanos: i64) -> String {
931 if nanos == 0 {
932 return "0s".to_string();
933 }
934 let sign = if nanos < 0 { "-" } else { "" };
935 let abs_nanos = nanos.unsigned_abs();
936 if abs_nanos >= 1_000_000_000 {
937 let secs = abs_nanos as f64 / 1_000_000_000.0;
938 format!("{sign}{secs}s")
939 } else if abs_nanos >= 1_000_000 {
940 let ms = abs_nanos as f64 / 1_000_000.0;
941 format!("{sign}{ms}ms")
942 } else if abs_nanos >= 1_000 {
943 let us = abs_nanos as f64 / 1_000.0;
944 format!("{sign}{us}µs")
945 } else {
946 format!("{sign}{abs_nanos}ns")
947 }
948}
949
950#[cfg(test)]
953mod tests {
954 use super::*;
955
956 #[test]
959 fn ordf64_total_order_neg_zero_vs_pos_zero() {
960 let neg = OrdF64(-0.0_f64);
961 let pos = OrdF64(0.0_f64);
962 assert!(neg < pos, "-0.0 should be less than +0.0 under total order");
963 }
964
965 #[test]
966 fn ordf64_nan_is_ordered() {
967 let nan = OrdF64(f64::NAN);
968 let inf = OrdF64(f64::INFINITY);
969 assert!(inf < nan, "+Inf should be less than +NaN under total order");
970 }
971
972 #[test]
973 fn ordf64_equality_uses_total_cmp() {
974 assert_ne!(OrdF64(-0.0), OrdF64(0.0));
975 assert_eq!(OrdF64(1.0), OrdF64(1.0));
976 }
977
978 #[test]
981 fn bock_string_ord() {
982 let a = BockString::new("apple");
983 let b = BockString::new("banana");
984 assert!(a < b);
985 }
986
987 #[test]
988 fn bock_string_display() {
989 let s = BockString::new("hello");
990 assert_eq!(s.to_string(), "hello");
991 }
992
993 #[test]
996 fn int_equality() {
997 assert_eq!(Value::Int(42), Value::Int(42));
998 assert_ne!(Value::Int(1), Value::Int(2));
999 }
1000
1001 #[test]
1002 fn float_equality_is_ieee() {
1003 assert_eq!(Value::Float(OrdF64(1.5)), Value::Float(OrdF64(1.5)));
1009 assert_eq!(Value::Float(OrdF64(-0.0)), Value::Float(OrdF64(0.0)));
1011 assert_ne!(
1013 Value::Float(OrdF64(f64::NAN)),
1014 Value::Float(OrdF64(f64::NAN))
1015 );
1016 assert_ne!(Value::Float(OrdF64(1.5)), Value::Float(OrdF64(f64::NAN)));
1017 }
1018
1019 #[test]
1020 fn bool_equality() {
1021 assert_eq!(Value::Bool(true), Value::Bool(true));
1022 assert_ne!(Value::Bool(true), Value::Bool(false));
1023 }
1024
1025 #[test]
1026 fn string_equality() {
1027 assert_eq!(
1028 Value::String(BockString::new("hi")),
1029 Value::String(BockString::new("hi"))
1030 );
1031 }
1032
1033 #[test]
1034 fn void_equality() {
1035 assert_eq!(Value::Void, Value::Void);
1036 }
1037
1038 #[test]
1039 fn different_variants_not_equal() {
1040 assert_ne!(Value::Int(0), Value::Bool(false));
1041 }
1042
1043 #[test]
1046 fn fn_equality_by_identity() {
1047 let f1 = FnValue::new_named("foo");
1048 let f2 = FnValue::new_named("foo");
1049 assert_eq!(f1, f1.clone());
1050 assert_ne!(f1, f2);
1051 }
1052
1053 #[test]
1054 fn fn_value_equality_by_identity() {
1055 let f1 = FnValue::new_anonymous();
1056 let f2 = FnValue::new_anonymous();
1057 let v1 = Value::Function(f1.clone());
1058 let v1_clone = Value::Function(f1);
1059 let v2 = Value::Function(f2);
1060 assert_eq!(v1, v1_clone);
1061 assert_ne!(v1_clone, v2);
1062 }
1063
1064 #[test]
1065 #[should_panic(expected = "function values are not orderable")]
1066 fn fn_value_ordering_panics() {
1067 let f1 = Value::Function(FnValue::new_anonymous());
1068 let f2 = Value::Function(FnValue::new_anonymous());
1069 let _ = f1.cmp(&f2);
1070 }
1071
1072 #[test]
1075 fn int_ordering() {
1076 assert!(Value::Int(1) < Value::Int(2));
1077 assert!(Value::Int(2) > Value::Int(1));
1078 }
1079
1080 #[test]
1081 fn bool_ordering() {
1082 assert!(Value::Bool(false) < Value::Bool(true));
1083 }
1084
1085 #[test]
1086 fn optional_none_less_than_some() {
1087 assert!(Value::Optional(None) < Value::Optional(Some(Box::new(Value::Int(0)))));
1088 }
1089
1090 #[test]
1091 fn result_ok_less_than_err() {
1092 let ok = Value::Result(Ok(Box::new(Value::Int(0))));
1093 let err = Value::Result(Err(Box::new(Value::Int(0))));
1094 assert!(ok < err);
1095 }
1096
1097 #[test]
1098 fn cross_variant_ordering_by_discriminant() {
1099 assert!(Value::Void < Value::Bool(false));
1101 assert!(Value::Bool(false) < Value::Int(0));
1102 }
1103
1104 #[test]
1107 fn value_as_btreemap_key() {
1108 let mut map = BTreeMap::new();
1109 map.insert(Value::Int(1), Value::String(BockString::new("one")));
1110 map.insert(Value::Int(2), Value::String(BockString::new("two")));
1111 assert_eq!(
1112 map.get(&Value::Int(1)),
1113 Some(&Value::String(BockString::new("one")))
1114 );
1115 }
1116
1117 #[test]
1118 fn value_as_btreeset_element() {
1119 let mut set = BTreeSet::new();
1120 set.insert(Value::Int(3));
1121 set.insert(Value::Int(1));
1122 set.insert(Value::Int(2));
1123 let sorted: Vec<_> = set.iter().collect();
1124 assert_eq!(sorted[0], &Value::Int(1));
1125 assert_eq!(sorted[2], &Value::Int(3));
1126 }
1127
1128 #[test]
1129 fn float_as_btreeset_element() {
1130 let mut set = BTreeSet::new();
1131 set.insert(Value::Float(OrdF64(3.0)));
1132 set.insert(Value::Float(OrdF64(1.0)));
1133 set.insert(Value::Float(OrdF64(2.0)));
1134 let mut iter = set.iter();
1135 assert_eq!(iter.next(), Some(&Value::Float(OrdF64(1.0))));
1136 }
1137
1138 #[test]
1141 fn display_primitives() {
1142 assert_eq!(Value::Int(42).to_string(), "42");
1143 assert_eq!(Value::Float(OrdF64(3.5)).to_string(), "3.5");
1144 assert_eq!(Value::Bool(true).to_string(), "true");
1145 assert_eq!(Value::Bool(false).to_string(), "false");
1146 assert_eq!(Value::String(BockString::new("hi")).to_string(), "hi");
1147 assert_eq!(Value::Char('x').to_string(), "'x'");
1148 assert_eq!(Value::Void.to_string(), "void");
1149 }
1150
1151 #[test]
1152 fn display_list() {
1153 let v = Value::List(vec![Value::Int(1), Value::Int(2), Value::Int(3)]);
1154 assert_eq!(v.to_string(), "[1, 2, 3]");
1155 }
1156
1157 #[test]
1158 fn display_tuple() {
1159 let v = Value::Tuple(vec![Value::Int(1), Value::Bool(true)]);
1160 assert_eq!(v.to_string(), "(1, true)");
1161 }
1162
1163 #[test]
1164 fn display_optional() {
1165 assert_eq!(
1166 Value::Optional(Some(Box::new(Value::Int(5)))).to_string(),
1167 "Some(5)"
1168 );
1169 assert_eq!(Value::Optional(None).to_string(), "None");
1170 }
1171
1172 #[test]
1173 fn display_result() {
1174 assert_eq!(
1175 Value::Result(Ok(Box::new(Value::Int(0)))).to_string(),
1176 "Ok(0)"
1177 );
1178 assert_eq!(
1179 Value::Result(Err(Box::new(Value::String(BockString::new("fail"))))).to_string(),
1180 "Err(fail)"
1181 );
1182 }
1183
1184 #[test]
1185 fn display_enum_without_payload() {
1186 let v = Value::Enum(EnumValue {
1187 type_name: "Color".into(),
1188 variant: "Red".into(),
1189 payload: None,
1190 });
1191 assert_eq!(v.to_string(), "Color.Red");
1192 }
1193
1194 #[test]
1195 fn display_enum_with_payload() {
1196 let v = Value::Enum(EnumValue {
1197 type_name: "Shape".into(),
1198 variant: "Circle".into(),
1199 payload: Some(Box::new(Value::Float(OrdF64(1.0)))),
1200 });
1201 assert_eq!(v.to_string(), "Shape.Circle(1)");
1202 }
1203
1204 #[test]
1205 fn display_record() {
1206 let mut fields = BTreeMap::new();
1207 fields.insert("x".to_string(), Value::Int(1));
1208 fields.insert("y".to_string(), Value::Int(2));
1209 let v = Value::Record(RecordValue {
1210 type_name: "Point".into(),
1211 fields,
1212 });
1213 assert_eq!(v.to_string(), "Point {x: 1, y: 2}");
1214 }
1215
1216 #[test]
1217 fn display_function_named() {
1218 let v = Value::Function(FnValue::new_named("add"));
1219 assert_eq!(v.to_string(), "<fn add>");
1220 }
1221
1222 #[test]
1225 fn value_clone() {
1226 let original = Value::List(vec![Value::Int(1), Value::Bool(true)]);
1227 let cloned = original.clone();
1228 assert_eq!(original, cloned);
1229 }
1230
1231 #[test]
1234 fn nested_map_value() {
1235 let inner = Value::Map(BTreeMap::from([(Value::Int(1), Value::Bool(true))]));
1236 let outer = Value::List(vec![inner]);
1237 assert_eq!(outer.to_string(), "[{1: true}]");
1238 }
1239}