1use std::any::Any;
2use std::cell::{Cell, RefCell};
3use std::collections::BTreeMap;
4use std::fmt;
5use std::hash::{Hash, Hasher};
6use std::rc::Rc;
7
8use hashbrown::HashMap as SpurMap;
9use lasso::{Rodeo, Spur};
10
11use crate::error::SemaError;
12use crate::EvalContext;
13
14#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
18compile_error!("sema-core NaN-boxed Value requires a 64-bit platform (or wasm32)");
19
20thread_local! {
23 static INTERNER: RefCell<Rodeo> = RefCell::new(Rodeo::default());
24}
25
26pub fn intern(s: &str) -> Spur {
28 INTERNER.with(|r| r.borrow_mut().get_or_intern(s))
29}
30
31pub fn resolve(spur: Spur) -> String {
33 INTERNER.with(|r| r.borrow().resolve(&spur).to_string())
34}
35
36pub fn with_resolved<F, R>(spur: Spur, f: F) -> R
38where
39 F: FnOnce(&str) -> R,
40{
41 INTERNER.with(|r| {
42 let interner = r.borrow();
43 f(interner.resolve(&spur))
44 })
45}
46
47pub fn interner_stats() -> (usize, usize) {
49 INTERNER.with(|r| {
50 let interner = r.borrow();
51 let count = interner.len();
52 let bytes = count * 16; (count, bytes)
54 })
55}
56
57pub fn compare_spurs(a: Spur, b: Spur) -> std::cmp::Ordering {
59 if a == b {
60 return std::cmp::Ordering::Equal;
61 }
62 INTERNER.with(|r| {
63 let interner = r.borrow();
64 interner.resolve(&a).cmp(interner.resolve(&b))
65 })
66}
67
68pub type NativeFnInner = dyn Fn(&EvalContext, &[Value]) -> Result<Value, SemaError>;
72
73pub struct NativeFn {
74 pub name: String,
75 pub func: Box<NativeFnInner>,
76 pub payload: Option<Rc<dyn Any>>,
77}
78
79impl NativeFn {
80 pub fn simple(
81 name: impl Into<String>,
82 f: impl Fn(&[Value]) -> Result<Value, SemaError> + 'static,
83 ) -> Self {
84 Self {
85 name: name.into(),
86 func: Box::new(move |_ctx, args| f(args)),
87 payload: None,
88 }
89 }
90
91 pub fn with_ctx(
92 name: impl Into<String>,
93 f: impl Fn(&EvalContext, &[Value]) -> Result<Value, SemaError> + 'static,
94 ) -> Self {
95 Self {
96 name: name.into(),
97 func: Box::new(f),
98 payload: None,
99 }
100 }
101
102 pub fn with_payload(
103 name: impl Into<String>,
104 payload: Rc<dyn Any>,
105 f: impl Fn(&EvalContext, &[Value]) -> Result<Value, SemaError> + 'static,
106 ) -> Self {
107 Self {
108 name: name.into(),
109 func: Box::new(f),
110 payload: Some(payload),
111 }
112 }
113}
114
115impl fmt::Debug for NativeFn {
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 write!(f, "<native-fn {}>", self.name)
118 }
119}
120
121#[derive(Debug, Clone)]
123pub struct Lambda {
124 pub params: Vec<Spur>,
125 pub rest_param: Option<Spur>,
126 pub body: Vec<Value>,
127 pub env: Env,
128 pub name: Option<Spur>,
129}
130
131#[derive(Debug, Clone)]
133pub struct Macro {
134 pub params: Vec<Spur>,
135 pub rest_param: Option<Spur>,
136 pub body: Vec<Value>,
137 pub name: Spur,
138}
139
140pub struct Thunk {
142 pub body: Value,
143 pub forced: RefCell<Option<Value>>,
144}
145
146impl fmt::Debug for Thunk {
147 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148 if self.forced.borrow().is_some() {
149 write!(f, "<promise (forced)>")
150 } else {
151 write!(f, "<promise>")
152 }
153 }
154}
155
156impl Clone for Thunk {
157 fn clone(&self) -> Self {
158 Thunk {
159 body: self.body.clone(),
160 forced: RefCell::new(self.forced.borrow().clone()),
161 }
162 }
163}
164
165#[derive(Debug, Clone)]
167pub struct Record {
168 pub type_tag: Spur,
169 pub fields: Vec<Value>,
170}
171
172#[derive(Debug, Clone, PartialEq, Eq)]
174pub enum Role {
175 System,
176 User,
177 Assistant,
178 Tool,
179}
180
181impl fmt::Display for Role {
182 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183 match self {
184 Role::System => write!(f, "system"),
185 Role::User => write!(f, "user"),
186 Role::Assistant => write!(f, "assistant"),
187 Role::Tool => write!(f, "tool"),
188 }
189 }
190}
191
192#[derive(Debug, Clone)]
194pub struct ImageAttachment {
195 pub data: String,
196 pub media_type: String,
197}
198
199#[derive(Debug, Clone)]
201pub struct Message {
202 pub role: Role,
203 pub content: String,
204 pub images: Vec<ImageAttachment>,
206}
207
208#[derive(Debug, Clone)]
210pub struct Prompt {
211 pub messages: Vec<Message>,
212}
213
214#[derive(Debug, Clone)]
216pub struct Conversation {
217 pub messages: Vec<Message>,
218 pub model: String,
219 pub metadata: BTreeMap<String, String>,
220}
221
222#[derive(Debug, Clone)]
224pub struct ToolDefinition {
225 pub name: String,
226 pub description: String,
227 pub parameters: Value,
228 pub handler: Value,
229}
230
231#[derive(Debug, Clone)]
233pub struct Agent {
234 pub name: String,
235 pub system: String,
236 pub tools: Vec<Value>,
237 pub max_turns: usize,
238 pub model: String,
239}
240
241const BOX_MASK: u64 = 0xFFF8_0000_0000_0000;
253
254const PAYLOAD_MASK: u64 = (1u64 << 45) - 1; const INT_SIGN_BIT: u64 = 1u64 << 44;
259
260const CANONICAL_NAN: u64 = 0x7FF8_0000_0000_0000;
262
263const TAG_NIL: u64 = 0;
265const TAG_FALSE: u64 = 1;
266const TAG_TRUE: u64 = 2;
267const TAG_INT_SMALL: u64 = 3;
268const TAG_CHAR: u64 = 4;
269const TAG_SYMBOL: u64 = 5;
270const TAG_KEYWORD: u64 = 6;
271const TAG_INT_BIG: u64 = 7;
272const TAG_STRING: u64 = 8;
273const TAG_LIST: u64 = 9;
274const TAG_VECTOR: u64 = 10;
275const TAG_MAP: u64 = 11;
276const TAG_HASHMAP: u64 = 12;
277const TAG_LAMBDA: u64 = 13;
278const TAG_MACRO: u64 = 14;
279const TAG_NATIVE_FN: u64 = 15;
280const TAG_PROMPT: u64 = 16;
281const TAG_MESSAGE: u64 = 17;
282const TAG_CONVERSATION: u64 = 18;
283const TAG_TOOL_DEF: u64 = 19;
284const TAG_AGENT: u64 = 20;
285const TAG_THUNK: u64 = 21;
286const TAG_RECORD: u64 = 22;
287const TAG_BYTEVECTOR: u64 = 23;
288
289const SMALL_INT_MIN: i64 = -(1i64 << 44);
291const SMALL_INT_MAX: i64 = (1i64 << 44) - 1;
292
293pub const NAN_TAG_MASK: u64 = BOX_MASK | (0x3F << 45); pub const NAN_INT_SMALL_PATTERN: u64 = BOX_MASK | (TAG_INT_SMALL << 45);
300
301pub const NAN_PAYLOAD_MASK: u64 = PAYLOAD_MASK;
303
304pub const NAN_INT_SIGN_BIT: u64 = INT_SIGN_BIT;
306
307#[inline(always)]
310fn make_boxed(tag: u64, payload: u64) -> u64 {
311 BOX_MASK | (tag << 45) | (payload & PAYLOAD_MASK)
312}
313
314#[inline(always)]
315fn is_boxed(bits: u64) -> bool {
316 (bits & BOX_MASK) == BOX_MASK
317}
318
319#[inline(always)]
320fn get_tag(bits: u64) -> u64 {
321 (bits >> 45) & 0x3F
322}
323
324#[inline(always)]
325fn get_payload(bits: u64) -> u64 {
326 bits & PAYLOAD_MASK
327}
328
329#[inline(always)]
330fn ptr_to_payload(ptr: *const u8) -> u64 {
331 let raw = ptr as u64;
332 debug_assert!(raw & 0x7 == 0, "pointer not 8-byte aligned: 0x{:x}", raw);
333 debug_assert!(
334 raw >> 48 == 0,
335 "pointer exceeds 48-bit VA space: 0x{:x}",
336 raw
337 );
338 raw >> 3
339}
340
341#[inline(always)]
342fn payload_to_ptr(payload: u64) -> *const u8 {
343 (payload << 3) as *const u8
344}
345
346pub enum ValueView {
351 Nil,
352 Bool(bool),
353 Int(i64),
354 Float(f64),
355 String(Rc<String>),
356 Symbol(Spur),
357 Keyword(Spur),
358 Char(char),
359 List(Rc<Vec<Value>>),
360 Vector(Rc<Vec<Value>>),
361 Map(Rc<BTreeMap<Value, Value>>),
362 HashMap(Rc<hashbrown::HashMap<Value, Value>>),
363 Lambda(Rc<Lambda>),
364 Macro(Rc<Macro>),
365 NativeFn(Rc<NativeFn>),
366 Prompt(Rc<Prompt>),
367 Message(Rc<Message>),
368 Conversation(Rc<Conversation>),
369 ToolDef(Rc<ToolDefinition>),
370 Agent(Rc<Agent>),
371 Thunk(Rc<Thunk>),
372 Record(Rc<Record>),
373 Bytevector(Rc<Vec<u8>>),
374}
375
376#[repr(transparent)]
382pub struct Value(u64);
383
384impl Value {
387 pub const NIL: Value = Value(make_boxed_const(TAG_NIL, 0));
390 pub const TRUE: Value = Value(make_boxed_const(TAG_TRUE, 0));
391 pub const FALSE: Value = Value(make_boxed_const(TAG_FALSE, 0));
392
393 #[inline(always)]
394 pub fn nil() -> Value {
395 Value::NIL
396 }
397
398 #[inline(always)]
399 pub fn bool(b: bool) -> Value {
400 if b {
401 Value::TRUE
402 } else {
403 Value::FALSE
404 }
405 }
406
407 #[inline(always)]
408 pub fn int(n: i64) -> Value {
409 if (SMALL_INT_MIN..=SMALL_INT_MAX).contains(&n) {
410 let payload = (n as u64) & PAYLOAD_MASK;
412 Value(make_boxed(TAG_INT_SMALL, payload))
413 } else {
414 let rc = Rc::new(n);
416 let ptr = Rc::into_raw(rc) as *const u8;
417 Value(make_boxed(TAG_INT_BIG, ptr_to_payload(ptr)))
418 }
419 }
420
421 #[inline(always)]
422 pub fn float(f: f64) -> Value {
423 let bits = f.to_bits();
424 if f.is_nan() {
425 Value(CANONICAL_NAN)
427 } else {
428 debug_assert!(
435 !is_boxed(bits),
436 "non-NaN float collides with boxed pattern: {:?} = 0x{:016x}",
437 f,
438 bits
439 );
440 Value(bits)
441 }
442 }
443
444 #[inline(always)]
445 pub fn char(c: char) -> Value {
446 Value(make_boxed(TAG_CHAR, c as u64))
447 }
448
449 #[inline(always)]
450 pub fn symbol_from_spur(spur: Spur) -> Value {
451 let bits: u32 = unsafe { std::mem::transmute(spur) };
452 Value(make_boxed(TAG_SYMBOL, bits as u64))
453 }
454
455 pub fn symbol(s: &str) -> Value {
456 Value::symbol_from_spur(intern(s))
457 }
458
459 #[inline(always)]
460 pub fn keyword_from_spur(spur: Spur) -> Value {
461 let bits: u32 = unsafe { std::mem::transmute(spur) };
462 Value(make_boxed(TAG_KEYWORD, bits as u64))
463 }
464
465 pub fn keyword(s: &str) -> Value {
466 Value::keyword_from_spur(intern(s))
467 }
468
469 fn from_rc_ptr<T>(tag: u64, rc: Rc<T>) -> Value {
472 let ptr = Rc::into_raw(rc) as *const u8;
473 Value(make_boxed(tag, ptr_to_payload(ptr)))
474 }
475
476 pub fn string(s: &str) -> Value {
477 Value::from_rc_ptr(TAG_STRING, Rc::new(s.to_string()))
478 }
479
480 pub fn string_from_rc(rc: Rc<String>) -> Value {
481 Value::from_rc_ptr(TAG_STRING, rc)
482 }
483
484 pub fn list(v: Vec<Value>) -> Value {
485 Value::from_rc_ptr(TAG_LIST, Rc::new(v))
486 }
487
488 pub fn list_from_rc(rc: Rc<Vec<Value>>) -> Value {
489 Value::from_rc_ptr(TAG_LIST, rc)
490 }
491
492 pub fn vector(v: Vec<Value>) -> Value {
493 Value::from_rc_ptr(TAG_VECTOR, Rc::new(v))
494 }
495
496 pub fn vector_from_rc(rc: Rc<Vec<Value>>) -> Value {
497 Value::from_rc_ptr(TAG_VECTOR, rc)
498 }
499
500 pub fn map(m: BTreeMap<Value, Value>) -> Value {
501 Value::from_rc_ptr(TAG_MAP, Rc::new(m))
502 }
503
504 pub fn map_from_rc(rc: Rc<BTreeMap<Value, Value>>) -> Value {
505 Value::from_rc_ptr(TAG_MAP, rc)
506 }
507
508 pub fn hashmap(entries: Vec<(Value, Value)>) -> Value {
509 let map: hashbrown::HashMap<Value, Value> = entries.into_iter().collect();
510 Value::from_rc_ptr(TAG_HASHMAP, Rc::new(map))
511 }
512
513 pub fn hashmap_from_rc(rc: Rc<hashbrown::HashMap<Value, Value>>) -> Value {
514 Value::from_rc_ptr(TAG_HASHMAP, rc)
515 }
516
517 pub fn lambda(l: Lambda) -> Value {
518 Value::from_rc_ptr(TAG_LAMBDA, Rc::new(l))
519 }
520
521 pub fn lambda_from_rc(rc: Rc<Lambda>) -> Value {
522 Value::from_rc_ptr(TAG_LAMBDA, rc)
523 }
524
525 pub fn macro_val(m: Macro) -> Value {
526 Value::from_rc_ptr(TAG_MACRO, Rc::new(m))
527 }
528
529 pub fn macro_from_rc(rc: Rc<Macro>) -> Value {
530 Value::from_rc_ptr(TAG_MACRO, rc)
531 }
532
533 pub fn native_fn(f: NativeFn) -> Value {
534 Value::from_rc_ptr(TAG_NATIVE_FN, Rc::new(f))
535 }
536
537 pub fn native_fn_from_rc(rc: Rc<NativeFn>) -> Value {
538 Value::from_rc_ptr(TAG_NATIVE_FN, rc)
539 }
540
541 pub fn prompt(p: Prompt) -> Value {
542 Value::from_rc_ptr(TAG_PROMPT, Rc::new(p))
543 }
544
545 pub fn prompt_from_rc(rc: Rc<Prompt>) -> Value {
546 Value::from_rc_ptr(TAG_PROMPT, rc)
547 }
548
549 pub fn message(m: Message) -> Value {
550 Value::from_rc_ptr(TAG_MESSAGE, Rc::new(m))
551 }
552
553 pub fn message_from_rc(rc: Rc<Message>) -> Value {
554 Value::from_rc_ptr(TAG_MESSAGE, rc)
555 }
556
557 pub fn conversation(c: Conversation) -> Value {
558 Value::from_rc_ptr(TAG_CONVERSATION, Rc::new(c))
559 }
560
561 pub fn conversation_from_rc(rc: Rc<Conversation>) -> Value {
562 Value::from_rc_ptr(TAG_CONVERSATION, rc)
563 }
564
565 pub fn tool_def(t: ToolDefinition) -> Value {
566 Value::from_rc_ptr(TAG_TOOL_DEF, Rc::new(t))
567 }
568
569 pub fn tool_def_from_rc(rc: Rc<ToolDefinition>) -> Value {
570 Value::from_rc_ptr(TAG_TOOL_DEF, rc)
571 }
572
573 pub fn agent(a: Agent) -> Value {
574 Value::from_rc_ptr(TAG_AGENT, Rc::new(a))
575 }
576
577 pub fn agent_from_rc(rc: Rc<Agent>) -> Value {
578 Value::from_rc_ptr(TAG_AGENT, rc)
579 }
580
581 pub fn thunk(t: Thunk) -> Value {
582 Value::from_rc_ptr(TAG_THUNK, Rc::new(t))
583 }
584
585 pub fn thunk_from_rc(rc: Rc<Thunk>) -> Value {
586 Value::from_rc_ptr(TAG_THUNK, rc)
587 }
588
589 pub fn record(r: Record) -> Value {
590 Value::from_rc_ptr(TAG_RECORD, Rc::new(r))
591 }
592
593 pub fn record_from_rc(rc: Rc<Record>) -> Value {
594 Value::from_rc_ptr(TAG_RECORD, rc)
595 }
596
597 pub fn bytevector(bytes: Vec<u8>) -> Value {
598 Value::from_rc_ptr(TAG_BYTEVECTOR, Rc::new(bytes))
599 }
600
601 pub fn bytevector_from_rc(rc: Rc<Vec<u8>>) -> Value {
602 Value::from_rc_ptr(TAG_BYTEVECTOR, rc)
603 }
604}
605
606const fn make_boxed_const(tag: u64, payload: u64) -> u64 {
608 BOX_MASK | (tag << 45) | (payload & PAYLOAD_MASK)
609}
610
611impl Value {
614 #[inline(always)]
616 pub fn raw_bits(&self) -> u64 {
617 self.0
618 }
619
620 #[inline(always)]
629 pub unsafe fn from_raw_bits(bits: u64) -> Value {
630 Value(bits)
631 }
632
633 #[inline(always)]
636 pub fn raw_tag(&self) -> Option<u64> {
637 if is_boxed(self.0) {
638 Some(get_tag(self.0))
639 } else {
640 None
641 }
642 }
643
644 #[inline(always)]
647 pub fn as_native_fn_ref(&self) -> Option<&NativeFn> {
648 if is_boxed(self.0) && get_tag(self.0) == TAG_NATIVE_FN {
649 Some(unsafe { self.borrow_ref::<NativeFn>() })
650 } else {
651 None
652 }
653 }
654
655 #[inline(always)]
657 pub fn is_float(&self) -> bool {
658 !is_boxed(self.0)
659 }
660
661 #[inline(always)]
664 unsafe fn get_rc<T>(&self) -> Rc<T> {
665 let payload = get_payload(self.0);
666 let ptr = payload_to_ptr(payload) as *const T;
667 Rc::increment_strong_count(ptr);
668 Rc::from_raw(ptr)
669 }
670
671 #[inline(always)]
674 unsafe fn borrow_ref<T>(&self) -> &T {
675 let payload = get_payload(self.0);
676 let ptr = payload_to_ptr(payload) as *const T;
677 &*ptr
678 }
679
680 pub fn view(&self) -> ValueView {
683 if !is_boxed(self.0) {
684 return ValueView::Float(f64::from_bits(self.0));
685 }
686 let tag = get_tag(self.0);
687 match tag {
688 TAG_NIL => ValueView::Nil,
689 TAG_FALSE => ValueView::Bool(false),
690 TAG_TRUE => ValueView::Bool(true),
691 TAG_INT_SMALL => {
692 let payload = get_payload(self.0);
693 let val = if payload & INT_SIGN_BIT != 0 {
694 (payload | !PAYLOAD_MASK) as i64
695 } else {
696 payload as i64
697 };
698 ValueView::Int(val)
699 }
700 TAG_CHAR => {
701 let payload = get_payload(self.0);
702 ValueView::Char(unsafe { char::from_u32_unchecked(payload as u32) })
703 }
704 TAG_SYMBOL => {
705 let payload = get_payload(self.0);
706 let spur: Spur = unsafe { std::mem::transmute(payload as u32) };
707 ValueView::Symbol(spur)
708 }
709 TAG_KEYWORD => {
710 let payload = get_payload(self.0);
711 let spur: Spur = unsafe { std::mem::transmute(payload as u32) };
712 ValueView::Keyword(spur)
713 }
714 TAG_INT_BIG => {
715 let val = unsafe { *self.borrow_ref::<i64>() };
716 ValueView::Int(val)
717 }
718 TAG_STRING => ValueView::String(unsafe { self.get_rc::<String>() }),
719 TAG_LIST => ValueView::List(unsafe { self.get_rc::<Vec<Value>>() }),
720 TAG_VECTOR => ValueView::Vector(unsafe { self.get_rc::<Vec<Value>>() }),
721 TAG_MAP => ValueView::Map(unsafe { self.get_rc::<BTreeMap<Value, Value>>() }),
722 TAG_HASHMAP => {
723 ValueView::HashMap(unsafe { self.get_rc::<hashbrown::HashMap<Value, Value>>() })
724 }
725 TAG_LAMBDA => ValueView::Lambda(unsafe { self.get_rc::<Lambda>() }),
726 TAG_MACRO => ValueView::Macro(unsafe { self.get_rc::<Macro>() }),
727 TAG_NATIVE_FN => ValueView::NativeFn(unsafe { self.get_rc::<NativeFn>() }),
728 TAG_PROMPT => ValueView::Prompt(unsafe { self.get_rc::<Prompt>() }),
729 TAG_MESSAGE => ValueView::Message(unsafe { self.get_rc::<Message>() }),
730 TAG_CONVERSATION => ValueView::Conversation(unsafe { self.get_rc::<Conversation>() }),
731 TAG_TOOL_DEF => ValueView::ToolDef(unsafe { self.get_rc::<ToolDefinition>() }),
732 TAG_AGENT => ValueView::Agent(unsafe { self.get_rc::<Agent>() }),
733 TAG_THUNK => ValueView::Thunk(unsafe { self.get_rc::<Thunk>() }),
734 TAG_RECORD => ValueView::Record(unsafe { self.get_rc::<Record>() }),
735 TAG_BYTEVECTOR => ValueView::Bytevector(unsafe { self.get_rc::<Vec<u8>>() }),
736 _ => unreachable!("invalid NaN-boxed tag: {}", tag),
737 }
738 }
739
740 pub fn type_name(&self) -> &'static str {
743 if !is_boxed(self.0) {
744 return "float";
745 }
746 match get_tag(self.0) {
747 TAG_NIL => "nil",
748 TAG_FALSE | TAG_TRUE => "bool",
749 TAG_INT_SMALL | TAG_INT_BIG => "int",
750 TAG_CHAR => "char",
751 TAG_SYMBOL => "symbol",
752 TAG_KEYWORD => "keyword",
753 TAG_STRING => "string",
754 TAG_LIST => "list",
755 TAG_VECTOR => "vector",
756 TAG_MAP => "map",
757 TAG_HASHMAP => "hashmap",
758 TAG_LAMBDA => "lambda",
759 TAG_MACRO => "macro",
760 TAG_NATIVE_FN => "native-fn",
761 TAG_PROMPT => "prompt",
762 TAG_MESSAGE => "message",
763 TAG_CONVERSATION => "conversation",
764 TAG_TOOL_DEF => "tool",
765 TAG_AGENT => "agent",
766 TAG_THUNK => "promise",
767 TAG_RECORD => "record",
768 TAG_BYTEVECTOR => "bytevector",
769 _ => "unknown",
770 }
771 }
772
773 #[inline(always)]
774 pub fn is_nil(&self) -> bool {
775 self.0 == Value::NIL.0
776 }
777
778 #[inline(always)]
779 pub fn is_truthy(&self) -> bool {
780 self.0 != Value::NIL.0 && self.0 != Value::FALSE.0
781 }
782
783 #[inline(always)]
784 pub fn is_bool(&self) -> bool {
785 self.0 == Value::TRUE.0 || self.0 == Value::FALSE.0
786 }
787
788 #[inline(always)]
789 pub fn is_int(&self) -> bool {
790 is_boxed(self.0) && matches!(get_tag(self.0), TAG_INT_SMALL | TAG_INT_BIG)
791 }
792
793 #[inline(always)]
794 pub fn is_symbol(&self) -> bool {
795 is_boxed(self.0) && get_tag(self.0) == TAG_SYMBOL
796 }
797
798 #[inline(always)]
799 pub fn is_keyword(&self) -> bool {
800 is_boxed(self.0) && get_tag(self.0) == TAG_KEYWORD
801 }
802
803 #[inline(always)]
804 pub fn is_string(&self) -> bool {
805 is_boxed(self.0) && get_tag(self.0) == TAG_STRING
806 }
807
808 #[inline(always)]
809 pub fn is_list(&self) -> bool {
810 is_boxed(self.0) && get_tag(self.0) == TAG_LIST
811 }
812
813 #[inline(always)]
814 pub fn is_pair(&self) -> bool {
815 if let Some(items) = self.as_list() {
816 !items.is_empty()
817 } else {
818 false
819 }
820 }
821
822 #[inline(always)]
823 pub fn is_vector(&self) -> bool {
824 is_boxed(self.0) && get_tag(self.0) == TAG_VECTOR
825 }
826
827 #[inline(always)]
828 pub fn is_map(&self) -> bool {
829 is_boxed(self.0) && matches!(get_tag(self.0), TAG_MAP | TAG_HASHMAP)
830 }
831
832 #[inline(always)]
833 pub fn is_lambda(&self) -> bool {
834 is_boxed(self.0) && get_tag(self.0) == TAG_LAMBDA
835 }
836
837 #[inline(always)]
838 pub fn is_native_fn(&self) -> bool {
839 is_boxed(self.0) && get_tag(self.0) == TAG_NATIVE_FN
840 }
841
842 #[inline(always)]
843 pub fn is_thunk(&self) -> bool {
844 is_boxed(self.0) && get_tag(self.0) == TAG_THUNK
845 }
846
847 #[inline(always)]
848 pub fn is_record(&self) -> bool {
849 is_boxed(self.0) && get_tag(self.0) == TAG_RECORD
850 }
851
852 #[inline(always)]
853 pub fn as_int(&self) -> Option<i64> {
854 if !is_boxed(self.0) {
855 return None;
856 }
857 match get_tag(self.0) {
858 TAG_INT_SMALL => {
859 let payload = get_payload(self.0);
860 let val = if payload & INT_SIGN_BIT != 0 {
861 (payload | !PAYLOAD_MASK) as i64
862 } else {
863 payload as i64
864 };
865 Some(val)
866 }
867 TAG_INT_BIG => Some(unsafe { *self.borrow_ref::<i64>() }),
868 _ => None,
869 }
870 }
871
872 #[inline(always)]
873 pub fn as_float(&self) -> Option<f64> {
874 if !is_boxed(self.0) {
875 return Some(f64::from_bits(self.0));
876 }
877 match get_tag(self.0) {
878 TAG_INT_SMALL => {
879 let payload = get_payload(self.0);
880 let val = if payload & INT_SIGN_BIT != 0 {
881 (payload | !PAYLOAD_MASK) as i64
882 } else {
883 payload as i64
884 };
885 Some(val as f64)
886 }
887 TAG_INT_BIG => Some(unsafe { *self.borrow_ref::<i64>() } as f64),
888 _ => None,
889 }
890 }
891
892 #[inline(always)]
893 pub fn as_bool(&self) -> Option<bool> {
894 if self.0 == Value::TRUE.0 {
895 Some(true)
896 } else if self.0 == Value::FALSE.0 {
897 Some(false)
898 } else {
899 None
900 }
901 }
902
903 pub fn as_str(&self) -> Option<&str> {
904 if is_boxed(self.0) && get_tag(self.0) == TAG_STRING {
905 Some(unsafe { self.borrow_ref::<String>() })
906 } else {
907 None
908 }
909 }
910
911 pub fn as_string_rc(&self) -> Option<Rc<String>> {
912 if is_boxed(self.0) && get_tag(self.0) == TAG_STRING {
913 Some(unsafe { self.get_rc::<String>() })
914 } else {
915 None
916 }
917 }
918
919 pub fn as_symbol(&self) -> Option<String> {
920 self.as_symbol_spur().map(resolve)
921 }
922
923 pub fn as_symbol_spur(&self) -> Option<Spur> {
924 if is_boxed(self.0) && get_tag(self.0) == TAG_SYMBOL {
925 let payload = get_payload(self.0);
926 Some(unsafe { std::mem::transmute::<u32, Spur>(payload as u32) })
927 } else {
928 None
929 }
930 }
931
932 pub fn as_keyword(&self) -> Option<String> {
933 self.as_keyword_spur().map(resolve)
934 }
935
936 pub fn as_keyword_spur(&self) -> Option<Spur> {
937 if is_boxed(self.0) && get_tag(self.0) == TAG_KEYWORD {
938 let payload = get_payload(self.0);
939 Some(unsafe { std::mem::transmute::<u32, Spur>(payload as u32) })
940 } else {
941 None
942 }
943 }
944
945 pub fn as_char(&self) -> Option<char> {
946 if is_boxed(self.0) && get_tag(self.0) == TAG_CHAR {
947 let payload = get_payload(self.0);
948 char::from_u32(payload as u32)
949 } else {
950 None
951 }
952 }
953
954 pub fn as_list(&self) -> Option<&[Value]> {
955 if is_boxed(self.0) && get_tag(self.0) == TAG_LIST {
956 Some(unsafe { self.borrow_ref::<Vec<Value>>() })
957 } else {
958 None
959 }
960 }
961
962 pub fn as_list_rc(&self) -> Option<Rc<Vec<Value>>> {
963 if is_boxed(self.0) && get_tag(self.0) == TAG_LIST {
964 Some(unsafe { self.get_rc::<Vec<Value>>() })
965 } else {
966 None
967 }
968 }
969
970 pub fn as_vector(&self) -> Option<&[Value]> {
971 if is_boxed(self.0) && get_tag(self.0) == TAG_VECTOR {
972 Some(unsafe { self.borrow_ref::<Vec<Value>>() })
973 } else {
974 None
975 }
976 }
977
978 pub fn as_vector_rc(&self) -> Option<Rc<Vec<Value>>> {
979 if is_boxed(self.0) && get_tag(self.0) == TAG_VECTOR {
980 Some(unsafe { self.get_rc::<Vec<Value>>() })
981 } else {
982 None
983 }
984 }
985
986 pub fn as_map_rc(&self) -> Option<Rc<BTreeMap<Value, Value>>> {
987 if is_boxed(self.0) && get_tag(self.0) == TAG_MAP {
988 Some(unsafe { self.get_rc::<BTreeMap<Value, Value>>() })
989 } else {
990 None
991 }
992 }
993
994 pub fn as_hashmap_rc(&self) -> Option<Rc<hashbrown::HashMap<Value, Value>>> {
995 if is_boxed(self.0) && get_tag(self.0) == TAG_HASHMAP {
996 Some(unsafe { self.get_rc::<hashbrown::HashMap<Value, Value>>() })
997 } else {
998 None
999 }
1000 }
1001
1002 pub fn as_lambda_rc(&self) -> Option<Rc<Lambda>> {
1003 if is_boxed(self.0) && get_tag(self.0) == TAG_LAMBDA {
1004 Some(unsafe { self.get_rc::<Lambda>() })
1005 } else {
1006 None
1007 }
1008 }
1009
1010 pub fn as_macro_rc(&self) -> Option<Rc<Macro>> {
1011 if is_boxed(self.0) && get_tag(self.0) == TAG_MACRO {
1012 Some(unsafe { self.get_rc::<Macro>() })
1013 } else {
1014 None
1015 }
1016 }
1017
1018 pub fn as_native_fn_rc(&self) -> Option<Rc<NativeFn>> {
1019 if is_boxed(self.0) && get_tag(self.0) == TAG_NATIVE_FN {
1020 Some(unsafe { self.get_rc::<NativeFn>() })
1021 } else {
1022 None
1023 }
1024 }
1025
1026 pub fn as_thunk_rc(&self) -> Option<Rc<Thunk>> {
1027 if is_boxed(self.0) && get_tag(self.0) == TAG_THUNK {
1028 Some(unsafe { self.get_rc::<Thunk>() })
1029 } else {
1030 None
1031 }
1032 }
1033
1034 pub fn as_record(&self) -> Option<&Record> {
1035 if is_boxed(self.0) && get_tag(self.0) == TAG_RECORD {
1036 Some(unsafe { self.borrow_ref::<Record>() })
1037 } else {
1038 None
1039 }
1040 }
1041
1042 pub fn as_record_rc(&self) -> Option<Rc<Record>> {
1043 if is_boxed(self.0) && get_tag(self.0) == TAG_RECORD {
1044 Some(unsafe { self.get_rc::<Record>() })
1045 } else {
1046 None
1047 }
1048 }
1049
1050 pub fn as_bytevector(&self) -> Option<&[u8]> {
1051 if is_boxed(self.0) && get_tag(self.0) == TAG_BYTEVECTOR {
1052 Some(unsafe { self.borrow_ref::<Vec<u8>>() })
1053 } else {
1054 None
1055 }
1056 }
1057
1058 pub fn as_bytevector_rc(&self) -> Option<Rc<Vec<u8>>> {
1059 if is_boxed(self.0) && get_tag(self.0) == TAG_BYTEVECTOR {
1060 Some(unsafe { self.get_rc::<Vec<u8>>() })
1061 } else {
1062 None
1063 }
1064 }
1065
1066 pub fn as_prompt_rc(&self) -> Option<Rc<Prompt>> {
1067 if is_boxed(self.0) && get_tag(self.0) == TAG_PROMPT {
1068 Some(unsafe { self.get_rc::<Prompt>() })
1069 } else {
1070 None
1071 }
1072 }
1073
1074 pub fn as_message_rc(&self) -> Option<Rc<Message>> {
1075 if is_boxed(self.0) && get_tag(self.0) == TAG_MESSAGE {
1076 Some(unsafe { self.get_rc::<Message>() })
1077 } else {
1078 None
1079 }
1080 }
1081
1082 pub fn as_conversation_rc(&self) -> Option<Rc<Conversation>> {
1083 if is_boxed(self.0) && get_tag(self.0) == TAG_CONVERSATION {
1084 Some(unsafe { self.get_rc::<Conversation>() })
1085 } else {
1086 None
1087 }
1088 }
1089
1090 pub fn as_tool_def_rc(&self) -> Option<Rc<ToolDefinition>> {
1091 if is_boxed(self.0) && get_tag(self.0) == TAG_TOOL_DEF {
1092 Some(unsafe { self.get_rc::<ToolDefinition>() })
1093 } else {
1094 None
1095 }
1096 }
1097
1098 pub fn as_agent_rc(&self) -> Option<Rc<Agent>> {
1099 if is_boxed(self.0) && get_tag(self.0) == TAG_AGENT {
1100 Some(unsafe { self.get_rc::<Agent>() })
1101 } else {
1102 None
1103 }
1104 }
1105}
1106
1107impl Clone for Value {
1110 #[inline(always)]
1111 fn clone(&self) -> Self {
1112 if !is_boxed(self.0) {
1113 return Value(self.0);
1115 }
1116 let tag = get_tag(self.0);
1117 match tag {
1118 TAG_NIL | TAG_FALSE | TAG_TRUE | TAG_INT_SMALL | TAG_CHAR | TAG_SYMBOL
1120 | TAG_KEYWORD => Value(self.0),
1121 _ => {
1123 let payload = get_payload(self.0);
1124 let ptr = payload_to_ptr(payload);
1125 unsafe {
1127 match tag {
1128 TAG_INT_BIG => Rc::increment_strong_count(ptr as *const i64),
1129 TAG_STRING => Rc::increment_strong_count(ptr as *const String),
1130 TAG_LIST | TAG_VECTOR => {
1131 Rc::increment_strong_count(ptr as *const Vec<Value>)
1132 }
1133 TAG_MAP => Rc::increment_strong_count(ptr as *const BTreeMap<Value, Value>),
1134 TAG_HASHMAP => Rc::increment_strong_count(
1135 ptr as *const hashbrown::HashMap<Value, Value>,
1136 ),
1137 TAG_LAMBDA => Rc::increment_strong_count(ptr as *const Lambda),
1138 TAG_MACRO => Rc::increment_strong_count(ptr as *const Macro),
1139 TAG_NATIVE_FN => Rc::increment_strong_count(ptr as *const NativeFn),
1140 TAG_PROMPT => Rc::increment_strong_count(ptr as *const Prompt),
1141 TAG_MESSAGE => Rc::increment_strong_count(ptr as *const Message),
1142 TAG_CONVERSATION => Rc::increment_strong_count(ptr as *const Conversation),
1143 TAG_TOOL_DEF => Rc::increment_strong_count(ptr as *const ToolDefinition),
1144 TAG_AGENT => Rc::increment_strong_count(ptr as *const Agent),
1145 TAG_THUNK => Rc::increment_strong_count(ptr as *const Thunk),
1146 TAG_RECORD => Rc::increment_strong_count(ptr as *const Record),
1147 TAG_BYTEVECTOR => Rc::increment_strong_count(ptr as *const Vec<u8>),
1148 _ => unreachable!("invalid heap tag in clone: {}", tag),
1149 }
1150 }
1151 Value(self.0)
1152 }
1153 }
1154 }
1155}
1156
1157impl Drop for Value {
1160 #[inline(always)]
1161 fn drop(&mut self) {
1162 if !is_boxed(self.0) {
1163 return; }
1165 let tag = get_tag(self.0);
1166 match tag {
1167 TAG_NIL | TAG_FALSE | TAG_TRUE | TAG_INT_SMALL | TAG_CHAR | TAG_SYMBOL
1169 | TAG_KEYWORD => {}
1170 _ => {
1172 let payload = get_payload(self.0);
1173 let ptr = payload_to_ptr(payload);
1174 unsafe {
1175 match tag {
1176 TAG_INT_BIG => drop(Rc::from_raw(ptr as *const i64)),
1177 TAG_STRING => drop(Rc::from_raw(ptr as *const String)),
1178 TAG_LIST | TAG_VECTOR => drop(Rc::from_raw(ptr as *const Vec<Value>)),
1179 TAG_MAP => drop(Rc::from_raw(ptr as *const BTreeMap<Value, Value>)),
1180 TAG_HASHMAP => {
1181 drop(Rc::from_raw(ptr as *const hashbrown::HashMap<Value, Value>))
1182 }
1183 TAG_LAMBDA => drop(Rc::from_raw(ptr as *const Lambda)),
1184 TAG_MACRO => drop(Rc::from_raw(ptr as *const Macro)),
1185 TAG_NATIVE_FN => drop(Rc::from_raw(ptr as *const NativeFn)),
1186 TAG_PROMPT => drop(Rc::from_raw(ptr as *const Prompt)),
1187 TAG_MESSAGE => drop(Rc::from_raw(ptr as *const Message)),
1188 TAG_CONVERSATION => drop(Rc::from_raw(ptr as *const Conversation)),
1189 TAG_TOOL_DEF => drop(Rc::from_raw(ptr as *const ToolDefinition)),
1190 TAG_AGENT => drop(Rc::from_raw(ptr as *const Agent)),
1191 TAG_THUNK => drop(Rc::from_raw(ptr as *const Thunk)),
1192 TAG_RECORD => drop(Rc::from_raw(ptr as *const Record)),
1193 TAG_BYTEVECTOR => drop(Rc::from_raw(ptr as *const Vec<u8>)),
1194 _ => {} }
1196 }
1197 }
1198 }
1199 }
1200}
1201
1202impl PartialEq for Value {
1205 fn eq(&self, other: &Self) -> bool {
1206 if self.0 == other.0 {
1208 if !is_boxed(self.0) {
1212 let f = f64::from_bits(self.0);
1213 if f.is_nan() {
1215 return false;
1216 }
1217 return true;
1218 }
1219 return true;
1220 }
1221 match (self.view(), other.view()) {
1223 (ValueView::Nil, ValueView::Nil) => true,
1224 (ValueView::Bool(a), ValueView::Bool(b)) => a == b,
1225 (ValueView::Int(a), ValueView::Int(b)) => a == b,
1226 (ValueView::Float(a), ValueView::Float(b)) => a.to_bits() == b.to_bits(),
1227 (ValueView::String(a), ValueView::String(b)) => a == b,
1228 (ValueView::Symbol(a), ValueView::Symbol(b)) => a == b,
1229 (ValueView::Keyword(a), ValueView::Keyword(b)) => a == b,
1230 (ValueView::Char(a), ValueView::Char(b)) => a == b,
1231 (ValueView::List(a), ValueView::List(b)) => a == b,
1232 (ValueView::Vector(a), ValueView::Vector(b)) => a == b,
1233 (ValueView::Map(a), ValueView::Map(b)) => a == b,
1234 (ValueView::HashMap(a), ValueView::HashMap(b)) => a == b,
1235 (ValueView::Record(a), ValueView::Record(b)) => {
1236 a.type_tag == b.type_tag && a.fields == b.fields
1237 }
1238 (ValueView::Bytevector(a), ValueView::Bytevector(b)) => a == b,
1239 _ => false,
1240 }
1241 }
1242}
1243
1244impl Eq for Value {}
1245
1246impl Hash for Value {
1249 fn hash<H: Hasher>(&self, state: &mut H) {
1250 match self.view() {
1251 ValueView::Nil => 0u8.hash(state),
1252 ValueView::Bool(b) => {
1253 1u8.hash(state);
1254 b.hash(state);
1255 }
1256 ValueView::Int(n) => {
1257 2u8.hash(state);
1258 n.hash(state);
1259 }
1260 ValueView::Float(f) => {
1261 3u8.hash(state);
1262 f.to_bits().hash(state);
1263 }
1264 ValueView::String(s) => {
1265 4u8.hash(state);
1266 s.hash(state);
1267 }
1268 ValueView::Symbol(s) => {
1269 5u8.hash(state);
1270 s.hash(state);
1271 }
1272 ValueView::Keyword(s) => {
1273 6u8.hash(state);
1274 s.hash(state);
1275 }
1276 ValueView::Char(c) => {
1277 7u8.hash(state);
1278 c.hash(state);
1279 }
1280 ValueView::List(l) => {
1281 8u8.hash(state);
1282 l.hash(state);
1283 }
1284 ValueView::Vector(v) => {
1285 9u8.hash(state);
1286 v.hash(state);
1287 }
1288 ValueView::Record(r) => {
1289 10u8.hash(state);
1290 r.type_tag.hash(state);
1291 r.fields.hash(state);
1292 }
1293 ValueView::Bytevector(bv) => {
1294 11u8.hash(state);
1295 bv.hash(state);
1296 }
1297 _ => {}
1298 }
1299 }
1300}
1301
1302impl PartialOrd for Value {
1305 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1306 Some(self.cmp(other))
1307 }
1308}
1309
1310impl Ord for Value {
1311 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1312 use std::cmp::Ordering;
1313 fn type_order(v: &Value) -> u8 {
1314 match v.view() {
1315 ValueView::Nil => 0,
1316 ValueView::Bool(_) => 1,
1317 ValueView::Int(_) => 2,
1318 ValueView::Float(_) => 3,
1319 ValueView::Char(_) => 4,
1320 ValueView::String(_) => 5,
1321 ValueView::Symbol(_) => 6,
1322 ValueView::Keyword(_) => 7,
1323 ValueView::List(_) => 8,
1324 ValueView::Vector(_) => 9,
1325 ValueView::Map(_) => 10,
1326 ValueView::HashMap(_) => 11,
1327 ValueView::Record(_) => 12,
1328 ValueView::Bytevector(_) => 13,
1329 _ => 14,
1330 }
1331 }
1332 match (self.view(), other.view()) {
1333 (ValueView::Nil, ValueView::Nil) => Ordering::Equal,
1334 (ValueView::Bool(a), ValueView::Bool(b)) => a.cmp(&b),
1335 (ValueView::Int(a), ValueView::Int(b)) => a.cmp(&b),
1336 (ValueView::Float(a), ValueView::Float(b)) => a.to_bits().cmp(&b.to_bits()),
1337 (ValueView::String(a), ValueView::String(b)) => a.cmp(&b),
1338 (ValueView::Symbol(a), ValueView::Symbol(b)) => compare_spurs(a, b),
1339 (ValueView::Keyword(a), ValueView::Keyword(b)) => compare_spurs(a, b),
1340 (ValueView::Char(a), ValueView::Char(b)) => a.cmp(&b),
1341 (ValueView::List(a), ValueView::List(b)) => a.cmp(&b),
1342 (ValueView::Vector(a), ValueView::Vector(b)) => a.cmp(&b),
1343 (ValueView::Record(a), ValueView::Record(b)) => {
1344 compare_spurs(a.type_tag, b.type_tag).then_with(|| a.fields.cmp(&b.fields))
1345 }
1346 (ValueView::Bytevector(a), ValueView::Bytevector(b)) => a.cmp(&b),
1347 _ => type_order(self).cmp(&type_order(other)),
1348 }
1349 }
1350}
1351
1352fn truncate(s: &str, max: usize) -> String {
1355 let mut iter = s.chars();
1356 let prefix: String = iter.by_ref().take(max).collect();
1357 if iter.next().is_none() {
1358 prefix
1359 } else {
1360 format!("{prefix}...")
1361 }
1362}
1363
1364impl fmt::Display for Value {
1365 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1366 match self.view() {
1367 ValueView::Nil => write!(f, "nil"),
1368 ValueView::Bool(true) => write!(f, "#t"),
1369 ValueView::Bool(false) => write!(f, "#f"),
1370 ValueView::Int(n) => write!(f, "{n}"),
1371 ValueView::Float(n) => {
1372 if n.fract() == 0.0 {
1373 write!(f, "{n:.1}")
1374 } else {
1375 write!(f, "{n}")
1376 }
1377 }
1378 ValueView::String(s) => write!(f, "\"{s}\""),
1379 ValueView::Symbol(s) => with_resolved(s, |name| write!(f, "{name}")),
1380 ValueView::Keyword(s) => with_resolved(s, |name| write!(f, ":{name}")),
1381 ValueView::Char(c) => match c {
1382 ' ' => write!(f, "#\\space"),
1383 '\n' => write!(f, "#\\newline"),
1384 '\t' => write!(f, "#\\tab"),
1385 '\r' => write!(f, "#\\return"),
1386 '\0' => write!(f, "#\\nul"),
1387 _ => write!(f, "#\\{c}"),
1388 },
1389 ValueView::List(items) => {
1390 write!(f, "(")?;
1391 for (i, item) in items.iter().enumerate() {
1392 if i > 0 {
1393 write!(f, " ")?;
1394 }
1395 write!(f, "{item}")?;
1396 }
1397 write!(f, ")")
1398 }
1399 ValueView::Vector(items) => {
1400 write!(f, "[")?;
1401 for (i, item) in items.iter().enumerate() {
1402 if i > 0 {
1403 write!(f, " ")?;
1404 }
1405 write!(f, "{item}")?;
1406 }
1407 write!(f, "]")
1408 }
1409 ValueView::Map(map) => {
1410 write!(f, "{{")?;
1411 for (i, (k, v)) in map.iter().enumerate() {
1412 if i > 0 {
1413 write!(f, " ")?;
1414 }
1415 write!(f, "{k} {v}")?;
1416 }
1417 write!(f, "}}")
1418 }
1419 ValueView::HashMap(map) => {
1420 let mut entries: Vec<_> = map.iter().collect();
1421 entries.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
1422 write!(f, "{{")?;
1423 for (i, (k, v)) in entries.iter().enumerate() {
1424 if i > 0 {
1425 write!(f, " ")?;
1426 }
1427 write!(f, "{k} {v}")?;
1428 }
1429 write!(f, "}}")
1430 }
1431 ValueView::Lambda(l) => {
1432 if let Some(name) = &l.name {
1433 with_resolved(*name, |n| write!(f, "<lambda {n}>"))
1434 } else {
1435 write!(f, "<lambda>")
1436 }
1437 }
1438 ValueView::Macro(m) => with_resolved(m.name, |n| write!(f, "<macro {n}>")),
1439 ValueView::NativeFn(n) => write!(f, "<native-fn {}>", n.name),
1440 ValueView::Prompt(p) => write!(f, "<prompt {} messages>", p.messages.len()),
1441 ValueView::Message(m) => {
1442 write!(f, "<message {} \"{}\">", m.role, truncate(&m.content, 40))
1443 }
1444 ValueView::Conversation(c) => {
1445 write!(f, "<conversation {} messages>", c.messages.len())
1446 }
1447 ValueView::ToolDef(t) => write!(f, "<tool {}>", t.name),
1448 ValueView::Agent(a) => write!(f, "<agent {}>", a.name),
1449 ValueView::Thunk(t) => {
1450 if t.forced.borrow().is_some() {
1451 write!(f, "<promise (forced)>")
1452 } else {
1453 write!(f, "<promise>")
1454 }
1455 }
1456 ValueView::Record(r) => {
1457 with_resolved(r.type_tag, |tag| write!(f, "#<record {tag}"))?;
1458 for field in &r.fields {
1459 write!(f, " {field}")?;
1460 }
1461 write!(f, ">")
1462 }
1463 ValueView::Bytevector(bv) => {
1464 write!(f, "#u8(")?;
1465 for (i, byte) in bv.iter().enumerate() {
1466 if i > 0 {
1467 write!(f, " ")?;
1468 }
1469 write!(f, "{byte}")?;
1470 }
1471 write!(f, ")")
1472 }
1473 }
1474 }
1475}
1476
1477pub fn pretty_print(value: &Value, max_width: usize) -> String {
1483 let compact = format!("{value}");
1484 if compact.len() <= max_width {
1485 return compact;
1486 }
1487 let mut buf = String::new();
1488 pp_value(value, 0, max_width, &mut buf);
1489 buf
1490}
1491
1492fn pp_value(value: &Value, indent: usize, max_width: usize, buf: &mut String) {
1496 let compact = format!("{value}");
1497 let remaining = max_width.saturating_sub(indent);
1498 if compact.len() <= remaining {
1499 buf.push_str(&compact);
1500 return;
1501 }
1502
1503 match value.view() {
1504 ValueView::List(items) => {
1505 pp_seq(items.iter(), '(', ')', indent, max_width, buf);
1506 }
1507 ValueView::Vector(items) => {
1508 pp_seq(items.iter(), '[', ']', indent, max_width, buf);
1509 }
1510 ValueView::Map(map) => {
1511 pp_map(
1512 map.iter().map(|(k, v)| (k.clone(), v.clone())),
1513 indent,
1514 max_width,
1515 buf,
1516 );
1517 }
1518 ValueView::HashMap(map) => {
1519 let mut entries: Vec<_> = map.iter().map(|(k, v)| (k.clone(), v.clone())).collect();
1520 entries.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
1521 pp_map(entries.into_iter(), indent, max_width, buf);
1522 }
1523 _ => buf.push_str(&compact),
1524 }
1525}
1526
1527fn pp_seq<'a>(
1529 items: impl Iterator<Item = &'a Value>,
1530 open: char,
1531 close: char,
1532 indent: usize,
1533 max_width: usize,
1534 buf: &mut String,
1535) {
1536 buf.push(open);
1537 let child_indent = indent + 1;
1538 let pad = " ".repeat(child_indent);
1539 for (i, item) in items.enumerate() {
1540 if i > 0 {
1541 buf.push('\n');
1542 buf.push_str(&pad);
1543 }
1544 pp_value(item, child_indent, max_width, buf);
1545 }
1546 buf.push(close);
1547}
1548
1549fn pp_map(
1551 entries: impl Iterator<Item = (Value, Value)>,
1552 indent: usize,
1553 max_width: usize,
1554 buf: &mut String,
1555) {
1556 buf.push('{');
1557 let child_indent = indent + 1;
1558 let pad = " ".repeat(child_indent);
1559 for (i, (k, v)) in entries.enumerate() {
1560 if i > 0 {
1561 buf.push('\n');
1562 buf.push_str(&pad);
1563 }
1564 let key_str = format!("{k}");
1566 buf.push_str(&key_str);
1567
1568 let inline_indent = child_indent + key_str.len() + 1;
1570 let compact_val = format!("{v}");
1571 let remaining = max_width.saturating_sub(inline_indent);
1572
1573 if compact_val.len() <= remaining {
1574 buf.push(' ');
1576 buf.push_str(&compact_val);
1577 } else if is_compound(&v) {
1578 let nested_indent = child_indent + 2;
1580 let nested_pad = " ".repeat(nested_indent);
1581 buf.push('\n');
1582 buf.push_str(&nested_pad);
1583 pp_value(&v, nested_indent, max_width, buf);
1584 } else {
1585 buf.push(' ');
1587 buf.push_str(&compact_val);
1588 }
1589 }
1590 buf.push('}');
1591}
1592
1593fn is_compound(value: &Value) -> bool {
1595 matches!(
1596 value.view(),
1597 ValueView::List(_) | ValueView::Vector(_) | ValueView::Map(_) | ValueView::HashMap(_)
1598 )
1599}
1600
1601impl fmt::Debug for Value {
1604 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1605 match self.view() {
1606 ValueView::Nil => write!(f, "Nil"),
1607 ValueView::Bool(b) => write!(f, "Bool({b})"),
1608 ValueView::Int(n) => write!(f, "Int({n})"),
1609 ValueView::Float(n) => write!(f, "Float({n})"),
1610 ValueView::String(s) => write!(f, "String({:?})", &**s),
1611 ValueView::Symbol(s) => write!(f, "Symbol({})", resolve(s)),
1612 ValueView::Keyword(s) => write!(f, "Keyword({})", resolve(s)),
1613 ValueView::Char(c) => write!(f, "Char({c:?})"),
1614 ValueView::List(items) => write!(f, "List({items:?})"),
1615 ValueView::Vector(items) => write!(f, "Vector({items:?})"),
1616 ValueView::Map(map) => write!(f, "Map({map:?})"),
1617 ValueView::HashMap(map) => write!(f, "HashMap({map:?})"),
1618 ValueView::Lambda(l) => write!(f, "{l:?}"),
1619 ValueView::Macro(m) => write!(f, "{m:?}"),
1620 ValueView::NativeFn(n) => write!(f, "{n:?}"),
1621 ValueView::Prompt(p) => write!(f, "{p:?}"),
1622 ValueView::Message(m) => write!(f, "{m:?}"),
1623 ValueView::Conversation(c) => write!(f, "{c:?}"),
1624 ValueView::ToolDef(t) => write!(f, "{t:?}"),
1625 ValueView::Agent(a) => write!(f, "{a:?}"),
1626 ValueView::Thunk(t) => write!(f, "{t:?}"),
1627 ValueView::Record(r) => write!(f, "{r:?}"),
1628 ValueView::Bytevector(bv) => write!(f, "Bytevector({bv:?})"),
1629 }
1630 }
1631}
1632
1633#[derive(Debug, Clone)]
1637pub struct Env {
1638 pub bindings: Rc<RefCell<SpurMap<Spur, Value>>>,
1639 pub parent: Option<Rc<Env>>,
1640 pub version: Cell<u64>,
1641}
1642
1643impl Env {
1644 pub fn new() -> Self {
1645 Env {
1646 bindings: Rc::new(RefCell::new(SpurMap::new())),
1647 parent: None,
1648 version: Cell::new(0),
1649 }
1650 }
1651
1652 pub fn with_parent(parent: Rc<Env>) -> Self {
1653 Env {
1654 bindings: Rc::new(RefCell::new(SpurMap::new())),
1655 parent: Some(parent),
1656 version: Cell::new(0),
1657 }
1658 }
1659
1660 fn bump_version(&self) {
1661 self.version.set(self.version.get().wrapping_add(1));
1662 }
1663
1664 pub fn get(&self, name: Spur) -> Option<Value> {
1665 if let Some(val) = self.bindings.borrow().get(&name) {
1666 Some(val.clone())
1667 } else if let Some(parent) = &self.parent {
1668 parent.get(name)
1669 } else {
1670 None
1671 }
1672 }
1673
1674 pub fn get_str(&self, name: &str) -> Option<Value> {
1675 self.get(intern(name))
1676 }
1677
1678 pub fn set(&self, name: Spur, val: Value) {
1679 self.bindings.borrow_mut().insert(name, val);
1680 self.bump_version();
1681 }
1682
1683 pub fn set_str(&self, name: &str, val: Value) {
1684 self.set(intern(name), val);
1685 }
1686
1687 pub fn update(&self, name: Spur, val: Value) {
1689 let mut bindings = self.bindings.borrow_mut();
1690 if let Some(entry) = bindings.get_mut(&name) {
1691 *entry = val;
1692 } else {
1693 bindings.insert(name, val);
1694 }
1695 drop(bindings);
1696 self.bump_version();
1697 }
1698
1699 pub fn take(&self, name: Spur) -> Option<Value> {
1701 let result = self.bindings.borrow_mut().remove(&name);
1702 if result.is_some() {
1703 self.bump_version();
1704 }
1705 result
1706 }
1707
1708 pub fn take_anywhere(&self, name: Spur) -> Option<Value> {
1710 if let Some(val) = self.bindings.borrow_mut().remove(&name) {
1711 self.bump_version();
1712 Some(val)
1713 } else if let Some(parent) = &self.parent {
1714 parent.take_anywhere(name)
1715 } else {
1716 None
1717 }
1718 }
1719
1720 pub fn set_existing(&self, name: Spur, val: Value) -> bool {
1722 let mut bindings = self.bindings.borrow_mut();
1723 if let Some(entry) = bindings.get_mut(&name) {
1724 *entry = val;
1725 drop(bindings);
1726 self.bump_version();
1727 true
1728 } else {
1729 drop(bindings);
1730 if let Some(parent) = &self.parent {
1731 parent.set_existing(name, val)
1732 } else {
1733 false
1734 }
1735 }
1736 }
1737}
1738
1739impl Default for Env {
1740 fn default() -> Self {
1741 Self::new()
1742 }
1743}
1744
1745#[cfg(test)]
1748mod tests {
1749 use super::*;
1750
1751 #[test]
1752 fn test_size_of_value() {
1753 assert_eq!(std::mem::size_of::<Value>(), 8);
1754 }
1755
1756 #[test]
1757 fn test_nil() {
1758 let v = Value::nil();
1759 assert!(v.is_nil());
1760 assert!(!v.is_truthy());
1761 assert_eq!(v.type_name(), "nil");
1762 assert_eq!(format!("{v}"), "nil");
1763 }
1764
1765 #[test]
1766 fn test_bool() {
1767 let t = Value::bool(true);
1768 let f = Value::bool(false);
1769 assert!(t.is_truthy());
1770 assert!(!f.is_truthy());
1771 assert_eq!(t.as_bool(), Some(true));
1772 assert_eq!(f.as_bool(), Some(false));
1773 assert_eq!(format!("{t}"), "#t");
1774 assert_eq!(format!("{f}"), "#f");
1775 }
1776
1777 #[test]
1778 fn test_small_int() {
1779 let v = Value::int(42);
1780 assert_eq!(v.as_int(), Some(42));
1781 assert_eq!(v.type_name(), "int");
1782 assert_eq!(format!("{v}"), "42");
1783
1784 let neg = Value::int(-100);
1785 assert_eq!(neg.as_int(), Some(-100));
1786 assert_eq!(format!("{neg}"), "-100");
1787
1788 let zero = Value::int(0);
1789 assert_eq!(zero.as_int(), Some(0));
1790 }
1791
1792 #[test]
1793 fn test_small_int_boundaries() {
1794 let max = Value::int(SMALL_INT_MAX);
1795 assert_eq!(max.as_int(), Some(SMALL_INT_MAX));
1796
1797 let min = Value::int(SMALL_INT_MIN);
1798 assert_eq!(min.as_int(), Some(SMALL_INT_MIN));
1799 }
1800
1801 #[test]
1802 fn test_big_int() {
1803 let big = Value::int(i64::MAX);
1804 assert_eq!(big.as_int(), Some(i64::MAX));
1805 assert_eq!(big.type_name(), "int");
1806
1807 let big_neg = Value::int(i64::MIN);
1808 assert_eq!(big_neg.as_int(), Some(i64::MIN));
1809
1810 let just_over = Value::int(SMALL_INT_MAX + 1);
1812 assert_eq!(just_over.as_int(), Some(SMALL_INT_MAX + 1));
1813 }
1814
1815 #[test]
1816 fn test_float() {
1817 let v = Value::float(3.14);
1818 assert_eq!(v.as_float(), Some(3.14));
1819 assert_eq!(v.type_name(), "float");
1820
1821 let neg = Value::float(-0.5);
1822 assert_eq!(neg.as_float(), Some(-0.5));
1823
1824 let inf = Value::float(f64::INFINITY);
1825 assert_eq!(inf.as_float(), Some(f64::INFINITY));
1826
1827 let neg_inf = Value::float(f64::NEG_INFINITY);
1828 assert_eq!(neg_inf.as_float(), Some(f64::NEG_INFINITY));
1829 }
1830
1831 #[test]
1832 fn test_float_nan() {
1833 let nan = Value::float(f64::NAN);
1834 let f = nan.as_float().unwrap();
1835 assert!(f.is_nan());
1836 }
1837
1838 #[test]
1839 fn test_string() {
1840 let v = Value::string("hello");
1841 assert_eq!(v.as_str(), Some("hello"));
1842 assert_eq!(v.type_name(), "string");
1843 assert_eq!(format!("{v}"), "\"hello\"");
1844 }
1845
1846 #[test]
1847 fn test_symbol() {
1848 let v = Value::symbol("foo");
1849 assert!(v.as_symbol_spur().is_some());
1850 assert_eq!(v.as_symbol(), Some("foo".to_string()));
1851 assert_eq!(v.type_name(), "symbol");
1852 assert_eq!(format!("{v}"), "foo");
1853 }
1854
1855 #[test]
1856 fn test_keyword() {
1857 let v = Value::keyword("bar");
1858 assert!(v.as_keyword_spur().is_some());
1859 assert_eq!(v.as_keyword(), Some("bar".to_string()));
1860 assert_eq!(v.type_name(), "keyword");
1861 assert_eq!(format!("{v}"), ":bar");
1862 }
1863
1864 #[test]
1865 fn test_char() {
1866 let v = Value::char('λ');
1867 assert_eq!(v.as_char(), Some('λ'));
1868 assert_eq!(v.type_name(), "char");
1869 }
1870
1871 #[test]
1872 fn test_list() {
1873 let v = Value::list(vec![Value::int(1), Value::int(2), Value::int(3)]);
1874 assert_eq!(v.as_list().unwrap().len(), 3);
1875 assert_eq!(v.type_name(), "list");
1876 assert_eq!(format!("{v}"), "(1 2 3)");
1877 }
1878
1879 #[test]
1880 fn test_clone_immediate() {
1881 let v = Value::int(42);
1882 let v2 = v.clone();
1883 assert_eq!(v.as_int(), v2.as_int());
1884 }
1885
1886 #[test]
1887 fn test_clone_heap() {
1888 let v = Value::string("hello");
1889 let v2 = v.clone();
1890 assert_eq!(v.as_str(), v2.as_str());
1891 assert_eq!(format!("{v}"), format!("{v2}"));
1893 }
1894
1895 #[test]
1896 fn test_equality() {
1897 assert_eq!(Value::int(42), Value::int(42));
1898 assert_ne!(Value::int(42), Value::int(43));
1899 assert_eq!(Value::nil(), Value::nil());
1900 assert_eq!(Value::bool(true), Value::bool(true));
1901 assert_ne!(Value::bool(true), Value::bool(false));
1902 assert_eq!(Value::string("a"), Value::string("a"));
1903 assert_ne!(Value::string("a"), Value::string("b"));
1904 assert_eq!(Value::symbol("x"), Value::symbol("x"));
1905 }
1906
1907 #[test]
1908 fn test_big_int_equality() {
1909 assert_eq!(Value::int(i64::MAX), Value::int(i64::MAX));
1910 assert_ne!(Value::int(i64::MAX), Value::int(i64::MIN));
1911 }
1912
1913 #[test]
1914 fn test_view_pattern_matching() {
1915 let v = Value::int(42);
1916 match v.view() {
1917 ValueView::Int(n) => assert_eq!(n, 42),
1918 _ => panic!("expected int"),
1919 }
1920
1921 let v = Value::string("hello");
1922 match v.view() {
1923 ValueView::String(s) => assert_eq!(&**s, "hello"),
1924 _ => panic!("expected string"),
1925 }
1926 }
1927
1928 #[test]
1929 fn test_env() {
1930 let env = Env::new();
1931 env.set_str("x", Value::int(42));
1932 assert_eq!(env.get_str("x"), Some(Value::int(42)));
1933 }
1934
1935 #[test]
1936 fn test_native_fn_simple() {
1937 let f = NativeFn::simple("add1", |args| Ok(args[0].clone()));
1938 let ctx = EvalContext::new();
1939 assert!((f.func)(&ctx, &[Value::int(42)]).is_ok());
1940 }
1941
1942 #[test]
1943 fn test_native_fn_with_ctx() {
1944 let f = NativeFn::with_ctx("get-depth", |ctx, _args| {
1945 Ok(Value::int(ctx.eval_depth.get() as i64))
1946 });
1947 let ctx = EvalContext::new();
1948 assert_eq!((f.func)(&ctx, &[]).unwrap(), Value::int(0));
1949 }
1950
1951 #[test]
1952 fn test_drop_doesnt_leak() {
1953 for _ in 0..10000 {
1955 let _ = Value::string("test");
1956 let _ = Value::list(vec![Value::int(1), Value::int(2)]);
1957 let _ = Value::int(i64::MAX); }
1959 }
1960
1961 #[test]
1962 fn test_is_truthy() {
1963 assert!(!Value::nil().is_truthy());
1964 assert!(!Value::bool(false).is_truthy());
1965 assert!(Value::bool(true).is_truthy());
1966 assert!(Value::int(0).is_truthy());
1967 assert!(Value::int(1).is_truthy());
1968 assert!(Value::string("").is_truthy());
1969 assert!(Value::list(vec![]).is_truthy());
1970 }
1971
1972 #[test]
1973 fn test_as_float_from_int() {
1974 assert_eq!(Value::int(42).as_float(), Some(42.0));
1975 assert_eq!(Value::float(3.14).as_float(), Some(3.14));
1976 }
1977}