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 TAG_MASK_6BIT: u64 = 0x3F;
262
263const CANONICAL_NAN: u64 = 0x7FF8_0000_0000_0000;
265
266const TAG_NIL: u64 = 0;
268const TAG_FALSE: u64 = 1;
269const TAG_TRUE: u64 = 2;
270const TAG_INT_SMALL: u64 = 3;
271const TAG_CHAR: u64 = 4;
272const TAG_SYMBOL: u64 = 5;
273const TAG_KEYWORD: u64 = 6;
274const TAG_INT_BIG: u64 = 7;
275const TAG_STRING: u64 = 8;
276const TAG_LIST: u64 = 9;
277const TAG_VECTOR: u64 = 10;
278const TAG_MAP: u64 = 11;
279const TAG_HASHMAP: u64 = 12;
280const TAG_LAMBDA: u64 = 13;
281const TAG_MACRO: u64 = 14;
282pub const TAG_NATIVE_FN: u64 = 15;
283const TAG_PROMPT: u64 = 16;
284const TAG_MESSAGE: u64 = 17;
285const TAG_CONVERSATION: u64 = 18;
286const TAG_TOOL_DEF: u64 = 19;
287const TAG_AGENT: u64 = 20;
288const TAG_THUNK: u64 = 21;
289const TAG_RECORD: u64 = 22;
290const TAG_BYTEVECTOR: u64 = 23;
291
292const SMALL_INT_MIN: i64 = -(1i64 << 44);
294const SMALL_INT_MAX: i64 = (1i64 << 44) - 1;
295
296pub const NAN_TAG_MASK: u64 = BOX_MASK | (TAG_MASK_6BIT << 45); pub const NAN_INT_SMALL_PATTERN: u64 = BOX_MASK | (TAG_INT_SMALL << 45);
303
304pub const NAN_PAYLOAD_MASK: u64 = PAYLOAD_MASK;
306
307pub const NAN_INT_SIGN_BIT: u64 = INT_SIGN_BIT;
309
310pub const NAN_PAYLOAD_BITS: u32 = 45;
312
313#[inline(always)]
316fn make_boxed(tag: u64, payload: u64) -> u64 {
317 BOX_MASK | (tag << 45) | (payload & PAYLOAD_MASK)
318}
319
320#[inline(always)]
321fn is_boxed(bits: u64) -> bool {
322 (bits & BOX_MASK) == BOX_MASK
323}
324
325#[inline(always)]
326fn get_tag(bits: u64) -> u64 {
327 (bits >> 45) & TAG_MASK_6BIT
328}
329
330#[inline(always)]
331fn get_payload(bits: u64) -> u64 {
332 bits & PAYLOAD_MASK
333}
334
335#[inline(always)]
336fn ptr_to_payload(ptr: *const u8) -> u64 {
337 let raw = ptr as u64;
338 debug_assert!(raw & 0x7 == 0, "pointer not 8-byte aligned: 0x{:x}", raw);
339 debug_assert!(
340 raw >> 48 == 0,
341 "pointer exceeds 48-bit VA space: 0x{:x}",
342 raw
343 );
344 raw >> 3
345}
346
347#[inline(always)]
348fn payload_to_ptr(payload: u64) -> *const u8 {
349 (payload << 3) as *const u8
350}
351
352pub enum ValueView {
357 Nil,
358 Bool(bool),
359 Int(i64),
360 Float(f64),
361 String(Rc<String>),
362 Symbol(Spur),
363 Keyword(Spur),
364 Char(char),
365 List(Rc<Vec<Value>>),
366 Vector(Rc<Vec<Value>>),
367 Map(Rc<BTreeMap<Value, Value>>),
368 HashMap(Rc<hashbrown::HashMap<Value, Value>>),
369 Lambda(Rc<Lambda>),
370 Macro(Rc<Macro>),
371 NativeFn(Rc<NativeFn>),
372 Prompt(Rc<Prompt>),
373 Message(Rc<Message>),
374 Conversation(Rc<Conversation>),
375 ToolDef(Rc<ToolDefinition>),
376 Agent(Rc<Agent>),
377 Thunk(Rc<Thunk>),
378 Record(Rc<Record>),
379 Bytevector(Rc<Vec<u8>>),
380}
381
382#[repr(transparent)]
388pub struct Value(u64);
389
390impl Value {
393 pub const NIL: Value = Value(make_boxed_const(TAG_NIL, 0));
396 pub const TRUE: Value = Value(make_boxed_const(TAG_TRUE, 0));
397 pub const FALSE: Value = Value(make_boxed_const(TAG_FALSE, 0));
398
399 #[inline(always)]
400 pub fn nil() -> Value {
401 Value::NIL
402 }
403
404 #[inline(always)]
405 pub fn bool(b: bool) -> Value {
406 if b {
407 Value::TRUE
408 } else {
409 Value::FALSE
410 }
411 }
412
413 #[inline(always)]
414 pub fn int(n: i64) -> Value {
415 if (SMALL_INT_MIN..=SMALL_INT_MAX).contains(&n) {
416 let payload = (n as u64) & PAYLOAD_MASK;
418 Value(make_boxed(TAG_INT_SMALL, payload))
419 } else {
420 let rc = Rc::new(n);
422 let ptr = Rc::into_raw(rc) as *const u8;
423 Value(make_boxed(TAG_INT_BIG, ptr_to_payload(ptr)))
424 }
425 }
426
427 #[inline(always)]
428 pub fn float(f: f64) -> Value {
429 let bits = f.to_bits();
430 if f.is_nan() {
431 Value(CANONICAL_NAN)
433 } else {
434 debug_assert!(
441 !is_boxed(bits),
442 "non-NaN float collides with boxed pattern: {:?} = 0x{:016x}",
443 f,
444 bits
445 );
446 Value(bits)
447 }
448 }
449
450 #[inline(always)]
451 pub fn char(c: char) -> Value {
452 Value(make_boxed(TAG_CHAR, c as u64))
453 }
454
455 #[inline(always)]
456 pub fn symbol_from_spur(spur: Spur) -> Value {
457 let bits: u32 = unsafe { std::mem::transmute(spur) };
458 Value(make_boxed(TAG_SYMBOL, bits as u64))
459 }
460
461 pub fn symbol(s: &str) -> Value {
462 Value::symbol_from_spur(intern(s))
463 }
464
465 #[inline(always)]
466 pub fn keyword_from_spur(spur: Spur) -> Value {
467 let bits: u32 = unsafe { std::mem::transmute(spur) };
468 Value(make_boxed(TAG_KEYWORD, bits as u64))
469 }
470
471 pub fn keyword(s: &str) -> Value {
472 Value::keyword_from_spur(intern(s))
473 }
474
475 fn from_rc_ptr<T>(tag: u64, rc: Rc<T>) -> Value {
478 let ptr = Rc::into_raw(rc) as *const u8;
479 Value(make_boxed(tag, ptr_to_payload(ptr)))
480 }
481
482 pub fn string(s: &str) -> Value {
483 Value::from_rc_ptr(TAG_STRING, Rc::new(s.to_string()))
484 }
485
486 pub fn string_from_rc(rc: Rc<String>) -> Value {
487 Value::from_rc_ptr(TAG_STRING, rc)
488 }
489
490 pub fn list(v: Vec<Value>) -> Value {
491 Value::from_rc_ptr(TAG_LIST, Rc::new(v))
492 }
493
494 pub fn list_from_rc(rc: Rc<Vec<Value>>) -> Value {
495 Value::from_rc_ptr(TAG_LIST, rc)
496 }
497
498 pub fn vector(v: Vec<Value>) -> Value {
499 Value::from_rc_ptr(TAG_VECTOR, Rc::new(v))
500 }
501
502 pub fn vector_from_rc(rc: Rc<Vec<Value>>) -> Value {
503 Value::from_rc_ptr(TAG_VECTOR, rc)
504 }
505
506 pub fn map(m: BTreeMap<Value, Value>) -> Value {
507 Value::from_rc_ptr(TAG_MAP, Rc::new(m))
508 }
509
510 pub fn map_from_rc(rc: Rc<BTreeMap<Value, Value>>) -> Value {
511 Value::from_rc_ptr(TAG_MAP, rc)
512 }
513
514 pub fn hashmap(entries: Vec<(Value, Value)>) -> Value {
515 let map: hashbrown::HashMap<Value, Value> = entries.into_iter().collect();
516 Value::from_rc_ptr(TAG_HASHMAP, Rc::new(map))
517 }
518
519 pub fn hashmap_from_rc(rc: Rc<hashbrown::HashMap<Value, Value>>) -> Value {
520 Value::from_rc_ptr(TAG_HASHMAP, rc)
521 }
522
523 pub fn lambda(l: Lambda) -> Value {
524 Value::from_rc_ptr(TAG_LAMBDA, Rc::new(l))
525 }
526
527 pub fn lambda_from_rc(rc: Rc<Lambda>) -> Value {
528 Value::from_rc_ptr(TAG_LAMBDA, rc)
529 }
530
531 pub fn macro_val(m: Macro) -> Value {
532 Value::from_rc_ptr(TAG_MACRO, Rc::new(m))
533 }
534
535 pub fn macro_from_rc(rc: Rc<Macro>) -> Value {
536 Value::from_rc_ptr(TAG_MACRO, rc)
537 }
538
539 pub fn native_fn(f: NativeFn) -> Value {
540 Value::from_rc_ptr(TAG_NATIVE_FN, Rc::new(f))
541 }
542
543 pub fn native_fn_from_rc(rc: Rc<NativeFn>) -> Value {
544 Value::from_rc_ptr(TAG_NATIVE_FN, rc)
545 }
546
547 pub fn prompt(p: Prompt) -> Value {
548 Value::from_rc_ptr(TAG_PROMPT, Rc::new(p))
549 }
550
551 pub fn prompt_from_rc(rc: Rc<Prompt>) -> Value {
552 Value::from_rc_ptr(TAG_PROMPT, rc)
553 }
554
555 pub fn message(m: Message) -> Value {
556 Value::from_rc_ptr(TAG_MESSAGE, Rc::new(m))
557 }
558
559 pub fn message_from_rc(rc: Rc<Message>) -> Value {
560 Value::from_rc_ptr(TAG_MESSAGE, rc)
561 }
562
563 pub fn conversation(c: Conversation) -> Value {
564 Value::from_rc_ptr(TAG_CONVERSATION, Rc::new(c))
565 }
566
567 pub fn conversation_from_rc(rc: Rc<Conversation>) -> Value {
568 Value::from_rc_ptr(TAG_CONVERSATION, rc)
569 }
570
571 pub fn tool_def(t: ToolDefinition) -> Value {
572 Value::from_rc_ptr(TAG_TOOL_DEF, Rc::new(t))
573 }
574
575 pub fn tool_def_from_rc(rc: Rc<ToolDefinition>) -> Value {
576 Value::from_rc_ptr(TAG_TOOL_DEF, rc)
577 }
578
579 pub fn agent(a: Agent) -> Value {
580 Value::from_rc_ptr(TAG_AGENT, Rc::new(a))
581 }
582
583 pub fn agent_from_rc(rc: Rc<Agent>) -> Value {
584 Value::from_rc_ptr(TAG_AGENT, rc)
585 }
586
587 pub fn thunk(t: Thunk) -> Value {
588 Value::from_rc_ptr(TAG_THUNK, Rc::new(t))
589 }
590
591 pub fn thunk_from_rc(rc: Rc<Thunk>) -> Value {
592 Value::from_rc_ptr(TAG_THUNK, rc)
593 }
594
595 pub fn record(r: Record) -> Value {
596 Value::from_rc_ptr(TAG_RECORD, Rc::new(r))
597 }
598
599 pub fn record_from_rc(rc: Rc<Record>) -> Value {
600 Value::from_rc_ptr(TAG_RECORD, rc)
601 }
602
603 pub fn bytevector(bytes: Vec<u8>) -> Value {
604 Value::from_rc_ptr(TAG_BYTEVECTOR, Rc::new(bytes))
605 }
606
607 pub fn bytevector_from_rc(rc: Rc<Vec<u8>>) -> Value {
608 Value::from_rc_ptr(TAG_BYTEVECTOR, rc)
609 }
610}
611
612const fn make_boxed_const(tag: u64, payload: u64) -> u64 {
614 BOX_MASK | (tag << 45) | (payload & PAYLOAD_MASK)
615}
616
617impl Value {
620 #[inline(always)]
622 pub fn raw_bits(&self) -> u64 {
623 self.0
624 }
625
626 #[inline(always)]
635 pub unsafe fn from_raw_bits(bits: u64) -> Value {
636 Value(bits)
637 }
638
639 #[inline(always)]
642 pub fn raw_tag(&self) -> Option<u64> {
643 if is_boxed(self.0) {
644 Some(get_tag(self.0))
645 } else {
646 None
647 }
648 }
649
650 #[inline(always)]
653 pub fn as_native_fn_ref(&self) -> Option<&NativeFn> {
654 if is_boxed(self.0) && get_tag(self.0) == TAG_NATIVE_FN {
655 Some(unsafe { self.borrow_ref::<NativeFn>() })
656 } else {
657 None
658 }
659 }
660
661 #[inline(always)]
663 pub fn is_float(&self) -> bool {
664 !is_boxed(self.0)
665 }
666
667 #[inline(always)]
670 unsafe fn get_rc<T>(&self) -> Rc<T> {
671 let payload = get_payload(self.0);
672 let ptr = payload_to_ptr(payload) as *const T;
673 Rc::increment_strong_count(ptr);
674 Rc::from_raw(ptr)
675 }
676
677 #[inline(always)]
680 unsafe fn borrow_ref<T>(&self) -> &T {
681 let payload = get_payload(self.0);
682 let ptr = payload_to_ptr(payload) as *const T;
683 &*ptr
684 }
685
686 pub fn view(&self) -> ValueView {
689 if !is_boxed(self.0) {
690 return ValueView::Float(f64::from_bits(self.0));
691 }
692 let tag = get_tag(self.0);
693 match tag {
694 TAG_NIL => ValueView::Nil,
695 TAG_FALSE => ValueView::Bool(false),
696 TAG_TRUE => ValueView::Bool(true),
697 TAG_INT_SMALL => {
698 let payload = get_payload(self.0);
699 let val = if payload & INT_SIGN_BIT != 0 {
700 (payload | !PAYLOAD_MASK) as i64
701 } else {
702 payload as i64
703 };
704 ValueView::Int(val)
705 }
706 TAG_CHAR => {
707 let payload = get_payload(self.0);
708 ValueView::Char(unsafe { char::from_u32_unchecked(payload as u32) })
709 }
710 TAG_SYMBOL => {
711 let payload = get_payload(self.0);
712 let spur: Spur = unsafe { std::mem::transmute(payload as u32) };
713 ValueView::Symbol(spur)
714 }
715 TAG_KEYWORD => {
716 let payload = get_payload(self.0);
717 let spur: Spur = unsafe { std::mem::transmute(payload as u32) };
718 ValueView::Keyword(spur)
719 }
720 TAG_INT_BIG => {
721 let val = unsafe { *self.borrow_ref::<i64>() };
722 ValueView::Int(val)
723 }
724 TAG_STRING => ValueView::String(unsafe { self.get_rc::<String>() }),
725 TAG_LIST => ValueView::List(unsafe { self.get_rc::<Vec<Value>>() }),
726 TAG_VECTOR => ValueView::Vector(unsafe { self.get_rc::<Vec<Value>>() }),
727 TAG_MAP => ValueView::Map(unsafe { self.get_rc::<BTreeMap<Value, Value>>() }),
728 TAG_HASHMAP => {
729 ValueView::HashMap(unsafe { self.get_rc::<hashbrown::HashMap<Value, Value>>() })
730 }
731 TAG_LAMBDA => ValueView::Lambda(unsafe { self.get_rc::<Lambda>() }),
732 TAG_MACRO => ValueView::Macro(unsafe { self.get_rc::<Macro>() }),
733 TAG_NATIVE_FN => ValueView::NativeFn(unsafe { self.get_rc::<NativeFn>() }),
734 TAG_PROMPT => ValueView::Prompt(unsafe { self.get_rc::<Prompt>() }),
735 TAG_MESSAGE => ValueView::Message(unsafe { self.get_rc::<Message>() }),
736 TAG_CONVERSATION => ValueView::Conversation(unsafe { self.get_rc::<Conversation>() }),
737 TAG_TOOL_DEF => ValueView::ToolDef(unsafe { self.get_rc::<ToolDefinition>() }),
738 TAG_AGENT => ValueView::Agent(unsafe { self.get_rc::<Agent>() }),
739 TAG_THUNK => ValueView::Thunk(unsafe { self.get_rc::<Thunk>() }),
740 TAG_RECORD => ValueView::Record(unsafe { self.get_rc::<Record>() }),
741 TAG_BYTEVECTOR => ValueView::Bytevector(unsafe { self.get_rc::<Vec<u8>>() }),
742 _ => unreachable!("invalid NaN-boxed tag: {}", tag),
743 }
744 }
745
746 pub fn type_name(&self) -> &'static str {
749 if !is_boxed(self.0) {
750 return "float";
751 }
752 match get_tag(self.0) {
753 TAG_NIL => "nil",
754 TAG_FALSE | TAG_TRUE => "bool",
755 TAG_INT_SMALL | TAG_INT_BIG => "int",
756 TAG_CHAR => "char",
757 TAG_SYMBOL => "symbol",
758 TAG_KEYWORD => "keyword",
759 TAG_STRING => "string",
760 TAG_LIST => "list",
761 TAG_VECTOR => "vector",
762 TAG_MAP => "map",
763 TAG_HASHMAP => "hashmap",
764 TAG_LAMBDA => "lambda",
765 TAG_MACRO => "macro",
766 TAG_NATIVE_FN => "native-fn",
767 TAG_PROMPT => "prompt",
768 TAG_MESSAGE => "message",
769 TAG_CONVERSATION => "conversation",
770 TAG_TOOL_DEF => "tool",
771 TAG_AGENT => "agent",
772 TAG_THUNK => "promise",
773 TAG_RECORD => "record",
774 TAG_BYTEVECTOR => "bytevector",
775 _ => "unknown",
776 }
777 }
778
779 #[inline(always)]
780 pub fn is_nil(&self) -> bool {
781 self.0 == Value::NIL.0
782 }
783
784 #[inline(always)]
785 pub fn is_truthy(&self) -> bool {
786 self.0 != Value::NIL.0 && self.0 != Value::FALSE.0
787 }
788
789 #[inline(always)]
790 pub fn is_bool(&self) -> bool {
791 self.0 == Value::TRUE.0 || self.0 == Value::FALSE.0
792 }
793
794 #[inline(always)]
795 pub fn is_int(&self) -> bool {
796 is_boxed(self.0) && matches!(get_tag(self.0), TAG_INT_SMALL | TAG_INT_BIG)
797 }
798
799 #[inline(always)]
800 pub fn is_symbol(&self) -> bool {
801 is_boxed(self.0) && get_tag(self.0) == TAG_SYMBOL
802 }
803
804 #[inline(always)]
805 pub fn is_keyword(&self) -> bool {
806 is_boxed(self.0) && get_tag(self.0) == TAG_KEYWORD
807 }
808
809 #[inline(always)]
810 pub fn is_string(&self) -> bool {
811 is_boxed(self.0) && get_tag(self.0) == TAG_STRING
812 }
813
814 #[inline(always)]
815 pub fn is_list(&self) -> bool {
816 is_boxed(self.0) && get_tag(self.0) == TAG_LIST
817 }
818
819 #[inline(always)]
820 pub fn is_pair(&self) -> bool {
821 if let Some(items) = self.as_list() {
822 !items.is_empty()
823 } else {
824 false
825 }
826 }
827
828 #[inline(always)]
829 pub fn is_vector(&self) -> bool {
830 is_boxed(self.0) && get_tag(self.0) == TAG_VECTOR
831 }
832
833 #[inline(always)]
834 pub fn is_map(&self) -> bool {
835 is_boxed(self.0) && matches!(get_tag(self.0), TAG_MAP | TAG_HASHMAP)
836 }
837
838 #[inline(always)]
839 pub fn is_lambda(&self) -> bool {
840 is_boxed(self.0) && get_tag(self.0) == TAG_LAMBDA
841 }
842
843 #[inline(always)]
844 pub fn is_native_fn(&self) -> bool {
845 is_boxed(self.0) && get_tag(self.0) == TAG_NATIVE_FN
846 }
847
848 #[inline(always)]
849 pub fn is_thunk(&self) -> bool {
850 is_boxed(self.0) && get_tag(self.0) == TAG_THUNK
851 }
852
853 #[inline(always)]
854 pub fn is_record(&self) -> bool {
855 is_boxed(self.0) && get_tag(self.0) == TAG_RECORD
856 }
857
858 #[inline(always)]
859 pub fn as_int(&self) -> Option<i64> {
860 if !is_boxed(self.0) {
861 return None;
862 }
863 match get_tag(self.0) {
864 TAG_INT_SMALL => {
865 let payload = get_payload(self.0);
866 let val = if payload & INT_SIGN_BIT != 0 {
867 (payload | !PAYLOAD_MASK) as i64
868 } else {
869 payload as i64
870 };
871 Some(val)
872 }
873 TAG_INT_BIG => Some(unsafe { *self.borrow_ref::<i64>() }),
874 _ => None,
875 }
876 }
877
878 #[inline(always)]
879 pub fn as_float(&self) -> Option<f64> {
880 if !is_boxed(self.0) {
881 return Some(f64::from_bits(self.0));
882 }
883 match get_tag(self.0) {
884 TAG_INT_SMALL => {
885 let payload = get_payload(self.0);
886 let val = if payload & INT_SIGN_BIT != 0 {
887 (payload | !PAYLOAD_MASK) as i64
888 } else {
889 payload as i64
890 };
891 Some(val as f64)
892 }
893 TAG_INT_BIG => Some(unsafe { *self.borrow_ref::<i64>() } as f64),
894 _ => None,
895 }
896 }
897
898 #[inline(always)]
899 pub fn as_bool(&self) -> Option<bool> {
900 if self.0 == Value::TRUE.0 {
901 Some(true)
902 } else if self.0 == Value::FALSE.0 {
903 Some(false)
904 } else {
905 None
906 }
907 }
908
909 pub fn as_str(&self) -> Option<&str> {
910 if is_boxed(self.0) && get_tag(self.0) == TAG_STRING {
911 Some(unsafe { self.borrow_ref::<String>() })
912 } else {
913 None
914 }
915 }
916
917 pub fn as_string_rc(&self) -> Option<Rc<String>> {
918 if is_boxed(self.0) && get_tag(self.0) == TAG_STRING {
919 Some(unsafe { self.get_rc::<String>() })
920 } else {
921 None
922 }
923 }
924
925 pub fn as_symbol(&self) -> Option<String> {
926 self.as_symbol_spur().map(resolve)
927 }
928
929 pub fn as_symbol_spur(&self) -> Option<Spur> {
930 if is_boxed(self.0) && get_tag(self.0) == TAG_SYMBOL {
931 let payload = get_payload(self.0);
932 Some(unsafe { std::mem::transmute::<u32, Spur>(payload as u32) })
933 } else {
934 None
935 }
936 }
937
938 pub fn as_keyword(&self) -> Option<String> {
939 self.as_keyword_spur().map(resolve)
940 }
941
942 pub fn as_keyword_spur(&self) -> Option<Spur> {
943 if is_boxed(self.0) && get_tag(self.0) == TAG_KEYWORD {
944 let payload = get_payload(self.0);
945 Some(unsafe { std::mem::transmute::<u32, Spur>(payload as u32) })
946 } else {
947 None
948 }
949 }
950
951 pub fn as_char(&self) -> Option<char> {
952 if is_boxed(self.0) && get_tag(self.0) == TAG_CHAR {
953 let payload = get_payload(self.0);
954 char::from_u32(payload as u32)
955 } else {
956 None
957 }
958 }
959
960 pub fn as_list(&self) -> Option<&[Value]> {
961 if is_boxed(self.0) && get_tag(self.0) == TAG_LIST {
962 Some(unsafe { self.borrow_ref::<Vec<Value>>() })
963 } else {
964 None
965 }
966 }
967
968 pub fn as_list_rc(&self) -> Option<Rc<Vec<Value>>> {
969 if is_boxed(self.0) && get_tag(self.0) == TAG_LIST {
970 Some(unsafe { self.get_rc::<Vec<Value>>() })
971 } else {
972 None
973 }
974 }
975
976 pub fn as_vector(&self) -> Option<&[Value]> {
977 if is_boxed(self.0) && get_tag(self.0) == TAG_VECTOR {
978 Some(unsafe { self.borrow_ref::<Vec<Value>>() })
979 } else {
980 None
981 }
982 }
983
984 pub fn as_vector_rc(&self) -> Option<Rc<Vec<Value>>> {
985 if is_boxed(self.0) && get_tag(self.0) == TAG_VECTOR {
986 Some(unsafe { self.get_rc::<Vec<Value>>() })
987 } else {
988 None
989 }
990 }
991
992 pub fn as_map_rc(&self) -> Option<Rc<BTreeMap<Value, Value>>> {
993 if is_boxed(self.0) && get_tag(self.0) == TAG_MAP {
994 Some(unsafe { self.get_rc::<BTreeMap<Value, Value>>() })
995 } else {
996 None
997 }
998 }
999
1000 pub fn as_hashmap_rc(&self) -> Option<Rc<hashbrown::HashMap<Value, Value>>> {
1001 if is_boxed(self.0) && get_tag(self.0) == TAG_HASHMAP {
1002 Some(unsafe { self.get_rc::<hashbrown::HashMap<Value, Value>>() })
1003 } else {
1004 None
1005 }
1006 }
1007
1008 #[inline(always)]
1010 pub fn as_hashmap_ref(&self) -> Option<&hashbrown::HashMap<Value, Value>> {
1011 if is_boxed(self.0) && get_tag(self.0) == TAG_HASHMAP {
1012 Some(unsafe { self.borrow_ref::<hashbrown::HashMap<Value, Value>>() })
1013 } else {
1014 None
1015 }
1016 }
1017
1018 #[inline(always)]
1020 pub fn as_map_ref(&self) -> Option<&BTreeMap<Value, Value>> {
1021 if is_boxed(self.0) && get_tag(self.0) == TAG_MAP {
1022 Some(unsafe { self.borrow_ref::<BTreeMap<Value, Value>>() })
1023 } else {
1024 None
1025 }
1026 }
1027
1028 #[inline(always)]
1032 pub fn with_hashmap_mut_if_unique<R>(
1033 &self,
1034 f: impl FnOnce(&mut hashbrown::HashMap<Value, Value>) -> R,
1035 ) -> Option<R> {
1036 if !is_boxed(self.0) || get_tag(self.0) != TAG_HASHMAP {
1037 return None;
1038 }
1039 let payload = get_payload(self.0);
1040 let ptr = payload_to_ptr(payload) as *const hashbrown::HashMap<Value, Value>;
1041 let rc = std::mem::ManuallyDrop::new(unsafe { Rc::from_raw(ptr) });
1042 if Rc::strong_count(&rc) != 1 {
1043 return None;
1044 }
1045 let ptr_mut = ptr as *mut hashbrown::HashMap<Value, Value>;
1047 Some(f(unsafe { &mut *ptr_mut }))
1048 }
1049
1050 #[inline(always)]
1053 pub fn with_map_mut_if_unique<R>(
1054 &self,
1055 f: impl FnOnce(&mut BTreeMap<Value, Value>) -> R,
1056 ) -> Option<R> {
1057 if !is_boxed(self.0) || get_tag(self.0) != TAG_MAP {
1058 return None;
1059 }
1060 let payload = get_payload(self.0);
1061 let ptr = payload_to_ptr(payload) as *const BTreeMap<Value, Value>;
1062 let rc = std::mem::ManuallyDrop::new(unsafe { Rc::from_raw(ptr) });
1063 if Rc::strong_count(&rc) != 1 {
1064 return None;
1065 }
1066 let ptr_mut = ptr as *mut BTreeMap<Value, Value>;
1067 Some(f(unsafe { &mut *ptr_mut }))
1068 }
1069
1070 pub fn into_hashmap_rc(self) -> Result<Rc<hashbrown::HashMap<Value, Value>>, Value> {
1073 if is_boxed(self.0) && get_tag(self.0) == TAG_HASHMAP {
1074 let payload = get_payload(self.0);
1075 let ptr = payload_to_ptr(payload) as *const hashbrown::HashMap<Value, Value>;
1076 std::mem::forget(self);
1078 Ok(unsafe { Rc::from_raw(ptr) })
1079 } else {
1080 Err(self)
1081 }
1082 }
1083
1084 pub fn into_map_rc(self) -> Result<Rc<BTreeMap<Value, Value>>, Value> {
1087 if is_boxed(self.0) && get_tag(self.0) == TAG_MAP {
1088 let payload = get_payload(self.0);
1089 let ptr = payload_to_ptr(payload) as *const BTreeMap<Value, Value>;
1090 std::mem::forget(self);
1091 Ok(unsafe { Rc::from_raw(ptr) })
1092 } else {
1093 Err(self)
1094 }
1095 }
1096
1097 pub fn as_lambda_rc(&self) -> Option<Rc<Lambda>> {
1098 if is_boxed(self.0) && get_tag(self.0) == TAG_LAMBDA {
1099 Some(unsafe { self.get_rc::<Lambda>() })
1100 } else {
1101 None
1102 }
1103 }
1104
1105 pub fn as_macro_rc(&self) -> Option<Rc<Macro>> {
1106 if is_boxed(self.0) && get_tag(self.0) == TAG_MACRO {
1107 Some(unsafe { self.get_rc::<Macro>() })
1108 } else {
1109 None
1110 }
1111 }
1112
1113 pub fn as_native_fn_rc(&self) -> Option<Rc<NativeFn>> {
1114 if is_boxed(self.0) && get_tag(self.0) == TAG_NATIVE_FN {
1115 Some(unsafe { self.get_rc::<NativeFn>() })
1116 } else {
1117 None
1118 }
1119 }
1120
1121 pub fn as_thunk_rc(&self) -> Option<Rc<Thunk>> {
1122 if is_boxed(self.0) && get_tag(self.0) == TAG_THUNK {
1123 Some(unsafe { self.get_rc::<Thunk>() })
1124 } else {
1125 None
1126 }
1127 }
1128
1129 pub fn as_record(&self) -> Option<&Record> {
1130 if is_boxed(self.0) && get_tag(self.0) == TAG_RECORD {
1131 Some(unsafe { self.borrow_ref::<Record>() })
1132 } else {
1133 None
1134 }
1135 }
1136
1137 pub fn as_record_rc(&self) -> Option<Rc<Record>> {
1138 if is_boxed(self.0) && get_tag(self.0) == TAG_RECORD {
1139 Some(unsafe { self.get_rc::<Record>() })
1140 } else {
1141 None
1142 }
1143 }
1144
1145 pub fn as_bytevector(&self) -> Option<&[u8]> {
1146 if is_boxed(self.0) && get_tag(self.0) == TAG_BYTEVECTOR {
1147 Some(unsafe { self.borrow_ref::<Vec<u8>>() })
1148 } else {
1149 None
1150 }
1151 }
1152
1153 pub fn as_bytevector_rc(&self) -> Option<Rc<Vec<u8>>> {
1154 if is_boxed(self.0) && get_tag(self.0) == TAG_BYTEVECTOR {
1155 Some(unsafe { self.get_rc::<Vec<u8>>() })
1156 } else {
1157 None
1158 }
1159 }
1160
1161 pub fn as_prompt_rc(&self) -> Option<Rc<Prompt>> {
1162 if is_boxed(self.0) && get_tag(self.0) == TAG_PROMPT {
1163 Some(unsafe { self.get_rc::<Prompt>() })
1164 } else {
1165 None
1166 }
1167 }
1168
1169 pub fn as_message_rc(&self) -> Option<Rc<Message>> {
1170 if is_boxed(self.0) && get_tag(self.0) == TAG_MESSAGE {
1171 Some(unsafe { self.get_rc::<Message>() })
1172 } else {
1173 None
1174 }
1175 }
1176
1177 pub fn as_conversation_rc(&self) -> Option<Rc<Conversation>> {
1178 if is_boxed(self.0) && get_tag(self.0) == TAG_CONVERSATION {
1179 Some(unsafe { self.get_rc::<Conversation>() })
1180 } else {
1181 None
1182 }
1183 }
1184
1185 pub fn as_tool_def_rc(&self) -> Option<Rc<ToolDefinition>> {
1186 if is_boxed(self.0) && get_tag(self.0) == TAG_TOOL_DEF {
1187 Some(unsafe { self.get_rc::<ToolDefinition>() })
1188 } else {
1189 None
1190 }
1191 }
1192
1193 pub fn as_agent_rc(&self) -> Option<Rc<Agent>> {
1194 if is_boxed(self.0) && get_tag(self.0) == TAG_AGENT {
1195 Some(unsafe { self.get_rc::<Agent>() })
1196 } else {
1197 None
1198 }
1199 }
1200}
1201
1202impl Clone for Value {
1205 #[inline(always)]
1206 fn clone(&self) -> Self {
1207 if !is_boxed(self.0) {
1208 return Value(self.0);
1210 }
1211 let tag = get_tag(self.0);
1212 match tag {
1213 TAG_NIL | TAG_FALSE | TAG_TRUE | TAG_INT_SMALL | TAG_CHAR | TAG_SYMBOL
1215 | TAG_KEYWORD => Value(self.0),
1216 _ => {
1218 let payload = get_payload(self.0);
1219 let ptr = payload_to_ptr(payload);
1220 unsafe {
1222 match tag {
1223 TAG_INT_BIG => Rc::increment_strong_count(ptr as *const i64),
1224 TAG_STRING => Rc::increment_strong_count(ptr as *const String),
1225 TAG_LIST | TAG_VECTOR => {
1226 Rc::increment_strong_count(ptr as *const Vec<Value>)
1227 }
1228 TAG_MAP => Rc::increment_strong_count(ptr as *const BTreeMap<Value, Value>),
1229 TAG_HASHMAP => Rc::increment_strong_count(
1230 ptr as *const hashbrown::HashMap<Value, Value>,
1231 ),
1232 TAG_LAMBDA => Rc::increment_strong_count(ptr as *const Lambda),
1233 TAG_MACRO => Rc::increment_strong_count(ptr as *const Macro),
1234 TAG_NATIVE_FN => Rc::increment_strong_count(ptr as *const NativeFn),
1235 TAG_PROMPT => Rc::increment_strong_count(ptr as *const Prompt),
1236 TAG_MESSAGE => Rc::increment_strong_count(ptr as *const Message),
1237 TAG_CONVERSATION => Rc::increment_strong_count(ptr as *const Conversation),
1238 TAG_TOOL_DEF => Rc::increment_strong_count(ptr as *const ToolDefinition),
1239 TAG_AGENT => Rc::increment_strong_count(ptr as *const Agent),
1240 TAG_THUNK => Rc::increment_strong_count(ptr as *const Thunk),
1241 TAG_RECORD => Rc::increment_strong_count(ptr as *const Record),
1242 TAG_BYTEVECTOR => Rc::increment_strong_count(ptr as *const Vec<u8>),
1243 _ => unreachable!("invalid heap tag in clone: {}", tag),
1244 }
1245 }
1246 Value(self.0)
1247 }
1248 }
1249 }
1250}
1251
1252impl Drop for Value {
1255 #[inline(always)]
1256 fn drop(&mut self) {
1257 if !is_boxed(self.0) {
1258 return; }
1260 let tag = get_tag(self.0);
1261 match tag {
1262 TAG_NIL | TAG_FALSE | TAG_TRUE | TAG_INT_SMALL | TAG_CHAR | TAG_SYMBOL
1264 | TAG_KEYWORD => {}
1265 _ => {
1267 let payload = get_payload(self.0);
1268 let ptr = payload_to_ptr(payload);
1269 unsafe {
1270 match tag {
1271 TAG_INT_BIG => drop(Rc::from_raw(ptr as *const i64)),
1272 TAG_STRING => drop(Rc::from_raw(ptr as *const String)),
1273 TAG_LIST | TAG_VECTOR => drop(Rc::from_raw(ptr as *const Vec<Value>)),
1274 TAG_MAP => drop(Rc::from_raw(ptr as *const BTreeMap<Value, Value>)),
1275 TAG_HASHMAP => {
1276 drop(Rc::from_raw(ptr as *const hashbrown::HashMap<Value, Value>))
1277 }
1278 TAG_LAMBDA => drop(Rc::from_raw(ptr as *const Lambda)),
1279 TAG_MACRO => drop(Rc::from_raw(ptr as *const Macro)),
1280 TAG_NATIVE_FN => drop(Rc::from_raw(ptr as *const NativeFn)),
1281 TAG_PROMPT => drop(Rc::from_raw(ptr as *const Prompt)),
1282 TAG_MESSAGE => drop(Rc::from_raw(ptr as *const Message)),
1283 TAG_CONVERSATION => drop(Rc::from_raw(ptr as *const Conversation)),
1284 TAG_TOOL_DEF => drop(Rc::from_raw(ptr as *const ToolDefinition)),
1285 TAG_AGENT => drop(Rc::from_raw(ptr as *const Agent)),
1286 TAG_THUNK => drop(Rc::from_raw(ptr as *const Thunk)),
1287 TAG_RECORD => drop(Rc::from_raw(ptr as *const Record)),
1288 TAG_BYTEVECTOR => drop(Rc::from_raw(ptr as *const Vec<u8>)),
1289 _ => {} }
1291 }
1292 }
1293 }
1294 }
1295}
1296
1297impl PartialEq for Value {
1300 fn eq(&self, other: &Self) -> bool {
1301 if self.0 == other.0 {
1303 if !is_boxed(self.0) {
1307 let f = f64::from_bits(self.0);
1308 if f.is_nan() {
1310 return false;
1311 }
1312 return true;
1313 }
1314 return true;
1315 }
1316 match (self.view(), other.view()) {
1318 (ValueView::Nil, ValueView::Nil) => true,
1319 (ValueView::Bool(a), ValueView::Bool(b)) => a == b,
1320 (ValueView::Int(a), ValueView::Int(b)) => a == b,
1321 (ValueView::Float(a), ValueView::Float(b)) => a.to_bits() == b.to_bits(),
1322 (ValueView::String(a), ValueView::String(b)) => a == b,
1323 (ValueView::Symbol(a), ValueView::Symbol(b)) => a == b,
1324 (ValueView::Keyword(a), ValueView::Keyword(b)) => a == b,
1325 (ValueView::Char(a), ValueView::Char(b)) => a == b,
1326 (ValueView::List(a), ValueView::List(b)) => a == b,
1327 (ValueView::Vector(a), ValueView::Vector(b)) => a == b,
1328 (ValueView::Map(a), ValueView::Map(b)) => a == b,
1329 (ValueView::HashMap(a), ValueView::HashMap(b)) => a == b,
1330 (ValueView::Record(a), ValueView::Record(b)) => {
1331 a.type_tag == b.type_tag && a.fields == b.fields
1332 }
1333 (ValueView::Bytevector(a), ValueView::Bytevector(b)) => a == b,
1334 _ => false,
1335 }
1336 }
1337}
1338
1339impl Eq for Value {}
1340
1341impl Hash for Value {
1344 fn hash<H: Hasher>(&self, state: &mut H) {
1345 match self.view() {
1346 ValueView::Nil => 0u8.hash(state),
1347 ValueView::Bool(b) => {
1348 1u8.hash(state);
1349 b.hash(state);
1350 }
1351 ValueView::Int(n) => {
1352 2u8.hash(state);
1353 n.hash(state);
1354 }
1355 ValueView::Float(f) => {
1356 3u8.hash(state);
1357 f.to_bits().hash(state);
1358 }
1359 ValueView::String(s) => {
1360 4u8.hash(state);
1361 s.hash(state);
1362 }
1363 ValueView::Symbol(s) => {
1364 5u8.hash(state);
1365 s.hash(state);
1366 }
1367 ValueView::Keyword(s) => {
1368 6u8.hash(state);
1369 s.hash(state);
1370 }
1371 ValueView::Char(c) => {
1372 7u8.hash(state);
1373 c.hash(state);
1374 }
1375 ValueView::List(l) => {
1376 8u8.hash(state);
1377 l.hash(state);
1378 }
1379 ValueView::Vector(v) => {
1380 9u8.hash(state);
1381 v.hash(state);
1382 }
1383 ValueView::Record(r) => {
1384 10u8.hash(state);
1385 r.type_tag.hash(state);
1386 r.fields.hash(state);
1387 }
1388 ValueView::Bytevector(bv) => {
1389 11u8.hash(state);
1390 bv.hash(state);
1391 }
1392 _ => {}
1393 }
1394 }
1395}
1396
1397impl PartialOrd for Value {
1400 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1401 Some(self.cmp(other))
1402 }
1403}
1404
1405impl Ord for Value {
1406 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1407 use std::cmp::Ordering;
1408 fn type_order(v: &Value) -> u8 {
1409 match v.view() {
1410 ValueView::Nil => 0,
1411 ValueView::Bool(_) => 1,
1412 ValueView::Int(_) => 2,
1413 ValueView::Float(_) => 3,
1414 ValueView::Char(_) => 4,
1415 ValueView::String(_) => 5,
1416 ValueView::Symbol(_) => 6,
1417 ValueView::Keyword(_) => 7,
1418 ValueView::List(_) => 8,
1419 ValueView::Vector(_) => 9,
1420 ValueView::Map(_) => 10,
1421 ValueView::HashMap(_) => 11,
1422 ValueView::Record(_) => 12,
1423 ValueView::Bytevector(_) => 13,
1424 _ => 14,
1425 }
1426 }
1427 match (self.view(), other.view()) {
1428 (ValueView::Nil, ValueView::Nil) => Ordering::Equal,
1429 (ValueView::Bool(a), ValueView::Bool(b)) => a.cmp(&b),
1430 (ValueView::Int(a), ValueView::Int(b)) => a.cmp(&b),
1431 (ValueView::Float(a), ValueView::Float(b)) => a.to_bits().cmp(&b.to_bits()),
1432 (ValueView::String(a), ValueView::String(b)) => a.cmp(&b),
1433 (ValueView::Symbol(a), ValueView::Symbol(b)) => compare_spurs(a, b),
1434 (ValueView::Keyword(a), ValueView::Keyword(b)) => compare_spurs(a, b),
1435 (ValueView::Char(a), ValueView::Char(b)) => a.cmp(&b),
1436 (ValueView::List(a), ValueView::List(b)) => a.cmp(&b),
1437 (ValueView::Vector(a), ValueView::Vector(b)) => a.cmp(&b),
1438 (ValueView::Record(a), ValueView::Record(b)) => {
1439 compare_spurs(a.type_tag, b.type_tag).then_with(|| a.fields.cmp(&b.fields))
1440 }
1441 (ValueView::Bytevector(a), ValueView::Bytevector(b)) => a.cmp(&b),
1442 _ => type_order(self).cmp(&type_order(other)),
1443 }
1444 }
1445}
1446
1447fn truncate(s: &str, max: usize) -> String {
1450 let mut iter = s.chars();
1451 let prefix: String = iter.by_ref().take(max).collect();
1452 if iter.next().is_none() {
1453 prefix
1454 } else {
1455 format!("{prefix}...")
1456 }
1457}
1458
1459impl fmt::Display for Value {
1460 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1461 match self.view() {
1462 ValueView::Nil => write!(f, "nil"),
1463 ValueView::Bool(true) => write!(f, "#t"),
1464 ValueView::Bool(false) => write!(f, "#f"),
1465 ValueView::Int(n) => write!(f, "{n}"),
1466 ValueView::Float(n) => {
1467 if n.fract() == 0.0 {
1468 write!(f, "{n:.1}")
1469 } else {
1470 write!(f, "{n}")
1471 }
1472 }
1473 ValueView::String(s) => write!(f, "\"{s}\""),
1474 ValueView::Symbol(s) => with_resolved(s, |name| write!(f, "{name}")),
1475 ValueView::Keyword(s) => with_resolved(s, |name| write!(f, ":{name}")),
1476 ValueView::Char(c) => match c {
1477 ' ' => write!(f, "#\\space"),
1478 '\n' => write!(f, "#\\newline"),
1479 '\t' => write!(f, "#\\tab"),
1480 '\r' => write!(f, "#\\return"),
1481 '\0' => write!(f, "#\\nul"),
1482 _ => write!(f, "#\\{c}"),
1483 },
1484 ValueView::List(items) => {
1485 write!(f, "(")?;
1486 for (i, item) in items.iter().enumerate() {
1487 if i > 0 {
1488 write!(f, " ")?;
1489 }
1490 write!(f, "{item}")?;
1491 }
1492 write!(f, ")")
1493 }
1494 ValueView::Vector(items) => {
1495 write!(f, "[")?;
1496 for (i, item) in items.iter().enumerate() {
1497 if i > 0 {
1498 write!(f, " ")?;
1499 }
1500 write!(f, "{item}")?;
1501 }
1502 write!(f, "]")
1503 }
1504 ValueView::Map(map) => {
1505 write!(f, "{{")?;
1506 for (i, (k, v)) in map.iter().enumerate() {
1507 if i > 0 {
1508 write!(f, " ")?;
1509 }
1510 write!(f, "{k} {v}")?;
1511 }
1512 write!(f, "}}")
1513 }
1514 ValueView::HashMap(map) => {
1515 let mut entries: Vec<_> = map.iter().collect();
1516 entries.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
1517 write!(f, "{{")?;
1518 for (i, (k, v)) in entries.iter().enumerate() {
1519 if i > 0 {
1520 write!(f, " ")?;
1521 }
1522 write!(f, "{k} {v}")?;
1523 }
1524 write!(f, "}}")
1525 }
1526 ValueView::Lambda(l) => {
1527 if let Some(name) = &l.name {
1528 with_resolved(*name, |n| write!(f, "<lambda {n}>"))
1529 } else {
1530 write!(f, "<lambda>")
1531 }
1532 }
1533 ValueView::Macro(m) => with_resolved(m.name, |n| write!(f, "<macro {n}>")),
1534 ValueView::NativeFn(n) => write!(f, "<native-fn {}>", n.name),
1535 ValueView::Prompt(p) => write!(f, "<prompt {} messages>", p.messages.len()),
1536 ValueView::Message(m) => {
1537 write!(f, "<message {} \"{}\">", m.role, truncate(&m.content, 40))
1538 }
1539 ValueView::Conversation(c) => {
1540 write!(f, "<conversation {} messages>", c.messages.len())
1541 }
1542 ValueView::ToolDef(t) => write!(f, "<tool {}>", t.name),
1543 ValueView::Agent(a) => write!(f, "<agent {}>", a.name),
1544 ValueView::Thunk(t) => {
1545 if t.forced.borrow().is_some() {
1546 write!(f, "<promise (forced)>")
1547 } else {
1548 write!(f, "<promise>")
1549 }
1550 }
1551 ValueView::Record(r) => {
1552 with_resolved(r.type_tag, |tag| write!(f, "#<record {tag}"))?;
1553 for field in &r.fields {
1554 write!(f, " {field}")?;
1555 }
1556 write!(f, ">")
1557 }
1558 ValueView::Bytevector(bv) => {
1559 write!(f, "#u8(")?;
1560 for (i, byte) in bv.iter().enumerate() {
1561 if i > 0 {
1562 write!(f, " ")?;
1563 }
1564 write!(f, "{byte}")?;
1565 }
1566 write!(f, ")")
1567 }
1568 }
1569 }
1570}
1571
1572pub fn pretty_print(value: &Value, max_width: usize) -> String {
1578 let compact = format!("{value}");
1579 if compact.len() <= max_width {
1580 return compact;
1581 }
1582 let mut buf = String::new();
1583 pp_value(value, 0, max_width, &mut buf);
1584 buf
1585}
1586
1587fn pp_value(value: &Value, indent: usize, max_width: usize, buf: &mut String) {
1591 let compact = format!("{value}");
1592 let remaining = max_width.saturating_sub(indent);
1593 if compact.len() <= remaining {
1594 buf.push_str(&compact);
1595 return;
1596 }
1597
1598 match value.view() {
1599 ValueView::List(items) => {
1600 pp_seq(items.iter(), '(', ')', indent, max_width, buf);
1601 }
1602 ValueView::Vector(items) => {
1603 pp_seq(items.iter(), '[', ']', indent, max_width, buf);
1604 }
1605 ValueView::Map(map) => {
1606 pp_map(
1607 map.iter().map(|(k, v)| (k.clone(), v.clone())),
1608 indent,
1609 max_width,
1610 buf,
1611 );
1612 }
1613 ValueView::HashMap(map) => {
1614 let mut entries: Vec<_> = map.iter().map(|(k, v)| (k.clone(), v.clone())).collect();
1615 entries.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
1616 pp_map(entries.into_iter(), indent, max_width, buf);
1617 }
1618 _ => buf.push_str(&compact),
1619 }
1620}
1621
1622fn pp_seq<'a>(
1624 items: impl Iterator<Item = &'a Value>,
1625 open: char,
1626 close: char,
1627 indent: usize,
1628 max_width: usize,
1629 buf: &mut String,
1630) {
1631 buf.push(open);
1632 let child_indent = indent + 1;
1633 let pad = " ".repeat(child_indent);
1634 for (i, item) in items.enumerate() {
1635 if i > 0 {
1636 buf.push('\n');
1637 buf.push_str(&pad);
1638 }
1639 pp_value(item, child_indent, max_width, buf);
1640 }
1641 buf.push(close);
1642}
1643
1644fn pp_map(
1646 entries: impl Iterator<Item = (Value, Value)>,
1647 indent: usize,
1648 max_width: usize,
1649 buf: &mut String,
1650) {
1651 buf.push('{');
1652 let child_indent = indent + 1;
1653 let pad = " ".repeat(child_indent);
1654 for (i, (k, v)) in entries.enumerate() {
1655 if i > 0 {
1656 buf.push('\n');
1657 buf.push_str(&pad);
1658 }
1659 let key_str = format!("{k}");
1661 buf.push_str(&key_str);
1662
1663 let inline_indent = child_indent + key_str.len() + 1;
1665 let compact_val = format!("{v}");
1666 let remaining = max_width.saturating_sub(inline_indent);
1667
1668 if compact_val.len() <= remaining {
1669 buf.push(' ');
1671 buf.push_str(&compact_val);
1672 } else if is_compound(&v) {
1673 let nested_indent = child_indent + 2;
1675 let nested_pad = " ".repeat(nested_indent);
1676 buf.push('\n');
1677 buf.push_str(&nested_pad);
1678 pp_value(&v, nested_indent, max_width, buf);
1679 } else {
1680 buf.push(' ');
1682 buf.push_str(&compact_val);
1683 }
1684 }
1685 buf.push('}');
1686}
1687
1688fn is_compound(value: &Value) -> bool {
1690 matches!(
1691 value.view(),
1692 ValueView::List(_) | ValueView::Vector(_) | ValueView::Map(_) | ValueView::HashMap(_)
1693 )
1694}
1695
1696impl fmt::Debug for Value {
1699 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1700 match self.view() {
1701 ValueView::Nil => write!(f, "Nil"),
1702 ValueView::Bool(b) => write!(f, "Bool({b})"),
1703 ValueView::Int(n) => write!(f, "Int({n})"),
1704 ValueView::Float(n) => write!(f, "Float({n})"),
1705 ValueView::String(s) => write!(f, "String({:?})", &**s),
1706 ValueView::Symbol(s) => write!(f, "Symbol({})", resolve(s)),
1707 ValueView::Keyword(s) => write!(f, "Keyword({})", resolve(s)),
1708 ValueView::Char(c) => write!(f, "Char({c:?})"),
1709 ValueView::List(items) => write!(f, "List({items:?})"),
1710 ValueView::Vector(items) => write!(f, "Vector({items:?})"),
1711 ValueView::Map(map) => write!(f, "Map({map:?})"),
1712 ValueView::HashMap(map) => write!(f, "HashMap({map:?})"),
1713 ValueView::Lambda(l) => write!(f, "{l:?}"),
1714 ValueView::Macro(m) => write!(f, "{m:?}"),
1715 ValueView::NativeFn(n) => write!(f, "{n:?}"),
1716 ValueView::Prompt(p) => write!(f, "{p:?}"),
1717 ValueView::Message(m) => write!(f, "{m:?}"),
1718 ValueView::Conversation(c) => write!(f, "{c:?}"),
1719 ValueView::ToolDef(t) => write!(f, "{t:?}"),
1720 ValueView::Agent(a) => write!(f, "{a:?}"),
1721 ValueView::Thunk(t) => write!(f, "{t:?}"),
1722 ValueView::Record(r) => write!(f, "{r:?}"),
1723 ValueView::Bytevector(bv) => write!(f, "Bytevector({bv:?})"),
1724 }
1725 }
1726}
1727
1728#[derive(Debug, Clone)]
1732pub struct Env {
1733 pub bindings: Rc<RefCell<SpurMap<Spur, Value>>>,
1734 pub parent: Option<Rc<Env>>,
1735 pub version: Cell<u64>,
1736}
1737
1738impl Env {
1739 pub fn new() -> Self {
1740 Env {
1741 bindings: Rc::new(RefCell::new(SpurMap::new())),
1742 parent: None,
1743 version: Cell::new(0),
1744 }
1745 }
1746
1747 pub fn with_parent(parent: Rc<Env>) -> Self {
1748 Env {
1749 bindings: Rc::new(RefCell::new(SpurMap::new())),
1750 parent: Some(parent),
1751 version: Cell::new(0),
1752 }
1753 }
1754
1755 fn bump_version(&self) {
1756 self.version.set(self.version.get().wrapping_add(1));
1757 }
1758
1759 pub fn get(&self, name: Spur) -> Option<Value> {
1760 if let Some(val) = self.bindings.borrow().get(&name) {
1761 Some(val.clone())
1762 } else if let Some(parent) = &self.parent {
1763 parent.get(name)
1764 } else {
1765 None
1766 }
1767 }
1768
1769 pub fn get_str(&self, name: &str) -> Option<Value> {
1770 self.get(intern(name))
1771 }
1772
1773 pub fn set(&self, name: Spur, val: Value) {
1774 self.bindings.borrow_mut().insert(name, val);
1775 self.bump_version();
1776 }
1777
1778 pub fn set_str(&self, name: &str, val: Value) {
1779 self.set(intern(name), val);
1780 }
1781
1782 pub fn update(&self, name: Spur, val: Value) {
1784 let mut bindings = self.bindings.borrow_mut();
1785 if let Some(entry) = bindings.get_mut(&name) {
1786 *entry = val;
1787 } else {
1788 bindings.insert(name, val);
1789 }
1790 drop(bindings);
1791 self.bump_version();
1792 }
1793
1794 pub fn take(&self, name: Spur) -> Option<Value> {
1796 let result = self.bindings.borrow_mut().remove(&name);
1797 if result.is_some() {
1798 self.bump_version();
1799 }
1800 result
1801 }
1802
1803 pub fn take_anywhere(&self, name: Spur) -> Option<Value> {
1805 if let Some(val) = self.bindings.borrow_mut().remove(&name) {
1806 self.bump_version();
1807 Some(val)
1808 } else if let Some(parent) = &self.parent {
1809 parent.take_anywhere(name)
1810 } else {
1811 None
1812 }
1813 }
1814
1815 pub fn set_existing(&self, name: Spur, val: Value) -> bool {
1817 let mut bindings = self.bindings.borrow_mut();
1818 if let Some(entry) = bindings.get_mut(&name) {
1819 *entry = val;
1820 drop(bindings);
1821 self.bump_version();
1822 true
1823 } else {
1824 drop(bindings);
1825 if let Some(parent) = &self.parent {
1826 parent.set_existing(name, val)
1827 } else {
1828 false
1829 }
1830 }
1831 }
1832}
1833
1834impl Default for Env {
1835 fn default() -> Self {
1836 Self::new()
1837 }
1838}
1839
1840#[cfg(test)]
1843mod tests {
1844 use super::*;
1845
1846 #[test]
1847 fn test_size_of_value() {
1848 assert_eq!(std::mem::size_of::<Value>(), 8);
1849 }
1850
1851 #[test]
1852 fn test_nil() {
1853 let v = Value::nil();
1854 assert!(v.is_nil());
1855 assert!(!v.is_truthy());
1856 assert_eq!(v.type_name(), "nil");
1857 assert_eq!(format!("{v}"), "nil");
1858 }
1859
1860 #[test]
1861 fn test_bool() {
1862 let t = Value::bool(true);
1863 let f = Value::bool(false);
1864 assert!(t.is_truthy());
1865 assert!(!f.is_truthy());
1866 assert_eq!(t.as_bool(), Some(true));
1867 assert_eq!(f.as_bool(), Some(false));
1868 assert_eq!(format!("{t}"), "#t");
1869 assert_eq!(format!("{f}"), "#f");
1870 }
1871
1872 #[test]
1873 fn test_small_int() {
1874 let v = Value::int(42);
1875 assert_eq!(v.as_int(), Some(42));
1876 assert_eq!(v.type_name(), "int");
1877 assert_eq!(format!("{v}"), "42");
1878
1879 let neg = Value::int(-100);
1880 assert_eq!(neg.as_int(), Some(-100));
1881 assert_eq!(format!("{neg}"), "-100");
1882
1883 let zero = Value::int(0);
1884 assert_eq!(zero.as_int(), Some(0));
1885 }
1886
1887 #[test]
1888 fn test_small_int_boundaries() {
1889 let max = Value::int(SMALL_INT_MAX);
1890 assert_eq!(max.as_int(), Some(SMALL_INT_MAX));
1891
1892 let min = Value::int(SMALL_INT_MIN);
1893 assert_eq!(min.as_int(), Some(SMALL_INT_MIN));
1894 }
1895
1896 #[test]
1897 fn test_big_int() {
1898 let big = Value::int(i64::MAX);
1899 assert_eq!(big.as_int(), Some(i64::MAX));
1900 assert_eq!(big.type_name(), "int");
1901
1902 let big_neg = Value::int(i64::MIN);
1903 assert_eq!(big_neg.as_int(), Some(i64::MIN));
1904
1905 let just_over = Value::int(SMALL_INT_MAX + 1);
1907 assert_eq!(just_over.as_int(), Some(SMALL_INT_MAX + 1));
1908 }
1909
1910 #[test]
1911 fn test_float() {
1912 let v = Value::float(3.14);
1913 assert_eq!(v.as_float(), Some(3.14));
1914 assert_eq!(v.type_name(), "float");
1915
1916 let neg = Value::float(-0.5);
1917 assert_eq!(neg.as_float(), Some(-0.5));
1918
1919 let inf = Value::float(f64::INFINITY);
1920 assert_eq!(inf.as_float(), Some(f64::INFINITY));
1921
1922 let neg_inf = Value::float(f64::NEG_INFINITY);
1923 assert_eq!(neg_inf.as_float(), Some(f64::NEG_INFINITY));
1924 }
1925
1926 #[test]
1927 fn test_float_nan() {
1928 let nan = Value::float(f64::NAN);
1929 let f = nan.as_float().unwrap();
1930 assert!(f.is_nan());
1931 }
1932
1933 #[test]
1934 fn test_string() {
1935 let v = Value::string("hello");
1936 assert_eq!(v.as_str(), Some("hello"));
1937 assert_eq!(v.type_name(), "string");
1938 assert_eq!(format!("{v}"), "\"hello\"");
1939 }
1940
1941 #[test]
1942 fn test_symbol() {
1943 let v = Value::symbol("foo");
1944 assert!(v.as_symbol_spur().is_some());
1945 assert_eq!(v.as_symbol(), Some("foo".to_string()));
1946 assert_eq!(v.type_name(), "symbol");
1947 assert_eq!(format!("{v}"), "foo");
1948 }
1949
1950 #[test]
1951 fn test_keyword() {
1952 let v = Value::keyword("bar");
1953 assert!(v.as_keyword_spur().is_some());
1954 assert_eq!(v.as_keyword(), Some("bar".to_string()));
1955 assert_eq!(v.type_name(), "keyword");
1956 assert_eq!(format!("{v}"), ":bar");
1957 }
1958
1959 #[test]
1960 fn test_char() {
1961 let v = Value::char('λ');
1962 assert_eq!(v.as_char(), Some('λ'));
1963 assert_eq!(v.type_name(), "char");
1964 }
1965
1966 #[test]
1967 fn test_list() {
1968 let v = Value::list(vec![Value::int(1), Value::int(2), Value::int(3)]);
1969 assert_eq!(v.as_list().unwrap().len(), 3);
1970 assert_eq!(v.type_name(), "list");
1971 assert_eq!(format!("{v}"), "(1 2 3)");
1972 }
1973
1974 #[test]
1975 fn test_clone_immediate() {
1976 let v = Value::int(42);
1977 let v2 = v.clone();
1978 assert_eq!(v.as_int(), v2.as_int());
1979 }
1980
1981 #[test]
1982 fn test_clone_heap() {
1983 let v = Value::string("hello");
1984 let v2 = v.clone();
1985 assert_eq!(v.as_str(), v2.as_str());
1986 assert_eq!(format!("{v}"), format!("{v2}"));
1988 }
1989
1990 #[test]
1991 fn test_equality() {
1992 assert_eq!(Value::int(42), Value::int(42));
1993 assert_ne!(Value::int(42), Value::int(43));
1994 assert_eq!(Value::nil(), Value::nil());
1995 assert_eq!(Value::bool(true), Value::bool(true));
1996 assert_ne!(Value::bool(true), Value::bool(false));
1997 assert_eq!(Value::string("a"), Value::string("a"));
1998 assert_ne!(Value::string("a"), Value::string("b"));
1999 assert_eq!(Value::symbol("x"), Value::symbol("x"));
2000 }
2001
2002 #[test]
2003 fn test_big_int_equality() {
2004 assert_eq!(Value::int(i64::MAX), Value::int(i64::MAX));
2005 assert_ne!(Value::int(i64::MAX), Value::int(i64::MIN));
2006 }
2007
2008 #[test]
2009 fn test_view_pattern_matching() {
2010 let v = Value::int(42);
2011 match v.view() {
2012 ValueView::Int(n) => assert_eq!(n, 42),
2013 _ => panic!("expected int"),
2014 }
2015
2016 let v = Value::string("hello");
2017 match v.view() {
2018 ValueView::String(s) => assert_eq!(&**s, "hello"),
2019 _ => panic!("expected string"),
2020 }
2021 }
2022
2023 #[test]
2024 fn test_env() {
2025 let env = Env::new();
2026 env.set_str("x", Value::int(42));
2027 assert_eq!(env.get_str("x"), Some(Value::int(42)));
2028 }
2029
2030 #[test]
2031 fn test_native_fn_simple() {
2032 let f = NativeFn::simple("add1", |args| Ok(args[0].clone()));
2033 let ctx = EvalContext::new();
2034 assert!((f.func)(&ctx, &[Value::int(42)]).is_ok());
2035 }
2036
2037 #[test]
2038 fn test_native_fn_with_ctx() {
2039 let f = NativeFn::with_ctx("get-depth", |ctx, _args| {
2040 Ok(Value::int(ctx.eval_depth.get() as i64))
2041 });
2042 let ctx = EvalContext::new();
2043 assert_eq!((f.func)(&ctx, &[]).unwrap(), Value::int(0));
2044 }
2045
2046 #[test]
2047 fn test_drop_doesnt_leak() {
2048 for _ in 0..10000 {
2050 let _ = Value::string("test");
2051 let _ = Value::list(vec![Value::int(1), Value::int(2)]);
2052 let _ = Value::int(i64::MAX); }
2054 }
2055
2056 #[test]
2057 fn test_is_truthy() {
2058 assert!(!Value::nil().is_truthy());
2059 assert!(!Value::bool(false).is_truthy());
2060 assert!(Value::bool(true).is_truthy());
2061 assert!(Value::int(0).is_truthy());
2062 assert!(Value::int(1).is_truthy());
2063 assert!(Value::string("").is_truthy());
2064 assert!(Value::list(vec![]).is_truthy());
2065 }
2066
2067 #[test]
2068 fn test_as_float_from_int() {
2069 assert_eq!(Value::int(42).as_float(), Some(42.0));
2070 assert_eq!(Value::float(3.14).as_float(), Some(3.14));
2071 }
2072}