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
57thread_local! {
60 static GENSYM_COUNTER: Cell<u64> = const { Cell::new(0) };
61}
62
63pub fn next_gensym(prefix: &str) -> String {
67 GENSYM_COUNTER.with(|c| {
68 let val = c.get();
69 c.set(val.wrapping_add(1));
70 format!("{prefix}__{val}")
71 })
72}
73
74pub fn compare_spurs(a: Spur, b: Spur) -> std::cmp::Ordering {
76 if a == b {
77 return std::cmp::Ordering::Equal;
78 }
79 INTERNER.with(|r| {
80 let interner = r.borrow();
81 interner.resolve(&a).cmp(interner.resolve(&b))
82 })
83}
84
85pub type NativeFnInner = dyn Fn(&EvalContext, &[Value]) -> Result<Value, SemaError>;
89
90pub struct NativeFn {
91 pub name: String,
92 pub func: Box<NativeFnInner>,
93 pub payload: Option<Rc<dyn Any>>,
94}
95
96impl NativeFn {
97 pub fn simple(
98 name: impl Into<String>,
99 f: impl Fn(&[Value]) -> Result<Value, SemaError> + 'static,
100 ) -> Self {
101 Self {
102 name: name.into(),
103 func: Box::new(move |_ctx, args| f(args)),
104 payload: None,
105 }
106 }
107
108 pub fn with_ctx(
109 name: impl Into<String>,
110 f: impl Fn(&EvalContext, &[Value]) -> Result<Value, SemaError> + 'static,
111 ) -> Self {
112 Self {
113 name: name.into(),
114 func: Box::new(f),
115 payload: None,
116 }
117 }
118
119 pub fn with_payload(
120 name: impl Into<String>,
121 payload: Rc<dyn Any>,
122 f: impl Fn(&EvalContext, &[Value]) -> Result<Value, SemaError> + 'static,
123 ) -> Self {
124 Self {
125 name: name.into(),
126 func: Box::new(f),
127 payload: Some(payload),
128 }
129 }
130}
131
132impl fmt::Debug for NativeFn {
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 write!(f, "<native-fn {}>", self.name)
135 }
136}
137
138#[derive(Debug, Clone)]
140pub struct Lambda {
141 pub params: Vec<Spur>,
142 pub rest_param: Option<Spur>,
143 pub body: Vec<Value>,
144 pub env: Env,
145 pub name: Option<Spur>,
146}
147
148#[derive(Debug, Clone)]
150pub struct Macro {
151 pub params: Vec<Spur>,
152 pub rest_param: Option<Spur>,
153 pub body: Vec<Value>,
154 pub name: Spur,
155}
156
157pub struct Thunk {
159 pub body: Value,
160 pub forced: RefCell<Option<Value>>,
161}
162
163impl fmt::Debug for Thunk {
164 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165 if self.forced.borrow().is_some() {
166 write!(f, "<promise (forced)>")
167 } else {
168 write!(f, "<promise>")
169 }
170 }
171}
172
173impl Clone for Thunk {
174 fn clone(&self) -> Self {
175 Thunk {
176 body: self.body.clone(),
177 forced: RefCell::new(self.forced.borrow().clone()),
178 }
179 }
180}
181
182#[derive(Debug, Clone)]
184pub struct Record {
185 pub type_tag: Spur,
186 pub fields: Vec<Value>,
187}
188
189#[derive(Debug, Clone, PartialEq, Eq)]
191pub enum Role {
192 System,
193 User,
194 Assistant,
195 Tool,
196}
197
198impl fmt::Display for Role {
199 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
200 match self {
201 Role::System => write!(f, "system"),
202 Role::User => write!(f, "user"),
203 Role::Assistant => write!(f, "assistant"),
204 Role::Tool => write!(f, "tool"),
205 }
206 }
207}
208
209#[derive(Debug, Clone)]
211pub struct ImageAttachment {
212 pub data: String,
213 pub media_type: String,
214}
215
216#[derive(Debug, Clone)]
218pub struct Message {
219 pub role: Role,
220 pub content: String,
221 pub images: Vec<ImageAttachment>,
223}
224
225#[derive(Debug, Clone)]
227pub struct Prompt {
228 pub messages: Vec<Message>,
229}
230
231#[derive(Debug, Clone)]
233pub struct Conversation {
234 pub messages: Vec<Message>,
235 pub model: String,
236 pub metadata: BTreeMap<String, String>,
237}
238
239#[derive(Debug, Clone)]
241pub struct ToolDefinition {
242 pub name: String,
243 pub description: String,
244 pub parameters: Value,
245 pub handler: Value,
246}
247
248#[derive(Debug, Clone)]
250pub struct Agent {
251 pub name: String,
252 pub system: String,
253 pub tools: Vec<Value>,
254 pub max_turns: usize,
255 pub model: String,
256}
257
258pub struct MultiMethod {
261 pub name: Spur,
262 pub dispatch_fn: Value,
263 pub methods: RefCell<BTreeMap<Value, Value>>,
264 pub default: RefCell<Option<Value>>,
265}
266
267impl fmt::Debug for MultiMethod {
268 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
269 write!(f, "<multimethod {}>", resolve(self.name))
270 }
271}
272
273pub trait SemaStream: fmt::Debug {
276 fn read(&self, buf: &mut [u8]) -> Result<usize, SemaError>;
277 fn write(&self, data: &[u8]) -> Result<usize, SemaError>;
278 fn available(&self) -> Result<bool, SemaError> {
279 Ok(false)
280 }
281 fn flush(&self) -> Result<(), SemaError> {
282 Ok(())
283 }
284 fn close(&self) -> Result<(), SemaError> {
285 Ok(())
286 }
287 fn is_readable(&self) -> bool {
288 true
289 }
290 fn is_writable(&self) -> bool {
291 true
292 }
293 fn stream_type(&self) -> &'static str;
294 fn as_any(&self) -> &dyn std::any::Any;
295}
296
297pub struct StreamBox {
300 inner: RefCell<Box<dyn SemaStream>>,
301 closed: Cell<bool>,
302}
303
304impl StreamBox {
305 pub fn new(s: impl SemaStream + 'static) -> Self {
306 StreamBox {
307 inner: RefCell::new(Box::new(s)),
308 closed: Cell::new(false),
309 }
310 }
311
312 pub fn read(&self, buf: &mut [u8]) -> Result<usize, SemaError> {
313 if self.closed.get() {
314 return Err(SemaError::eval("stream/read: stream is closed"));
315 }
316 self.inner.borrow().read(buf)
317 }
318
319 pub fn write(&self, data: &[u8]) -> Result<usize, SemaError> {
320 if self.closed.get() {
321 return Err(SemaError::eval("stream/write: stream is closed"));
322 }
323 self.inner.borrow().write(data)
324 }
325
326 pub fn flush(&self) -> Result<(), SemaError> {
327 if self.closed.get() {
328 return Err(SemaError::eval("stream/flush: stream is closed"));
329 }
330 self.inner.borrow().flush()
331 }
332
333 pub fn close(&self) -> Result<(), SemaError> {
334 if self.closed.get() {
335 return Ok(()); }
337 self.inner.borrow().close()?;
338 self.closed.set(true);
339 Ok(())
340 }
341
342 pub fn is_closed(&self) -> bool {
343 self.closed.get()
344 }
345
346 pub fn is_readable(&self) -> bool {
347 !self.closed.get() && self.inner.borrow().is_readable()
348 }
349
350 pub fn is_writable(&self) -> bool {
351 !self.closed.get() && self.inner.borrow().is_writable()
352 }
353
354 pub fn available(&self) -> Result<bool, SemaError> {
355 if self.closed.get() {
356 return Ok(false);
357 }
358 self.inner.borrow().available()
359 }
360
361 pub fn stream_type(&self) -> &'static str {
362 self.inner.borrow().stream_type()
363 }
364
365 pub fn borrow_inner(&self) -> std::cell::Ref<'_, Box<dyn SemaStream>> {
366 self.inner.borrow()
367 }
368}
369
370impl fmt::Debug for StreamBox {
371 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
372 write!(f, "<stream:{}>", self.stream_type())
373 }
374}
375
376impl Clone for MultiMethod {
377 fn clone(&self) -> Self {
378 MultiMethod {
379 name: self.name,
380 dispatch_fn: self.dispatch_fn.clone(),
381 methods: RefCell::new(self.methods.borrow().clone()),
382 default: RefCell::new(self.default.borrow().clone()),
383 }
384 }
385}
386
387const BOX_MASK: u64 = 0xFFF8_0000_0000_0000;
399
400const PAYLOAD_MASK: u64 = (1u64 << 45) - 1; const INT_SIGN_BIT: u64 = 1u64 << 44;
405
406const TAG_MASK_6BIT: u64 = 0x3F;
408
409const CANONICAL_NAN: u64 = 0x7FF8_0000_0000_0000;
411
412const TAG_NIL: u64 = 0;
414const TAG_FALSE: u64 = 1;
415const TAG_TRUE: u64 = 2;
416const TAG_INT_SMALL: u64 = 3;
417const TAG_CHAR: u64 = 4;
418const TAG_SYMBOL: u64 = 5;
419const TAG_KEYWORD: u64 = 6;
420const TAG_INT_BIG: u64 = 7;
421const TAG_STRING: u64 = 8;
422const TAG_LIST: u64 = 9;
423const TAG_VECTOR: u64 = 10;
424const TAG_MAP: u64 = 11;
425const TAG_HASHMAP: u64 = 12;
426const TAG_LAMBDA: u64 = 13;
427const TAG_MACRO: u64 = 14;
428pub const TAG_NATIVE_FN: u64 = 15;
429const TAG_PROMPT: u64 = 16;
430const TAG_MESSAGE: u64 = 17;
431const TAG_CONVERSATION: u64 = 18;
432const TAG_TOOL_DEF: u64 = 19;
433const TAG_AGENT: u64 = 20;
434const TAG_THUNK: u64 = 21;
435const TAG_RECORD: u64 = 22;
436const TAG_BYTEVECTOR: u64 = 23;
437const TAG_MULTIMETHOD: u64 = 24;
438const TAG_STREAM: u64 = 25;
439const TAG_F64_ARRAY: u64 = 26;
440const TAG_I64_ARRAY: u64 = 27;
441
442const SMALL_INT_MIN: i64 = -(1i64 << 44);
444const SMALL_INT_MAX: i64 = (1i64 << 44) - 1;
445
446pub const NAN_TAG_MASK: u64 = BOX_MASK | (TAG_MASK_6BIT << 45); pub const NAN_INT_SMALL_PATTERN: u64 = BOX_MASK | (TAG_INT_SMALL << 45);
453
454pub const NAN_PAYLOAD_MASK: u64 = PAYLOAD_MASK;
456
457pub const NAN_INT_SIGN_BIT: u64 = INT_SIGN_BIT;
459
460pub const NAN_PAYLOAD_BITS: u32 = 45;
462
463#[inline(always)]
466fn make_boxed(tag: u64, payload: u64) -> u64 {
467 BOX_MASK | (tag << 45) | (payload & PAYLOAD_MASK)
468}
469
470#[inline(always)]
471fn is_boxed(bits: u64) -> bool {
472 (bits & BOX_MASK) == BOX_MASK
473}
474
475#[inline(always)]
476fn get_tag(bits: u64) -> u64 {
477 (bits >> 45) & TAG_MASK_6BIT
478}
479
480#[inline(always)]
481fn get_payload(bits: u64) -> u64 {
482 bits & PAYLOAD_MASK
483}
484
485#[inline(always)]
486fn ptr_to_payload(ptr: *const u8) -> u64 {
487 let raw = ptr as u64;
488 debug_assert!(raw & 0x7 == 0, "pointer not 8-byte aligned: 0x{:x}", raw);
489 debug_assert!(
490 raw >> 48 == 0,
491 "pointer exceeds 48-bit VA space: 0x{:x}",
492 raw
493 );
494 raw >> 3
495}
496
497#[inline(always)]
498fn payload_to_ptr(payload: u64) -> *const u8 {
499 (payload << 3) as *const u8
500}
501
502pub enum ValueView {
507 Nil,
508 Bool(bool),
509 Int(i64),
510 Float(f64),
511 String(Rc<String>),
512 Symbol(Spur),
513 Keyword(Spur),
514 Char(char),
515 List(Rc<Vec<Value>>),
516 Vector(Rc<Vec<Value>>),
517 Map(Rc<BTreeMap<Value, Value>>),
518 HashMap(Rc<hashbrown::HashMap<Value, Value>>),
519 Lambda(Rc<Lambda>),
520 Macro(Rc<Macro>),
521 NativeFn(Rc<NativeFn>),
522 Prompt(Rc<Prompt>),
523 Message(Rc<Message>),
524 Conversation(Rc<Conversation>),
525 ToolDef(Rc<ToolDefinition>),
526 Agent(Rc<Agent>),
527 Thunk(Rc<Thunk>),
528 Record(Rc<Record>),
529 Bytevector(Rc<Vec<u8>>),
530 MultiMethod(Rc<MultiMethod>),
531 Stream(Rc<StreamBox>),
532 F64Array(Rc<Vec<f64>>),
533 I64Array(Rc<Vec<i64>>),
534}
535
536#[repr(transparent)]
542pub struct Value(u64);
543
544impl Value {
547 pub const NIL: Value = Value(make_boxed_const(TAG_NIL, 0));
550 pub const TRUE: Value = Value(make_boxed_const(TAG_TRUE, 0));
551 pub const FALSE: Value = Value(make_boxed_const(TAG_FALSE, 0));
552
553 #[inline(always)]
554 pub fn nil() -> Value {
555 Value::NIL
556 }
557
558 #[inline(always)]
559 pub fn bool(b: bool) -> Value {
560 if b {
561 Value::TRUE
562 } else {
563 Value::FALSE
564 }
565 }
566
567 #[inline(always)]
568 pub fn int(n: i64) -> Value {
569 if (SMALL_INT_MIN..=SMALL_INT_MAX).contains(&n) {
570 let payload = (n as u64) & PAYLOAD_MASK;
572 Value(make_boxed(TAG_INT_SMALL, payload))
573 } else {
574 let rc = Rc::new(n);
576 let ptr = Rc::into_raw(rc) as *const u8;
577 Value(make_boxed(TAG_INT_BIG, ptr_to_payload(ptr)))
578 }
579 }
580
581 #[inline(always)]
582 pub fn float(f: f64) -> Value {
583 let bits = f.to_bits();
584 if f.is_nan() {
585 Value(CANONICAL_NAN)
587 } else {
588 debug_assert!(
595 !is_boxed(bits),
596 "non-NaN float collides with boxed pattern: {:?} = 0x{:016x}",
597 f,
598 bits
599 );
600 Value(bits)
601 }
602 }
603
604 #[inline(always)]
605 pub fn char(c: char) -> Value {
606 Value(make_boxed(TAG_CHAR, c as u64))
607 }
608
609 #[inline(always)]
610 pub fn symbol_from_spur(spur: Spur) -> Value {
611 let bits: u32 = unsafe { std::mem::transmute(spur) };
612 Value(make_boxed(TAG_SYMBOL, bits as u64))
613 }
614
615 pub fn symbol(s: &str) -> Value {
616 Value::symbol_from_spur(intern(s))
617 }
618
619 #[inline(always)]
620 pub fn keyword_from_spur(spur: Spur) -> Value {
621 let bits: u32 = unsafe { std::mem::transmute(spur) };
622 Value(make_boxed(TAG_KEYWORD, bits as u64))
623 }
624
625 pub fn keyword(s: &str) -> Value {
626 Value::keyword_from_spur(intern(s))
627 }
628
629 fn from_rc_ptr<T>(tag: u64, rc: Rc<T>) -> Value {
632 let ptr = Rc::into_raw(rc) as *const u8;
633 Value(make_boxed(tag, ptr_to_payload(ptr)))
634 }
635
636 pub fn string(s: &str) -> Value {
637 Value::from_rc_ptr(TAG_STRING, Rc::new(s.to_string()))
638 }
639
640 pub fn string_from_rc(rc: Rc<String>) -> Value {
641 Value::from_rc_ptr(TAG_STRING, rc)
642 }
643
644 pub fn list(v: Vec<Value>) -> Value {
645 Value::from_rc_ptr(TAG_LIST, Rc::new(v))
646 }
647
648 pub fn list_from_rc(rc: Rc<Vec<Value>>) -> Value {
649 Value::from_rc_ptr(TAG_LIST, rc)
650 }
651
652 pub fn vector(v: Vec<Value>) -> Value {
653 Value::from_rc_ptr(TAG_VECTOR, Rc::new(v))
654 }
655
656 pub fn vector_from_rc(rc: Rc<Vec<Value>>) -> Value {
657 Value::from_rc_ptr(TAG_VECTOR, rc)
658 }
659
660 pub fn map(m: BTreeMap<Value, Value>) -> Value {
661 Value::from_rc_ptr(TAG_MAP, Rc::new(m))
662 }
663
664 pub fn map_from_rc(rc: Rc<BTreeMap<Value, Value>>) -> Value {
665 Value::from_rc_ptr(TAG_MAP, rc)
666 }
667
668 pub fn hashmap(entries: Vec<(Value, Value)>) -> Value {
669 let map: hashbrown::HashMap<Value, Value> = entries.into_iter().collect();
670 Value::from_rc_ptr(TAG_HASHMAP, Rc::new(map))
671 }
672
673 pub fn hashmap_from_rc(rc: Rc<hashbrown::HashMap<Value, Value>>) -> Value {
674 Value::from_rc_ptr(TAG_HASHMAP, rc)
675 }
676
677 pub fn lambda(l: Lambda) -> Value {
678 Value::from_rc_ptr(TAG_LAMBDA, Rc::new(l))
679 }
680
681 pub fn lambda_from_rc(rc: Rc<Lambda>) -> Value {
682 Value::from_rc_ptr(TAG_LAMBDA, rc)
683 }
684
685 pub fn macro_val(m: Macro) -> Value {
686 Value::from_rc_ptr(TAG_MACRO, Rc::new(m))
687 }
688
689 pub fn macro_from_rc(rc: Rc<Macro>) -> Value {
690 Value::from_rc_ptr(TAG_MACRO, rc)
691 }
692
693 pub fn native_fn(f: NativeFn) -> Value {
694 Value::from_rc_ptr(TAG_NATIVE_FN, Rc::new(f))
695 }
696
697 pub fn native_fn_from_rc(rc: Rc<NativeFn>) -> Value {
698 Value::from_rc_ptr(TAG_NATIVE_FN, rc)
699 }
700
701 pub fn prompt(p: Prompt) -> Value {
702 Value::from_rc_ptr(TAG_PROMPT, Rc::new(p))
703 }
704
705 pub fn prompt_from_rc(rc: Rc<Prompt>) -> Value {
706 Value::from_rc_ptr(TAG_PROMPT, rc)
707 }
708
709 pub fn message(m: Message) -> Value {
710 Value::from_rc_ptr(TAG_MESSAGE, Rc::new(m))
711 }
712
713 pub fn message_from_rc(rc: Rc<Message>) -> Value {
714 Value::from_rc_ptr(TAG_MESSAGE, rc)
715 }
716
717 pub fn conversation(c: Conversation) -> Value {
718 Value::from_rc_ptr(TAG_CONVERSATION, Rc::new(c))
719 }
720
721 pub fn conversation_from_rc(rc: Rc<Conversation>) -> Value {
722 Value::from_rc_ptr(TAG_CONVERSATION, rc)
723 }
724
725 pub fn tool_def(t: ToolDefinition) -> Value {
726 Value::from_rc_ptr(TAG_TOOL_DEF, Rc::new(t))
727 }
728
729 pub fn tool_def_from_rc(rc: Rc<ToolDefinition>) -> Value {
730 Value::from_rc_ptr(TAG_TOOL_DEF, rc)
731 }
732
733 pub fn agent(a: Agent) -> Value {
734 Value::from_rc_ptr(TAG_AGENT, Rc::new(a))
735 }
736
737 pub fn agent_from_rc(rc: Rc<Agent>) -> Value {
738 Value::from_rc_ptr(TAG_AGENT, rc)
739 }
740
741 pub fn thunk(t: Thunk) -> Value {
742 Value::from_rc_ptr(TAG_THUNK, Rc::new(t))
743 }
744
745 pub fn thunk_from_rc(rc: Rc<Thunk>) -> Value {
746 Value::from_rc_ptr(TAG_THUNK, rc)
747 }
748
749 pub fn record(r: Record) -> Value {
750 Value::from_rc_ptr(TAG_RECORD, Rc::new(r))
751 }
752
753 pub fn record_from_rc(rc: Rc<Record>) -> Value {
754 Value::from_rc_ptr(TAG_RECORD, rc)
755 }
756
757 pub fn bytevector(bytes: Vec<u8>) -> Value {
758 Value::from_rc_ptr(TAG_BYTEVECTOR, Rc::new(bytes))
759 }
760
761 pub fn bytevector_from_rc(rc: Rc<Vec<u8>>) -> Value {
762 Value::from_rc_ptr(TAG_BYTEVECTOR, rc)
763 }
764
765 pub fn f64_array(data: Vec<f64>) -> Value {
766 Value::from_rc_ptr(TAG_F64_ARRAY, Rc::new(data))
767 }
768
769 pub fn f64_array_from_rc(rc: Rc<Vec<f64>>) -> Value {
770 Value::from_rc_ptr(TAG_F64_ARRAY, rc)
771 }
772
773 pub fn i64_array(data: Vec<i64>) -> Value {
774 Value::from_rc_ptr(TAG_I64_ARRAY, Rc::new(data))
775 }
776
777 pub fn i64_array_from_rc(rc: Rc<Vec<i64>>) -> Value {
778 Value::from_rc_ptr(TAG_I64_ARRAY, rc)
779 }
780
781 pub fn multimethod(m: MultiMethod) -> Value {
782 Value::from_rc_ptr(TAG_MULTIMETHOD, Rc::new(m))
783 }
784
785 pub fn multimethod_from_rc(rc: Rc<MultiMethod>) -> Value {
786 Value::from_rc_ptr(TAG_MULTIMETHOD, rc)
787 }
788
789 pub fn stream(s: impl SemaStream + 'static) -> Value {
790 Value::from_rc_ptr(TAG_STREAM, Rc::new(StreamBox::new(s)))
791 }
792
793 pub fn stream_from_rc(rc: Rc<StreamBox>) -> Value {
794 Value::from_rc_ptr(TAG_STREAM, rc)
795 }
796}
797
798const fn make_boxed_const(tag: u64, payload: u64) -> u64 {
800 BOX_MASK | (tag << 45) | (payload & PAYLOAD_MASK)
801}
802
803impl Value {
806 #[inline(always)]
808 pub fn raw_bits(&self) -> u64 {
809 self.0
810 }
811
812 #[inline(always)]
821 pub unsafe fn from_raw_bits(bits: u64) -> Value {
822 Value(bits)
823 }
824
825 #[inline(always)]
828 pub fn raw_tag(&self) -> Option<u64> {
829 if is_boxed(self.0) {
830 Some(get_tag(self.0))
831 } else {
832 None
833 }
834 }
835
836 #[inline(always)]
839 pub fn as_native_fn_ref(&self) -> Option<&NativeFn> {
840 if is_boxed(self.0) && get_tag(self.0) == TAG_NATIVE_FN {
841 Some(unsafe { self.borrow_ref::<NativeFn>() })
842 } else {
843 None
844 }
845 }
846
847 #[inline(always)]
849 pub fn is_float(&self) -> bool {
850 !is_boxed(self.0)
851 }
852
853 #[inline(always)]
856 unsafe fn get_rc<T>(&self) -> Rc<T> {
857 let payload = get_payload(self.0);
858 let ptr = payload_to_ptr(payload) as *const T;
859 Rc::increment_strong_count(ptr);
860 Rc::from_raw(ptr)
861 }
862
863 #[inline(always)]
866 unsafe fn borrow_ref<T>(&self) -> &T {
867 let payload = get_payload(self.0);
868 let ptr = payload_to_ptr(payload) as *const T;
869 &*ptr
870 }
871
872 pub fn view(&self) -> ValueView {
875 if !is_boxed(self.0) {
876 return ValueView::Float(f64::from_bits(self.0));
877 }
878 let tag = get_tag(self.0);
879 match tag {
880 TAG_NIL => ValueView::Nil,
881 TAG_FALSE => ValueView::Bool(false),
882 TAG_TRUE => ValueView::Bool(true),
883 TAG_INT_SMALL => {
884 let payload = get_payload(self.0);
885 let val = if payload & INT_SIGN_BIT != 0 {
886 (payload | !PAYLOAD_MASK) as i64
887 } else {
888 payload as i64
889 };
890 ValueView::Int(val)
891 }
892 TAG_CHAR => {
893 let payload = get_payload(self.0);
894 ValueView::Char(unsafe { char::from_u32_unchecked(payload as u32) })
895 }
896 TAG_SYMBOL => {
897 let payload = get_payload(self.0);
898 let spur: Spur = unsafe { std::mem::transmute(payload as u32) };
899 ValueView::Symbol(spur)
900 }
901 TAG_KEYWORD => {
902 let payload = get_payload(self.0);
903 let spur: Spur = unsafe { std::mem::transmute(payload as u32) };
904 ValueView::Keyword(spur)
905 }
906 TAG_INT_BIG => {
907 let val = unsafe { *self.borrow_ref::<i64>() };
908 ValueView::Int(val)
909 }
910 TAG_STRING => ValueView::String(unsafe { self.get_rc::<String>() }),
911 TAG_LIST => ValueView::List(unsafe { self.get_rc::<Vec<Value>>() }),
912 TAG_VECTOR => ValueView::Vector(unsafe { self.get_rc::<Vec<Value>>() }),
913 TAG_MAP => ValueView::Map(unsafe { self.get_rc::<BTreeMap<Value, Value>>() }),
914 TAG_HASHMAP => {
915 ValueView::HashMap(unsafe { self.get_rc::<hashbrown::HashMap<Value, Value>>() })
916 }
917 TAG_LAMBDA => ValueView::Lambda(unsafe { self.get_rc::<Lambda>() }),
918 TAG_MACRO => ValueView::Macro(unsafe { self.get_rc::<Macro>() }),
919 TAG_NATIVE_FN => ValueView::NativeFn(unsafe { self.get_rc::<NativeFn>() }),
920 TAG_PROMPT => ValueView::Prompt(unsafe { self.get_rc::<Prompt>() }),
921 TAG_MESSAGE => ValueView::Message(unsafe { self.get_rc::<Message>() }),
922 TAG_CONVERSATION => ValueView::Conversation(unsafe { self.get_rc::<Conversation>() }),
923 TAG_TOOL_DEF => ValueView::ToolDef(unsafe { self.get_rc::<ToolDefinition>() }),
924 TAG_AGENT => ValueView::Agent(unsafe { self.get_rc::<Agent>() }),
925 TAG_THUNK => ValueView::Thunk(unsafe { self.get_rc::<Thunk>() }),
926 TAG_RECORD => ValueView::Record(unsafe { self.get_rc::<Record>() }),
927 TAG_BYTEVECTOR => ValueView::Bytevector(unsafe { self.get_rc::<Vec<u8>>() }),
928 TAG_MULTIMETHOD => ValueView::MultiMethod(unsafe { self.get_rc::<MultiMethod>() }),
929 TAG_STREAM => ValueView::Stream(unsafe { self.get_rc::<StreamBox>() }),
930 TAG_F64_ARRAY => ValueView::F64Array(unsafe { self.get_rc::<Vec<f64>>() }),
931 TAG_I64_ARRAY => ValueView::I64Array(unsafe { self.get_rc::<Vec<i64>>() }),
932 _ => unreachable!("invalid NaN-boxed tag: {}", tag),
933 }
934 }
935
936 pub fn type_name(&self) -> &'static str {
939 if !is_boxed(self.0) {
940 return "float";
941 }
942 match get_tag(self.0) {
943 TAG_NIL => "nil",
944 TAG_FALSE | TAG_TRUE => "bool",
945 TAG_INT_SMALL | TAG_INT_BIG => "int",
946 TAG_CHAR => "char",
947 TAG_SYMBOL => "symbol",
948 TAG_KEYWORD => "keyword",
949 TAG_STRING => "string",
950 TAG_LIST => "list",
951 TAG_VECTOR => "vector",
952 TAG_MAP => "map",
953 TAG_HASHMAP => "hashmap",
954 TAG_LAMBDA => "lambda",
955 TAG_MACRO => "macro",
956 TAG_NATIVE_FN => "native-fn",
957 TAG_PROMPT => "prompt",
958 TAG_MESSAGE => "message",
959 TAG_CONVERSATION => "conversation",
960 TAG_TOOL_DEF => "tool",
961 TAG_AGENT => "agent",
962 TAG_THUNK => "promise",
963 TAG_RECORD => "record",
964 TAG_BYTEVECTOR => "bytevector",
965 TAG_MULTIMETHOD => "multimethod",
966 TAG_STREAM => "stream",
967 TAG_F64_ARRAY => "f64-array",
968 TAG_I64_ARRAY => "i64-array",
969 _ => "unknown",
970 }
971 }
972
973 #[inline(always)]
974 pub fn is_nil(&self) -> bool {
975 self.0 == Value::NIL.0
976 }
977
978 #[inline(always)]
979 pub fn is_truthy(&self) -> bool {
980 self.0 != Value::NIL.0 && self.0 != Value::FALSE.0
981 }
982
983 #[inline(always)]
984 pub fn is_falsy(&self) -> bool {
985 !self.is_truthy()
986 }
987
988 #[inline(always)]
989 pub fn is_bool(&self) -> bool {
990 self.0 == Value::TRUE.0 || self.0 == Value::FALSE.0
991 }
992
993 #[inline(always)]
994 pub fn is_int(&self) -> bool {
995 is_boxed(self.0) && matches!(get_tag(self.0), TAG_INT_SMALL | TAG_INT_BIG)
996 }
997
998 #[inline(always)]
999 pub fn is_symbol(&self) -> bool {
1000 is_boxed(self.0) && get_tag(self.0) == TAG_SYMBOL
1001 }
1002
1003 #[inline(always)]
1004 pub fn is_keyword(&self) -> bool {
1005 is_boxed(self.0) && get_tag(self.0) == TAG_KEYWORD
1006 }
1007
1008 #[inline(always)]
1009 pub fn is_string(&self) -> bool {
1010 is_boxed(self.0) && get_tag(self.0) == TAG_STRING
1011 }
1012
1013 #[inline(always)]
1014 pub fn is_list(&self) -> bool {
1015 is_boxed(self.0) && get_tag(self.0) == TAG_LIST
1016 }
1017
1018 #[inline(always)]
1019 pub fn is_pair(&self) -> bool {
1020 if let Some(items) = self.as_list() {
1021 !items.is_empty()
1022 } else {
1023 false
1024 }
1025 }
1026
1027 #[inline(always)]
1028 pub fn is_vector(&self) -> bool {
1029 is_boxed(self.0) && get_tag(self.0) == TAG_VECTOR
1030 }
1031
1032 #[inline(always)]
1033 pub fn is_map(&self) -> bool {
1034 is_boxed(self.0) && matches!(get_tag(self.0), TAG_MAP | TAG_HASHMAP)
1035 }
1036
1037 #[inline(always)]
1038 pub fn is_lambda(&self) -> bool {
1039 is_boxed(self.0) && get_tag(self.0) == TAG_LAMBDA
1040 }
1041
1042 #[inline(always)]
1043 pub fn is_native_fn(&self) -> bool {
1044 is_boxed(self.0) && get_tag(self.0) == TAG_NATIVE_FN
1045 }
1046
1047 #[inline(always)]
1048 pub fn is_thunk(&self) -> bool {
1049 is_boxed(self.0) && get_tag(self.0) == TAG_THUNK
1050 }
1051
1052 #[inline(always)]
1053 pub fn is_record(&self) -> bool {
1054 is_boxed(self.0) && get_tag(self.0) == TAG_RECORD
1055 }
1056
1057 #[inline(always)]
1058 pub fn as_int(&self) -> Option<i64> {
1059 if !is_boxed(self.0) {
1060 return None;
1061 }
1062 match get_tag(self.0) {
1063 TAG_INT_SMALL => {
1064 let payload = get_payload(self.0);
1065 let val = if payload & INT_SIGN_BIT != 0 {
1066 (payload | !PAYLOAD_MASK) as i64
1067 } else {
1068 payload as i64
1069 };
1070 Some(val)
1071 }
1072 TAG_INT_BIG => Some(unsafe { *self.borrow_ref::<i64>() }),
1073 _ => None,
1074 }
1075 }
1076
1077 #[inline(always)]
1078 pub fn as_float(&self) -> Option<f64> {
1079 if !is_boxed(self.0) {
1080 return Some(f64::from_bits(self.0));
1081 }
1082 match get_tag(self.0) {
1083 TAG_INT_SMALL => {
1084 let payload = get_payload(self.0);
1085 let val = if payload & INT_SIGN_BIT != 0 {
1086 (payload | !PAYLOAD_MASK) as i64
1087 } else {
1088 payload as i64
1089 };
1090 Some(val as f64)
1091 }
1092 TAG_INT_BIG => Some(unsafe { *self.borrow_ref::<i64>() } as f64),
1093 _ => None,
1094 }
1095 }
1096
1097 #[inline(always)]
1098 pub fn as_bool(&self) -> Option<bool> {
1099 if self.0 == Value::TRUE.0 {
1100 Some(true)
1101 } else if self.0 == Value::FALSE.0 {
1102 Some(false)
1103 } else {
1104 None
1105 }
1106 }
1107
1108 pub fn as_str(&self) -> Option<&str> {
1109 if is_boxed(self.0) && get_tag(self.0) == TAG_STRING {
1110 Some(unsafe { self.borrow_ref::<String>() })
1111 } else {
1112 None
1113 }
1114 }
1115
1116 pub fn as_string_rc(&self) -> Option<Rc<String>> {
1117 if is_boxed(self.0) && get_tag(self.0) == TAG_STRING {
1118 Some(unsafe { self.get_rc::<String>() })
1119 } else {
1120 None
1121 }
1122 }
1123
1124 pub fn as_symbol(&self) -> Option<String> {
1125 self.as_symbol_spur().map(resolve)
1126 }
1127
1128 pub fn as_symbol_spur(&self) -> Option<Spur> {
1129 if is_boxed(self.0) && get_tag(self.0) == TAG_SYMBOL {
1130 let payload = get_payload(self.0);
1131 Some(unsafe { std::mem::transmute::<u32, Spur>(payload as u32) })
1132 } else {
1133 None
1134 }
1135 }
1136
1137 pub fn as_keyword(&self) -> Option<String> {
1138 self.as_keyword_spur().map(resolve)
1139 }
1140
1141 pub fn as_keyword_spur(&self) -> Option<Spur> {
1142 if is_boxed(self.0) && get_tag(self.0) == TAG_KEYWORD {
1143 let payload = get_payload(self.0);
1144 Some(unsafe { std::mem::transmute::<u32, Spur>(payload as u32) })
1145 } else {
1146 None
1147 }
1148 }
1149
1150 pub fn as_char(&self) -> Option<char> {
1151 if is_boxed(self.0) && get_tag(self.0) == TAG_CHAR {
1152 let payload = get_payload(self.0);
1153 char::from_u32(payload as u32)
1154 } else {
1155 None
1156 }
1157 }
1158
1159 pub fn as_list(&self) -> Option<&[Value]> {
1160 if is_boxed(self.0) && get_tag(self.0) == TAG_LIST {
1161 Some(unsafe { self.borrow_ref::<Vec<Value>>() })
1162 } else {
1163 None
1164 }
1165 }
1166
1167 pub fn as_list_rc(&self) -> Option<Rc<Vec<Value>>> {
1168 if is_boxed(self.0) && get_tag(self.0) == TAG_LIST {
1169 Some(unsafe { self.get_rc::<Vec<Value>>() })
1170 } else {
1171 None
1172 }
1173 }
1174
1175 pub fn as_seq(&self) -> Option<&[Value]> {
1177 self.as_list().or_else(|| self.as_vector())
1178 }
1179
1180 pub fn as_vector(&self) -> Option<&[Value]> {
1181 if is_boxed(self.0) && get_tag(self.0) == TAG_VECTOR {
1182 Some(unsafe { self.borrow_ref::<Vec<Value>>() })
1183 } else {
1184 None
1185 }
1186 }
1187
1188 pub fn as_vector_rc(&self) -> Option<Rc<Vec<Value>>> {
1189 if is_boxed(self.0) && get_tag(self.0) == TAG_VECTOR {
1190 Some(unsafe { self.get_rc::<Vec<Value>>() })
1191 } else {
1192 None
1193 }
1194 }
1195
1196 pub fn as_map_rc(&self) -> Option<Rc<BTreeMap<Value, Value>>> {
1197 if is_boxed(self.0) && get_tag(self.0) == TAG_MAP {
1198 Some(unsafe { self.get_rc::<BTreeMap<Value, Value>>() })
1199 } else {
1200 None
1201 }
1202 }
1203
1204 pub fn as_hashmap_rc(&self) -> Option<Rc<hashbrown::HashMap<Value, Value>>> {
1205 if is_boxed(self.0) && get_tag(self.0) == TAG_HASHMAP {
1206 Some(unsafe { self.get_rc::<hashbrown::HashMap<Value, Value>>() })
1207 } else {
1208 None
1209 }
1210 }
1211
1212 #[inline(always)]
1214 pub fn as_hashmap_ref(&self) -> Option<&hashbrown::HashMap<Value, Value>> {
1215 if is_boxed(self.0) && get_tag(self.0) == TAG_HASHMAP {
1216 Some(unsafe { self.borrow_ref::<hashbrown::HashMap<Value, Value>>() })
1217 } else {
1218 None
1219 }
1220 }
1221
1222 #[inline(always)]
1224 pub fn as_map_ref(&self) -> Option<&BTreeMap<Value, Value>> {
1225 if is_boxed(self.0) && get_tag(self.0) == TAG_MAP {
1226 Some(unsafe { self.borrow_ref::<BTreeMap<Value, Value>>() })
1227 } else {
1228 None
1229 }
1230 }
1231
1232 #[inline(always)]
1236 pub fn with_hashmap_mut_if_unique<R>(
1237 &self,
1238 f: impl FnOnce(&mut hashbrown::HashMap<Value, Value>) -> R,
1239 ) -> Option<R> {
1240 if !is_boxed(self.0) || get_tag(self.0) != TAG_HASHMAP {
1241 return None;
1242 }
1243 let payload = get_payload(self.0);
1244 let ptr = payload_to_ptr(payload) as *const hashbrown::HashMap<Value, Value>;
1245 let rc = std::mem::ManuallyDrop::new(unsafe { Rc::from_raw(ptr) });
1246 if Rc::strong_count(&rc) != 1 {
1247 return None;
1248 }
1249 let ptr_mut = ptr as *mut hashbrown::HashMap<Value, Value>;
1251 Some(f(unsafe { &mut *ptr_mut }))
1252 }
1253
1254 #[inline(always)]
1257 pub fn with_map_mut_if_unique<R>(
1258 &self,
1259 f: impl FnOnce(&mut BTreeMap<Value, Value>) -> R,
1260 ) -> Option<R> {
1261 if !is_boxed(self.0) || get_tag(self.0) != TAG_MAP {
1262 return None;
1263 }
1264 let payload = get_payload(self.0);
1265 let ptr = payload_to_ptr(payload) as *const BTreeMap<Value, Value>;
1266 let rc = std::mem::ManuallyDrop::new(unsafe { Rc::from_raw(ptr) });
1267 if Rc::strong_count(&rc) != 1 {
1268 return None;
1269 }
1270 let ptr_mut = ptr as *mut BTreeMap<Value, Value>;
1271 Some(f(unsafe { &mut *ptr_mut }))
1272 }
1273
1274 pub fn into_hashmap_rc(self) -> Result<Rc<hashbrown::HashMap<Value, Value>>, Value> {
1277 if is_boxed(self.0) && get_tag(self.0) == TAG_HASHMAP {
1278 let payload = get_payload(self.0);
1279 let ptr = payload_to_ptr(payload) as *const hashbrown::HashMap<Value, Value>;
1280 std::mem::forget(self);
1282 Ok(unsafe { Rc::from_raw(ptr) })
1283 } else {
1284 Err(self)
1285 }
1286 }
1287
1288 pub fn into_map_rc(self) -> Result<Rc<BTreeMap<Value, Value>>, Value> {
1291 if is_boxed(self.0) && get_tag(self.0) == TAG_MAP {
1292 let payload = get_payload(self.0);
1293 let ptr = payload_to_ptr(payload) as *const BTreeMap<Value, Value>;
1294 std::mem::forget(self);
1295 Ok(unsafe { Rc::from_raw(ptr) })
1296 } else {
1297 Err(self)
1298 }
1299 }
1300
1301 pub fn as_lambda_rc(&self) -> Option<Rc<Lambda>> {
1302 if is_boxed(self.0) && get_tag(self.0) == TAG_LAMBDA {
1303 Some(unsafe { self.get_rc::<Lambda>() })
1304 } else {
1305 None
1306 }
1307 }
1308
1309 pub fn as_macro_rc(&self) -> Option<Rc<Macro>> {
1310 if is_boxed(self.0) && get_tag(self.0) == TAG_MACRO {
1311 Some(unsafe { self.get_rc::<Macro>() })
1312 } else {
1313 None
1314 }
1315 }
1316
1317 pub fn as_native_fn_rc(&self) -> Option<Rc<NativeFn>> {
1318 if is_boxed(self.0) && get_tag(self.0) == TAG_NATIVE_FN {
1319 Some(unsafe { self.get_rc::<NativeFn>() })
1320 } else {
1321 None
1322 }
1323 }
1324
1325 pub fn as_thunk_rc(&self) -> Option<Rc<Thunk>> {
1326 if is_boxed(self.0) && get_tag(self.0) == TAG_THUNK {
1327 Some(unsafe { self.get_rc::<Thunk>() })
1328 } else {
1329 None
1330 }
1331 }
1332
1333 pub fn as_record(&self) -> Option<&Record> {
1334 if is_boxed(self.0) && get_tag(self.0) == TAG_RECORD {
1335 Some(unsafe { self.borrow_ref::<Record>() })
1336 } else {
1337 None
1338 }
1339 }
1340
1341 pub fn as_record_rc(&self) -> Option<Rc<Record>> {
1342 if is_boxed(self.0) && get_tag(self.0) == TAG_RECORD {
1343 Some(unsafe { self.get_rc::<Record>() })
1344 } else {
1345 None
1346 }
1347 }
1348
1349 pub fn as_bytevector(&self) -> Option<&[u8]> {
1350 if is_boxed(self.0) && get_tag(self.0) == TAG_BYTEVECTOR {
1351 Some(unsafe { self.borrow_ref::<Vec<u8>>() })
1352 } else {
1353 None
1354 }
1355 }
1356
1357 pub fn as_bytevector_rc(&self) -> Option<Rc<Vec<u8>>> {
1358 if is_boxed(self.0) && get_tag(self.0) == TAG_BYTEVECTOR {
1359 Some(unsafe { self.get_rc::<Vec<u8>>() })
1360 } else {
1361 None
1362 }
1363 }
1364
1365 pub fn as_f64_array(&self) -> Option<&[f64]> {
1366 if is_boxed(self.0) && get_tag(self.0) == TAG_F64_ARRAY {
1367 Some(unsafe { self.borrow_ref::<Vec<f64>>() })
1368 } else {
1369 None
1370 }
1371 }
1372
1373 pub fn as_f64_array_rc(&self) -> Option<Rc<Vec<f64>>> {
1374 if is_boxed(self.0) && get_tag(self.0) == TAG_F64_ARRAY {
1375 Some(unsafe { self.get_rc::<Vec<f64>>() })
1376 } else {
1377 None
1378 }
1379 }
1380
1381 pub fn as_i64_array(&self) -> Option<&[i64]> {
1382 if is_boxed(self.0) && get_tag(self.0) == TAG_I64_ARRAY {
1383 Some(unsafe { self.borrow_ref::<Vec<i64>>() })
1384 } else {
1385 None
1386 }
1387 }
1388
1389 pub fn as_i64_array_rc(&self) -> Option<Rc<Vec<i64>>> {
1390 if is_boxed(self.0) && get_tag(self.0) == TAG_I64_ARRAY {
1391 Some(unsafe { self.get_rc::<Vec<i64>>() })
1392 } else {
1393 None
1394 }
1395 }
1396
1397 pub fn as_stream(&self) -> Option<&StreamBox> {
1398 if is_boxed(self.0) && get_tag(self.0) == TAG_STREAM {
1399 Some(unsafe { self.borrow_ref::<StreamBox>() })
1400 } else {
1401 None
1402 }
1403 }
1404
1405 pub fn as_stream_rc(&self) -> Option<Rc<StreamBox>> {
1406 if is_boxed(self.0) && get_tag(self.0) == TAG_STREAM {
1407 Some(unsafe { self.get_rc::<StreamBox>() })
1408 } else {
1409 None
1410 }
1411 }
1412
1413 pub fn as_prompt_rc(&self) -> Option<Rc<Prompt>> {
1414 if is_boxed(self.0) && get_tag(self.0) == TAG_PROMPT {
1415 Some(unsafe { self.get_rc::<Prompt>() })
1416 } else {
1417 None
1418 }
1419 }
1420
1421 pub fn as_message_rc(&self) -> Option<Rc<Message>> {
1422 if is_boxed(self.0) && get_tag(self.0) == TAG_MESSAGE {
1423 Some(unsafe { self.get_rc::<Message>() })
1424 } else {
1425 None
1426 }
1427 }
1428
1429 pub fn as_conversation_rc(&self) -> Option<Rc<Conversation>> {
1430 if is_boxed(self.0) && get_tag(self.0) == TAG_CONVERSATION {
1431 Some(unsafe { self.get_rc::<Conversation>() })
1432 } else {
1433 None
1434 }
1435 }
1436
1437 pub fn as_tool_def_rc(&self) -> Option<Rc<ToolDefinition>> {
1438 if is_boxed(self.0) && get_tag(self.0) == TAG_TOOL_DEF {
1439 Some(unsafe { self.get_rc::<ToolDefinition>() })
1440 } else {
1441 None
1442 }
1443 }
1444
1445 pub fn as_agent_rc(&self) -> Option<Rc<Agent>> {
1446 if is_boxed(self.0) && get_tag(self.0) == TAG_AGENT {
1447 Some(unsafe { self.get_rc::<Agent>() })
1448 } else {
1449 None
1450 }
1451 }
1452
1453 pub fn as_multimethod_rc(&self) -> Option<Rc<MultiMethod>> {
1454 if is_boxed(self.0) && get_tag(self.0) == TAG_MULTIMETHOD {
1455 Some(unsafe { self.get_rc::<MultiMethod>() })
1456 } else {
1457 None
1458 }
1459 }
1460}
1461
1462impl Clone for Value {
1465 #[inline(always)]
1466 fn clone(&self) -> Self {
1467 if !is_boxed(self.0) {
1468 return Value(self.0);
1470 }
1471 let tag = get_tag(self.0);
1472 match tag {
1473 TAG_NIL | TAG_FALSE | TAG_TRUE | TAG_INT_SMALL | TAG_CHAR | TAG_SYMBOL
1475 | TAG_KEYWORD => Value(self.0),
1476 _ => {
1478 let payload = get_payload(self.0);
1479 let ptr = payload_to_ptr(payload);
1480 unsafe {
1482 match tag {
1483 TAG_INT_BIG => Rc::increment_strong_count(ptr as *const i64),
1484 TAG_STRING => Rc::increment_strong_count(ptr as *const String),
1485 TAG_LIST | TAG_VECTOR => {
1486 Rc::increment_strong_count(ptr as *const Vec<Value>)
1487 }
1488 TAG_MAP => Rc::increment_strong_count(ptr as *const BTreeMap<Value, Value>),
1489 TAG_HASHMAP => Rc::increment_strong_count(
1490 ptr as *const hashbrown::HashMap<Value, Value>,
1491 ),
1492 TAG_LAMBDA => Rc::increment_strong_count(ptr as *const Lambda),
1493 TAG_MACRO => Rc::increment_strong_count(ptr as *const Macro),
1494 TAG_NATIVE_FN => Rc::increment_strong_count(ptr as *const NativeFn),
1495 TAG_PROMPT => Rc::increment_strong_count(ptr as *const Prompt),
1496 TAG_MESSAGE => Rc::increment_strong_count(ptr as *const Message),
1497 TAG_CONVERSATION => Rc::increment_strong_count(ptr as *const Conversation),
1498 TAG_TOOL_DEF => Rc::increment_strong_count(ptr as *const ToolDefinition),
1499 TAG_AGENT => Rc::increment_strong_count(ptr as *const Agent),
1500 TAG_THUNK => Rc::increment_strong_count(ptr as *const Thunk),
1501 TAG_RECORD => Rc::increment_strong_count(ptr as *const Record),
1502 TAG_BYTEVECTOR => Rc::increment_strong_count(ptr as *const Vec<u8>),
1503 TAG_MULTIMETHOD => Rc::increment_strong_count(ptr as *const MultiMethod),
1504 TAG_STREAM => Rc::increment_strong_count(ptr as *const StreamBox),
1505 TAG_F64_ARRAY => Rc::increment_strong_count(ptr as *const Vec<f64>),
1506 TAG_I64_ARRAY => Rc::increment_strong_count(ptr as *const Vec<i64>),
1507 _ => unreachable!("invalid heap tag in clone: {}", tag),
1508 }
1509 }
1510 Value(self.0)
1511 }
1512 }
1513 }
1514}
1515
1516impl Drop for Value {
1519 #[inline(always)]
1520 fn drop(&mut self) {
1521 if !is_boxed(self.0) {
1522 return; }
1524 let tag = get_tag(self.0);
1525 match tag {
1526 TAG_NIL | TAG_FALSE | TAG_TRUE | TAG_INT_SMALL | TAG_CHAR | TAG_SYMBOL
1528 | TAG_KEYWORD => {}
1529 _ => {
1531 let payload = get_payload(self.0);
1532 let ptr = payload_to_ptr(payload);
1533 unsafe {
1534 match tag {
1535 TAG_INT_BIG => drop(Rc::from_raw(ptr as *const i64)),
1536 TAG_STRING => drop(Rc::from_raw(ptr as *const String)),
1537 TAG_LIST | TAG_VECTOR => drop(Rc::from_raw(ptr as *const Vec<Value>)),
1538 TAG_MAP => drop(Rc::from_raw(ptr as *const BTreeMap<Value, Value>)),
1539 TAG_HASHMAP => {
1540 drop(Rc::from_raw(ptr as *const hashbrown::HashMap<Value, Value>))
1541 }
1542 TAG_LAMBDA => drop(Rc::from_raw(ptr as *const Lambda)),
1543 TAG_MACRO => drop(Rc::from_raw(ptr as *const Macro)),
1544 TAG_NATIVE_FN => drop(Rc::from_raw(ptr as *const NativeFn)),
1545 TAG_PROMPT => drop(Rc::from_raw(ptr as *const Prompt)),
1546 TAG_MESSAGE => drop(Rc::from_raw(ptr as *const Message)),
1547 TAG_CONVERSATION => drop(Rc::from_raw(ptr as *const Conversation)),
1548 TAG_TOOL_DEF => drop(Rc::from_raw(ptr as *const ToolDefinition)),
1549 TAG_AGENT => drop(Rc::from_raw(ptr as *const Agent)),
1550 TAG_THUNK => drop(Rc::from_raw(ptr as *const Thunk)),
1551 TAG_RECORD => drop(Rc::from_raw(ptr as *const Record)),
1552 TAG_BYTEVECTOR => drop(Rc::from_raw(ptr as *const Vec<u8>)),
1553 TAG_MULTIMETHOD => drop(Rc::from_raw(ptr as *const MultiMethod)),
1554 TAG_STREAM => drop(Rc::from_raw(ptr as *const StreamBox)),
1555 TAG_F64_ARRAY => drop(Rc::from_raw(ptr as *const Vec<f64>)),
1556 TAG_I64_ARRAY => drop(Rc::from_raw(ptr as *const Vec<i64>)),
1557 _ => {} }
1559 }
1560 }
1561 }
1562 }
1563}
1564
1565impl PartialEq for Value {
1568 fn eq(&self, other: &Self) -> bool {
1569 if self.0 == other.0 {
1571 if !is_boxed(self.0) {
1575 let f = f64::from_bits(self.0);
1576 if f.is_nan() {
1578 return false;
1579 }
1580 return true;
1581 }
1582 return true;
1583 }
1584 match (self.view(), other.view()) {
1586 (ValueView::Nil, ValueView::Nil) => true,
1587 (ValueView::Bool(a), ValueView::Bool(b)) => a == b,
1588 (ValueView::Int(a), ValueView::Int(b)) => a == b,
1589 (ValueView::Float(a), ValueView::Float(b)) => a == b,
1590 (ValueView::String(a), ValueView::String(b)) => a == b,
1591 (ValueView::Symbol(a), ValueView::Symbol(b)) => a == b,
1592 (ValueView::Keyword(a), ValueView::Keyword(b)) => a == b,
1593 (ValueView::Char(a), ValueView::Char(b)) => a == b,
1594 (ValueView::List(a), ValueView::List(b)) => a == b,
1595 (ValueView::Vector(a), ValueView::Vector(b)) => a == b,
1596 (ValueView::Map(a), ValueView::Map(b)) => a == b,
1597 (ValueView::HashMap(a), ValueView::HashMap(b)) => a == b,
1598 (ValueView::Record(a), ValueView::Record(b)) => {
1599 a.type_tag == b.type_tag && a.fields == b.fields
1600 }
1601 (ValueView::Bytevector(a), ValueView::Bytevector(b)) => a == b,
1602 (ValueView::F64Array(a), ValueView::F64Array(b)) => {
1603 a.len() == b.len()
1604 && a.iter()
1605 .zip(b.iter())
1606 .all(|(x, y)| x.to_bits() == y.to_bits())
1607 }
1608 (ValueView::I64Array(a), ValueView::I64Array(b)) => a == b,
1609 (ValueView::Stream(a), ValueView::Stream(b)) => Rc::ptr_eq(&a, &b),
1610 _ => false,
1611 }
1612 }
1613}
1614
1615impl Eq for Value {}
1616
1617impl Hash for Value {
1620 fn hash<H: Hasher>(&self, state: &mut H) {
1621 match self.view() {
1622 ValueView::Nil => 0u8.hash(state),
1623 ValueView::Bool(b) => {
1624 1u8.hash(state);
1625 b.hash(state);
1626 }
1627 ValueView::Int(n) => {
1628 2u8.hash(state);
1629 n.hash(state);
1630 }
1631 ValueView::Float(f) => {
1632 3u8.hash(state);
1633 let bits = if f == 0.0 { 0u64 } else { f.to_bits() };
1635 bits.hash(state);
1636 }
1637 ValueView::String(s) => {
1638 4u8.hash(state);
1639 s.hash(state);
1640 }
1641 ValueView::Symbol(s) => {
1642 5u8.hash(state);
1643 s.hash(state);
1644 }
1645 ValueView::Keyword(s) => {
1646 6u8.hash(state);
1647 s.hash(state);
1648 }
1649 ValueView::Char(c) => {
1650 7u8.hash(state);
1651 c.hash(state);
1652 }
1653 ValueView::List(l) => {
1654 8u8.hash(state);
1655 l.hash(state);
1656 }
1657 ValueView::Vector(v) => {
1658 9u8.hash(state);
1659 v.hash(state);
1660 }
1661 ValueView::Record(r) => {
1662 10u8.hash(state);
1663 r.type_tag.hash(state);
1664 r.fields.hash(state);
1665 }
1666 ValueView::Bytevector(bv) => {
1667 11u8.hash(state);
1668 bv.hash(state);
1669 }
1670 ValueView::F64Array(arr) => {
1671 26u8.hash(state);
1672 for v in arr.iter() {
1673 v.to_bits().hash(state);
1674 }
1675 }
1676 ValueView::I64Array(arr) => {
1677 27u8.hash(state);
1678 arr.hash(state);
1679 }
1680 ValueView::Stream(s) => {
1681 25u8.hash(state);
1682 (Rc::as_ptr(&s) as usize).hash(state);
1683 }
1684 _ => {}
1685 }
1686 }
1687}
1688
1689impl PartialOrd for Value {
1692 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1693 Some(self.cmp(other))
1694 }
1695}
1696
1697impl Ord for Value {
1698 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1699 use std::cmp::Ordering;
1700 fn type_order(v: &Value) -> u8 {
1701 match v.view() {
1702 ValueView::Nil => 0,
1703 ValueView::Bool(_) => 1,
1704 ValueView::Int(_) => 2,
1705 ValueView::Float(_) => 3,
1706 ValueView::Char(_) => 4,
1707 ValueView::String(_) => 5,
1708 ValueView::Symbol(_) => 6,
1709 ValueView::Keyword(_) => 7,
1710 ValueView::List(_) => 8,
1711 ValueView::Vector(_) => 9,
1712 ValueView::Map(_) => 10,
1713 ValueView::HashMap(_) => 11,
1714 ValueView::Record(_) => 12,
1715 ValueView::Bytevector(_) => 13,
1716 ValueView::F64Array(_) => 14,
1717 ValueView::I64Array(_) => 15,
1718 ValueView::Stream(_) => 16,
1719 _ => 17,
1720 }
1721 }
1722 match (self.view(), other.view()) {
1723 (ValueView::Nil, ValueView::Nil) => Ordering::Equal,
1724 (ValueView::Bool(a), ValueView::Bool(b)) => a.cmp(&b),
1725 (ValueView::Int(a), ValueView::Int(b)) => a.cmp(&b),
1726 (ValueView::Float(a), ValueView::Float(b)) => a.total_cmp(&b),
1727 (ValueView::String(a), ValueView::String(b)) => a.cmp(&b),
1728 (ValueView::Symbol(a), ValueView::Symbol(b)) => compare_spurs(a, b),
1729 (ValueView::Keyword(a), ValueView::Keyword(b)) => compare_spurs(a, b),
1730 (ValueView::Char(a), ValueView::Char(b)) => a.cmp(&b),
1731 (ValueView::List(a), ValueView::List(b)) => a.cmp(&b),
1732 (ValueView::Vector(a), ValueView::Vector(b)) => a.cmp(&b),
1733 (ValueView::Record(a), ValueView::Record(b)) => {
1734 compare_spurs(a.type_tag, b.type_tag).then_with(|| a.fields.cmp(&b.fields))
1735 }
1736 (ValueView::Bytevector(a), ValueView::Bytevector(b)) => a.cmp(&b),
1737 (ValueView::I64Array(a), ValueView::I64Array(b)) => a.cmp(&b),
1738 (ValueView::F64Array(a), ValueView::F64Array(b)) => a
1739 .iter()
1740 .zip(b.iter())
1741 .map(|(x, y)| x.total_cmp(y))
1742 .find(|o| *o != std::cmp::Ordering::Equal)
1743 .unwrap_or_else(|| a.len().cmp(&b.len())),
1744 _ => type_order(self).cmp(&type_order(other)),
1745 }
1746 }
1747}
1748
1749fn truncate(s: &str, max: usize) -> String {
1752 let mut iter = s.chars();
1753 let prefix: String = iter.by_ref().take(max).collect();
1754 if iter.next().is_none() {
1755 prefix
1756 } else {
1757 format!("{prefix}...")
1758 }
1759}
1760
1761impl fmt::Display for Value {
1762 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1763 match self.view() {
1764 ValueView::Nil => write!(f, "nil"),
1765 ValueView::Bool(true) => write!(f, "#t"),
1766 ValueView::Bool(false) => write!(f, "#f"),
1767 ValueView::Int(n) => write!(f, "{n}"),
1768 ValueView::Float(n) => {
1769 if n.fract() == 0.0 {
1770 write!(f, "{n:.1}")
1771 } else {
1772 write!(f, "{n}")
1773 }
1774 }
1775 ValueView::String(s) => write!(f, "\"{s}\""),
1776 ValueView::Symbol(s) => with_resolved(s, |name| write!(f, "{name}")),
1777 ValueView::Keyword(s) => with_resolved(s, |name| write!(f, ":{name}")),
1778 ValueView::Char(c) => match c {
1779 ' ' => write!(f, "#\\space"),
1780 '\n' => write!(f, "#\\newline"),
1781 '\t' => write!(f, "#\\tab"),
1782 '\r' => write!(f, "#\\return"),
1783 '\0' => write!(f, "#\\nul"),
1784 _ => write!(f, "#\\{c}"),
1785 },
1786 ValueView::List(items) => {
1787 write!(f, "(")?;
1788 for (i, item) in items.iter().enumerate() {
1789 if i > 0 {
1790 write!(f, " ")?;
1791 }
1792 write!(f, "{item}")?;
1793 }
1794 write!(f, ")")
1795 }
1796 ValueView::Vector(items) => {
1797 write!(f, "[")?;
1798 for (i, item) in items.iter().enumerate() {
1799 if i > 0 {
1800 write!(f, " ")?;
1801 }
1802 write!(f, "{item}")?;
1803 }
1804 write!(f, "]")
1805 }
1806 ValueView::Map(map) => {
1807 write!(f, "{{")?;
1808 for (i, (k, v)) in map.iter().enumerate() {
1809 if i > 0 {
1810 write!(f, " ")?;
1811 }
1812 write!(f, "{k} {v}")?;
1813 }
1814 write!(f, "}}")
1815 }
1816 ValueView::HashMap(map) => {
1817 let mut entries: Vec<_> = map.iter().collect();
1818 entries.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
1819 write!(f, "{{")?;
1820 for (i, (k, v)) in entries.iter().enumerate() {
1821 if i > 0 {
1822 write!(f, " ")?;
1823 }
1824 write!(f, "{k} {v}")?;
1825 }
1826 write!(f, "}}")
1827 }
1828 ValueView::Lambda(l) => {
1829 if let Some(name) = &l.name {
1830 with_resolved(*name, |n| write!(f, "<lambda {n}>"))
1831 } else {
1832 write!(f, "<lambda>")
1833 }
1834 }
1835 ValueView::Macro(m) => with_resolved(m.name, |n| write!(f, "<macro {n}>")),
1836 ValueView::NativeFn(n) => write!(f, "<native-fn {}>", n.name),
1837 ValueView::Prompt(p) => write!(f, "<prompt {} messages>", p.messages.len()),
1838 ValueView::Message(m) => {
1839 write!(f, "<message {} \"{}\">", m.role, truncate(&m.content, 40))
1840 }
1841 ValueView::Conversation(c) => {
1842 write!(f, "<conversation {} messages>", c.messages.len())
1843 }
1844 ValueView::ToolDef(t) => write!(f, "<tool {}>", t.name),
1845 ValueView::Agent(a) => write!(f, "<agent {}>", a.name),
1846 ValueView::Thunk(t) => {
1847 if t.forced.borrow().is_some() {
1848 write!(f, "<promise (forced)>")
1849 } else {
1850 write!(f, "<promise>")
1851 }
1852 }
1853 ValueView::Record(r) => {
1854 with_resolved(r.type_tag, |tag| write!(f, "#<record {tag}"))?;
1855 for field in &r.fields {
1856 write!(f, " {field}")?;
1857 }
1858 write!(f, ">")
1859 }
1860 ValueView::Bytevector(bv) => {
1861 write!(f, "#u8(")?;
1862 for (i, byte) in bv.iter().enumerate() {
1863 if i > 0 {
1864 write!(f, " ")?;
1865 }
1866 write!(f, "{byte}")?;
1867 }
1868 write!(f, ")")
1869 }
1870 ValueView::F64Array(arr) => {
1871 write!(f, "#f64(")?;
1872 for (i, v) in arr.iter().enumerate() {
1873 if i > 0 {
1874 write!(f, " ")?;
1875 }
1876 write!(f, "{v}")?;
1877 }
1878 write!(f, ")")
1879 }
1880 ValueView::I64Array(arr) => {
1881 write!(f, "#i64(")?;
1882 for (i, v) in arr.iter().enumerate() {
1883 if i > 0 {
1884 write!(f, " ")?;
1885 }
1886 write!(f, "{v}")?;
1887 }
1888 write!(f, ")")
1889 }
1890 ValueView::MultiMethod(m) => with_resolved(m.name, |n| write!(f, "<multimethod {n}>")),
1891 ValueView::Stream(s) => write!(f, "<stream:{}>", s.stream_type()),
1892 }
1893 }
1894}
1895
1896pub fn pretty_print(value: &Value, max_width: usize) -> String {
1902 let compact = format!("{value}");
1903 if compact.len() <= max_width {
1904 return compact;
1905 }
1906 let mut buf = String::new();
1907 pp_value(value, 0, max_width, &mut buf);
1908 buf
1909}
1910
1911fn pp_value(value: &Value, indent: usize, max_width: usize, buf: &mut String) {
1915 let compact = format!("{value}");
1916 let remaining = max_width.saturating_sub(indent);
1917 if compact.len() <= remaining {
1918 buf.push_str(&compact);
1919 return;
1920 }
1921
1922 match value.view() {
1923 ValueView::List(items) => {
1924 pp_seq(items.iter(), '(', ')', indent, max_width, buf);
1925 }
1926 ValueView::Vector(items) => {
1927 pp_seq(items.iter(), '[', ']', indent, max_width, buf);
1928 }
1929 ValueView::Map(map) => {
1930 pp_map(
1931 map.iter().map(|(k, v)| (k.clone(), v.clone())),
1932 indent,
1933 max_width,
1934 buf,
1935 );
1936 }
1937 ValueView::HashMap(map) => {
1938 let mut entries: Vec<_> = map.iter().map(|(k, v)| (k.clone(), v.clone())).collect();
1939 entries.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
1940 pp_map(entries.into_iter(), indent, max_width, buf);
1941 }
1942 _ => buf.push_str(&compact),
1943 }
1944}
1945
1946fn pp_seq<'a>(
1948 items: impl Iterator<Item = &'a Value>,
1949 open: char,
1950 close: char,
1951 indent: usize,
1952 max_width: usize,
1953 buf: &mut String,
1954) {
1955 buf.push(open);
1956 let child_indent = indent + 1;
1957 let pad = " ".repeat(child_indent);
1958 for (i, item) in items.enumerate() {
1959 if i > 0 {
1960 buf.push('\n');
1961 buf.push_str(&pad);
1962 }
1963 pp_value(item, child_indent, max_width, buf);
1964 }
1965 buf.push(close);
1966}
1967
1968fn pp_map(
1970 entries: impl Iterator<Item = (Value, Value)>,
1971 indent: usize,
1972 max_width: usize,
1973 buf: &mut String,
1974) {
1975 buf.push('{');
1976 let child_indent = indent + 1;
1977 let pad = " ".repeat(child_indent);
1978 for (i, (k, v)) in entries.enumerate() {
1979 if i > 0 {
1980 buf.push('\n');
1981 buf.push_str(&pad);
1982 }
1983 let key_str = format!("{k}");
1985 buf.push_str(&key_str);
1986
1987 let inline_indent = child_indent + key_str.len() + 1;
1989 let compact_val = format!("{v}");
1990 let remaining = max_width.saturating_sub(inline_indent);
1991
1992 if compact_val.len() <= remaining {
1993 buf.push(' ');
1995 buf.push_str(&compact_val);
1996 } else if is_compound(&v) {
1997 let nested_indent = child_indent + 2;
1999 let nested_pad = " ".repeat(nested_indent);
2000 buf.push('\n');
2001 buf.push_str(&nested_pad);
2002 pp_value(&v, nested_indent, max_width, buf);
2003 } else {
2004 buf.push(' ');
2006 buf.push_str(&compact_val);
2007 }
2008 }
2009 buf.push('}');
2010}
2011
2012fn is_compound(value: &Value) -> bool {
2014 matches!(
2015 value.view(),
2016 ValueView::List(_) | ValueView::Vector(_) | ValueView::Map(_) | ValueView::HashMap(_)
2017 )
2018}
2019
2020impl fmt::Debug for Value {
2023 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2024 match self.view() {
2025 ValueView::Nil => write!(f, "Nil"),
2026 ValueView::Bool(b) => write!(f, "Bool({b})"),
2027 ValueView::Int(n) => write!(f, "Int({n})"),
2028 ValueView::Float(n) => write!(f, "Float({n})"),
2029 ValueView::String(s) => write!(f, "String({:?})", &**s),
2030 ValueView::Symbol(s) => write!(f, "Symbol({})", resolve(s)),
2031 ValueView::Keyword(s) => write!(f, "Keyword({})", resolve(s)),
2032 ValueView::Char(c) => write!(f, "Char({c:?})"),
2033 ValueView::List(items) => write!(f, "List({items:?})"),
2034 ValueView::Vector(items) => write!(f, "Vector({items:?})"),
2035 ValueView::Map(map) => write!(f, "Map({map:?})"),
2036 ValueView::HashMap(map) => write!(f, "HashMap({map:?})"),
2037 ValueView::Lambda(l) => write!(f, "{l:?}"),
2038 ValueView::Macro(m) => write!(f, "{m:?}"),
2039 ValueView::NativeFn(n) => write!(f, "{n:?}"),
2040 ValueView::Prompt(p) => write!(f, "{p:?}"),
2041 ValueView::Message(m) => write!(f, "{m:?}"),
2042 ValueView::Conversation(c) => write!(f, "{c:?}"),
2043 ValueView::ToolDef(t) => write!(f, "{t:?}"),
2044 ValueView::Agent(a) => write!(f, "{a:?}"),
2045 ValueView::Thunk(t) => write!(f, "{t:?}"),
2046 ValueView::Record(r) => write!(f, "{r:?}"),
2047 ValueView::Bytevector(bv) => write!(f, "Bytevector({bv:?})"),
2048 ValueView::F64Array(arr) => write!(f, "F64Array({arr:?})"),
2049 ValueView::I64Array(arr) => write!(f, "I64Array({arr:?})"),
2050 ValueView::MultiMethod(m) => write!(f, "{m:?}"),
2051 ValueView::Stream(s) => write!(f, "Stream({:?})", s.stream_type()),
2052 }
2053 }
2054}
2055
2056#[derive(Debug, Clone)]
2060pub struct Env {
2061 pub bindings: Rc<RefCell<SpurMap<Spur, Value>>>,
2062 pub parent: Option<Rc<Env>>,
2063 pub version: Cell<u64>,
2064}
2065
2066impl Env {
2067 pub fn new() -> Self {
2068 Env {
2069 bindings: Rc::new(RefCell::new(SpurMap::new())),
2070 parent: None,
2071 version: Cell::new(0),
2072 }
2073 }
2074
2075 pub fn with_parent(parent: Rc<Env>) -> Self {
2076 Env {
2077 bindings: Rc::new(RefCell::new(SpurMap::new())),
2078 parent: Some(parent),
2079 version: Cell::new(0),
2080 }
2081 }
2082
2083 fn bump_version(&self) {
2084 self.version.set(self.version.get().wrapping_add(1));
2085 }
2086
2087 pub fn get(&self, name: Spur) -> Option<Value> {
2088 if let Some(val) = self.bindings.borrow().get(&name) {
2089 Some(val.clone())
2090 } else if let Some(parent) = &self.parent {
2091 parent.get(name)
2092 } else {
2093 None
2094 }
2095 }
2096
2097 pub fn get_str(&self, name: &str) -> Option<Value> {
2098 self.get(intern(name))
2099 }
2100
2101 pub fn set(&self, name: Spur, val: Value) {
2102 self.bindings.borrow_mut().insert(name, val);
2103 self.bump_version();
2104 }
2105
2106 pub fn set_str(&self, name: &str, val: Value) {
2107 self.set(intern(name), val);
2108 }
2109
2110 pub fn update(&self, name: Spur, val: Value) {
2112 let mut bindings = self.bindings.borrow_mut();
2113 if let Some(entry) = bindings.get_mut(&name) {
2114 *entry = val;
2115 } else {
2116 bindings.insert(name, val);
2117 }
2118 drop(bindings);
2119 self.bump_version();
2120 }
2121
2122 pub fn take(&self, name: Spur) -> Option<Value> {
2124 let result = self.bindings.borrow_mut().remove(&name);
2125 if result.is_some() {
2126 self.bump_version();
2127 }
2128 result
2129 }
2130
2131 pub fn take_anywhere(&self, name: Spur) -> Option<Value> {
2133 if let Some(val) = self.bindings.borrow_mut().remove(&name) {
2134 self.bump_version();
2135 Some(val)
2136 } else if let Some(parent) = &self.parent {
2137 parent.take_anywhere(name)
2138 } else {
2139 None
2140 }
2141 }
2142
2143 pub fn set_existing(&self, name: Spur, val: Value) -> bool {
2145 let mut bindings = self.bindings.borrow_mut();
2146 if let Some(entry) = bindings.get_mut(&name) {
2147 *entry = val;
2148 drop(bindings);
2149 self.bump_version();
2150 true
2151 } else {
2152 drop(bindings);
2153 if let Some(parent) = &self.parent {
2154 parent.set_existing(name, val)
2155 } else {
2156 false
2157 }
2158 }
2159 }
2160
2161 pub fn all_names(&self) -> Vec<Spur> {
2163 let mut names: Vec<Spur> = self.bindings.borrow().keys().copied().collect();
2164 if let Some(parent) = &self.parent {
2165 names.extend(parent.all_names());
2166 }
2167 names.sort_unstable();
2168 names.dedup();
2169 names
2170 }
2171
2172 pub fn iter_bindings(&self, mut f: impl FnMut(Spur, &Value)) {
2174 let bindings = self.bindings.borrow();
2175 for (&spur, value) in bindings.iter() {
2176 f(spur, value);
2177 }
2178 }
2179
2180 pub fn get_local(&self, name: Spur) -> Option<Value> {
2182 self.bindings.borrow().get(&name).cloned()
2183 }
2184
2185 pub fn replace_bindings(&self, new_bindings: impl IntoIterator<Item = (Spur, Value)>) {
2188 let mut bindings = self.bindings.borrow_mut();
2189 bindings.clear();
2190 for (spur, value) in new_bindings {
2191 bindings.insert(spur, value);
2192 }
2193 drop(bindings);
2194 self.bump_version();
2195 }
2196}
2197
2198impl Default for Env {
2199 fn default() -> Self {
2200 Self::new()
2201 }
2202}
2203
2204#[cfg(test)]
2207mod tests {
2208 use super::*;
2209
2210 #[test]
2211 fn test_size_of_value() {
2212 assert_eq!(std::mem::size_of::<Value>(), 8);
2213 }
2214
2215 #[test]
2216 fn test_nil() {
2217 let v = Value::nil();
2218 assert!(v.is_nil());
2219 assert!(!v.is_truthy());
2220 assert_eq!(v.type_name(), "nil");
2221 assert_eq!(format!("{v}"), "nil");
2222 }
2223
2224 #[test]
2225 fn test_bool() {
2226 let t = Value::bool(true);
2227 let f = Value::bool(false);
2228 assert!(t.is_truthy());
2229 assert!(!f.is_truthy());
2230 assert_eq!(t.as_bool(), Some(true));
2231 assert_eq!(f.as_bool(), Some(false));
2232 assert_eq!(format!("{t}"), "#t");
2233 assert_eq!(format!("{f}"), "#f");
2234 }
2235
2236 #[test]
2237 fn test_small_int() {
2238 let v = Value::int(42);
2239 assert_eq!(v.as_int(), Some(42));
2240 assert_eq!(v.type_name(), "int");
2241 assert_eq!(format!("{v}"), "42");
2242
2243 let neg = Value::int(-100);
2244 assert_eq!(neg.as_int(), Some(-100));
2245 assert_eq!(format!("{neg}"), "-100");
2246
2247 let zero = Value::int(0);
2248 assert_eq!(zero.as_int(), Some(0));
2249 }
2250
2251 #[test]
2252 fn test_small_int_boundaries() {
2253 let max = Value::int(SMALL_INT_MAX);
2254 assert_eq!(max.as_int(), Some(SMALL_INT_MAX));
2255
2256 let min = Value::int(SMALL_INT_MIN);
2257 assert_eq!(min.as_int(), Some(SMALL_INT_MIN));
2258 }
2259
2260 #[test]
2261 fn test_big_int() {
2262 let big = Value::int(i64::MAX);
2263 assert_eq!(big.as_int(), Some(i64::MAX));
2264 assert_eq!(big.type_name(), "int");
2265
2266 let big_neg = Value::int(i64::MIN);
2267 assert_eq!(big_neg.as_int(), Some(i64::MIN));
2268
2269 let just_over = Value::int(SMALL_INT_MAX + 1);
2271 assert_eq!(just_over.as_int(), Some(SMALL_INT_MAX + 1));
2272 }
2273
2274 #[test]
2275 fn test_float() {
2276 let v = Value::float(3.14);
2277 assert_eq!(v.as_float(), Some(3.14));
2278 assert_eq!(v.type_name(), "float");
2279
2280 let neg = Value::float(-0.5);
2281 assert_eq!(neg.as_float(), Some(-0.5));
2282
2283 let inf = Value::float(f64::INFINITY);
2284 assert_eq!(inf.as_float(), Some(f64::INFINITY));
2285
2286 let neg_inf = Value::float(f64::NEG_INFINITY);
2287 assert_eq!(neg_inf.as_float(), Some(f64::NEG_INFINITY));
2288 }
2289
2290 #[test]
2291 fn test_float_nan() {
2292 let nan = Value::float(f64::NAN);
2293 let f = nan.as_float().unwrap();
2294 assert!(f.is_nan());
2295 }
2296
2297 #[test]
2298 fn test_string() {
2299 let v = Value::string("hello");
2300 assert_eq!(v.as_str(), Some("hello"));
2301 assert_eq!(v.type_name(), "string");
2302 assert_eq!(format!("{v}"), "\"hello\"");
2303 }
2304
2305 #[test]
2306 fn test_symbol() {
2307 let v = Value::symbol("foo");
2308 assert!(v.as_symbol_spur().is_some());
2309 assert_eq!(v.as_symbol(), Some("foo".to_string()));
2310 assert_eq!(v.type_name(), "symbol");
2311 assert_eq!(format!("{v}"), "foo");
2312 }
2313
2314 #[test]
2315 fn test_keyword() {
2316 let v = Value::keyword("bar");
2317 assert!(v.as_keyword_spur().is_some());
2318 assert_eq!(v.as_keyword(), Some("bar".to_string()));
2319 assert_eq!(v.type_name(), "keyword");
2320 assert_eq!(format!("{v}"), ":bar");
2321 }
2322
2323 #[test]
2324 fn test_char() {
2325 let v = Value::char('λ');
2326 assert_eq!(v.as_char(), Some('λ'));
2327 assert_eq!(v.type_name(), "char");
2328 }
2329
2330 #[test]
2331 fn test_list() {
2332 let v = Value::list(vec![Value::int(1), Value::int(2), Value::int(3)]);
2333 assert_eq!(v.as_list().unwrap().len(), 3);
2334 assert_eq!(v.type_name(), "list");
2335 assert_eq!(format!("{v}"), "(1 2 3)");
2336 }
2337
2338 #[test]
2339 fn test_clone_immediate() {
2340 let v = Value::int(42);
2341 let v2 = v.clone();
2342 assert_eq!(v.as_int(), v2.as_int());
2343 }
2344
2345 #[test]
2346 fn test_clone_heap() {
2347 let v = Value::string("hello");
2348 let v2 = v.clone();
2349 assert_eq!(v.as_str(), v2.as_str());
2350 assert_eq!(format!("{v}"), format!("{v2}"));
2352 }
2353
2354 #[test]
2355 fn test_equality() {
2356 assert_eq!(Value::int(42), Value::int(42));
2357 assert_ne!(Value::int(42), Value::int(43));
2358 assert_eq!(Value::nil(), Value::nil());
2359 assert_eq!(Value::bool(true), Value::bool(true));
2360 assert_ne!(Value::bool(true), Value::bool(false));
2361 assert_eq!(Value::string("a"), Value::string("a"));
2362 assert_ne!(Value::string("a"), Value::string("b"));
2363 assert_eq!(Value::symbol("x"), Value::symbol("x"));
2364 }
2365
2366 #[test]
2367 fn test_big_int_equality() {
2368 assert_eq!(Value::int(i64::MAX), Value::int(i64::MAX));
2369 assert_ne!(Value::int(i64::MAX), Value::int(i64::MIN));
2370 }
2371
2372 #[test]
2373 fn test_view_pattern_matching() {
2374 let v = Value::int(42);
2375 match v.view() {
2376 ValueView::Int(n) => assert_eq!(n, 42),
2377 _ => panic!("expected int"),
2378 }
2379
2380 let v = Value::string("hello");
2381 match v.view() {
2382 ValueView::String(s) => assert_eq!(&**s, "hello"),
2383 _ => panic!("expected string"),
2384 }
2385 }
2386
2387 #[test]
2388 fn test_env() {
2389 let env = Env::new();
2390 env.set_str("x", Value::int(42));
2391 assert_eq!(env.get_str("x"), Some(Value::int(42)));
2392 }
2393
2394 #[test]
2395 fn test_native_fn_simple() {
2396 let f = NativeFn::simple("add1", |args| Ok(args[0].clone()));
2397 let ctx = EvalContext::new();
2398 assert!((f.func)(&ctx, &[Value::int(42)]).is_ok());
2399 }
2400
2401 #[test]
2402 fn test_native_fn_with_ctx() {
2403 let f = NativeFn::with_ctx("get-depth", |ctx, _args| {
2404 Ok(Value::int(ctx.eval_depth.get() as i64))
2405 });
2406 let ctx = EvalContext::new();
2407 assert_eq!((f.func)(&ctx, &[]).unwrap(), Value::int(0));
2408 }
2409
2410 #[test]
2411 fn test_drop_doesnt_leak() {
2412 for _ in 0..10000 {
2414 let _ = Value::string("test");
2415 let _ = Value::list(vec![Value::int(1), Value::int(2)]);
2416 let _ = Value::int(i64::MAX); }
2418 }
2419
2420 #[test]
2421 fn test_is_truthy() {
2422 assert!(!Value::nil().is_truthy());
2423 assert!(!Value::bool(false).is_truthy());
2424 assert!(Value::bool(true).is_truthy());
2425 assert!(Value::int(0).is_truthy());
2426 assert!(Value::int(1).is_truthy());
2427 assert!(Value::string("").is_truthy());
2428 assert!(Value::list(vec![]).is_truthy());
2429 }
2430
2431 #[test]
2432 fn test_as_float_from_int() {
2433 assert_eq!(Value::int(42).as_float(), Some(42.0));
2434 assert_eq!(Value::float(3.14).as_float(), Some(3.14));
2435 }
2436
2437 #[test]
2438 fn test_next_gensym_unique() {
2439 let a = next_gensym("x");
2440 let b = next_gensym("x");
2441 let c = next_gensym("y");
2442 assert_ne!(a, b);
2443 assert_ne!(a, c);
2444 assert_ne!(b, c);
2445 assert!(a.starts_with("x__"));
2446 assert!(b.starts_with("x__"));
2447 assert!(c.starts_with("y__"));
2448 }
2449
2450 #[test]
2451 fn test_next_gensym_counter_does_not_panic_near_max() {
2452 GENSYM_COUNTER.with(|c| c.set(u64::MAX - 1));
2454 let a = next_gensym("z");
2455 assert!(a.contains(&(u64::MAX - 1).to_string()));
2456 let b = next_gensym("z");
2458 assert!(b.contains(&u64::MAX.to_string()));
2459 let c = next_gensym("z");
2461 assert!(c.contains("__0"));
2462 }
2463}