1use std::collections::{BTreeMap, HashMap};
2use std::rc::Rc;
3use std::sync::atomic::Ordering;
4use std::{cell::RefCell, future::Future, pin::Pin};
5
6use crate::harness::VmHarness;
7use crate::mcp::VmMcpClientHandle;
8use crate::BuiltinId;
9
10use super::{
11 VmAtomicHandle, VmChannelHandle, VmClosure, VmError, VmGenerator, VmRange, VmRngHandle,
12 VmStream, VmSyncPermitHandle,
13};
14
15pub type VmAsyncBuiltinFn =
17 Rc<dyn Fn(Vec<VmValue>) -> Pin<Box<dyn Future<Output = Result<VmValue, VmError>>>>>;
18
19#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct StructLayout {
22 struct_name: String,
23 field_names: Vec<String>,
24 field_indexes: HashMap<String, usize>,
25}
26
27impl StructLayout {
28 pub fn new(struct_name: impl Into<String>, field_names: Vec<String>) -> Self {
29 let mut deduped = Vec::with_capacity(field_names.len());
30 let mut field_indexes = HashMap::with_capacity(field_names.len());
31 for field_name in field_names {
32 if field_indexes.contains_key(&field_name) {
33 continue;
34 }
35 let index = deduped.len();
36 field_indexes.insert(field_name.clone(), index);
37 deduped.push(field_name);
38 }
39
40 Self {
41 struct_name: struct_name.into(),
42 field_names: deduped,
43 field_indexes,
44 }
45 }
46
47 pub fn from_map(struct_name: impl Into<String>, fields: &BTreeMap<String, VmValue>) -> Self {
48 Self::new(struct_name, fields.keys().cloned().collect())
49 }
50
51 pub fn struct_name(&self) -> &str {
52 &self.struct_name
53 }
54
55 pub fn field_names(&self) -> &[String] {
56 &self.field_names
57 }
58
59 pub fn field_index(&self, field_name: &str) -> Option<usize> {
60 if self.field_names.len() <= 8 {
61 return self
62 .field_names
63 .iter()
64 .position(|candidate| candidate == field_name);
65 }
66 self.field_indexes.get(field_name).copied()
67 }
68
69 pub fn with_appended_field(&self, field_name: String) -> Self {
70 if self.field_indexes.contains_key(&field_name) {
71 return self.clone();
72 }
73 let mut field_names = self.field_names.clone();
74 field_names.push(field_name);
75 Self::new(self.struct_name.clone(), field_names)
76 }
77}
78
79#[derive(Debug, Clone)]
81pub struct VmEnumVariant {
82 pub enum_name: Rc<str>,
83 pub variant: Rc<str>,
84 pub fields: Rc<Vec<VmValue>>,
85}
86
87impl VmEnumVariant {
88 pub fn has_enum_name(&self, enum_name: &str) -> bool {
89 self.enum_name.as_ref() == enum_name
90 }
91
92 pub fn is_variant(&self, enum_name: &str, variant: &str) -> bool {
93 self.has_enum_name(enum_name) && self.variant.as_ref() == variant
94 }
95}
96
97#[derive(Debug, Clone)]
104pub enum VmValue {
105 Int(i64),
106 Float(f64),
107 String(Rc<str>),
108 Bytes(Rc<Vec<u8>>),
109 Bool(bool),
110 Nil,
111 List(Rc<Vec<VmValue>>),
112 Dict(Rc<BTreeMap<String, VmValue>>),
113 Closure(Rc<VmClosure>),
114 BuiltinRef(Rc<str>),
118 BuiltinRefId {
121 id: BuiltinId,
122 name: Rc<str>,
123 },
124 Duration(i64),
125 EnumVariant(Rc<VmEnumVariant>),
126 StructInstance {
127 layout: Rc<StructLayout>,
128 fields: Rc<Vec<Option<VmValue>>>,
129 },
130 TaskHandle(Rc<str>),
131 Channel(Rc<VmChannelHandle>),
132 Atomic(Rc<VmAtomicHandle>),
133 Rng(Rc<VmRngHandle>),
134 SyncPermit(Rc<VmSyncPermitHandle>),
135 McpClient(Rc<VmMcpClientHandle>),
136 Set(Rc<Vec<VmValue>>),
137 Generator(Rc<VmGenerator>),
138 Stream(Rc<VmStream>),
139 Range(VmRange),
140 Iter(Rc<RefCell<crate::vm::iter::VmIter>>),
142 Pair(Rc<(VmValue, VmValue)>),
147 Harness(Rc<VmHarness>),
152}
153
154impl VmValue {
155 pub fn enum_variant(
156 enum_name: impl Into<Rc<str>>,
157 variant: impl Into<Rc<str>>,
158 fields: Vec<VmValue>,
159 ) -> Self {
160 VmValue::EnumVariant(Rc::new(VmEnumVariant {
161 enum_name: enum_name.into(),
162 variant: variant.into(),
163 fields: Rc::new(fields),
164 }))
165 }
166
167 pub fn task_handle(id: impl Into<Rc<str>>) -> Self {
168 VmValue::TaskHandle(id.into())
169 }
170
171 pub fn channel(handle: VmChannelHandle) -> Self {
172 VmValue::Channel(Rc::new(handle))
173 }
174
175 pub fn atomic(handle: VmAtomicHandle) -> Self {
176 VmValue::Atomic(Rc::new(handle))
177 }
178
179 pub fn rng(handle: VmRngHandle) -> Self {
180 VmValue::Rng(Rc::new(handle))
181 }
182
183 pub fn sync_permit(handle: VmSyncPermitHandle) -> Self {
184 VmValue::SyncPermit(Rc::new(handle))
185 }
186
187 pub fn mcp_client(handle: VmMcpClientHandle) -> Self {
188 VmValue::McpClient(Rc::new(handle))
189 }
190
191 pub fn generator(generator: VmGenerator) -> Self {
192 VmValue::Generator(Rc::new(generator))
193 }
194
195 pub fn stream(stream: VmStream) -> Self {
196 VmValue::Stream(Rc::new(stream))
197 }
198
199 pub fn harness(handle: VmHarness) -> Self {
200 VmValue::Harness(Rc::new(handle))
201 }
202
203 pub fn struct_instance(
204 struct_name: impl Into<Rc<str>>,
205 fields: BTreeMap<String, VmValue>,
206 ) -> Self {
207 Self::struct_instance_from_map(struct_name.into().to_string(), fields)
208 }
209
210 pub fn is_truthy(&self) -> bool {
211 match self {
212 VmValue::Bool(b) => *b,
213 VmValue::Nil => false,
214 VmValue::Int(n) => *n != 0,
215 VmValue::Float(n) => *n != 0.0,
216 VmValue::String(s) => !s.is_empty(),
217 VmValue::Bytes(bytes) => !bytes.is_empty(),
218 VmValue::List(l) => !l.is_empty(),
219 VmValue::Dict(d) => !d.is_empty(),
220 VmValue::Closure(_) => true,
221 VmValue::BuiltinRef(_) => true,
222 VmValue::BuiltinRefId { .. } => true,
223 VmValue::Duration(ms) => *ms != 0,
224 VmValue::EnumVariant(_) => true,
225 VmValue::StructInstance { .. } => true,
226 VmValue::TaskHandle(_) => true,
227 VmValue::Channel(_) => true,
228 VmValue::Atomic(_) => true,
229 VmValue::Rng(_) => true,
230 VmValue::SyncPermit(_) => true,
231 VmValue::McpClient(_) => true,
232 VmValue::Set(s) => !s.is_empty(),
233 VmValue::Generator(_) => true,
234 VmValue::Stream(_) => true,
235 VmValue::Range(_) => true,
238 VmValue::Iter(_) => true,
239 VmValue::Pair(_) => true,
240 VmValue::Harness(_) => true,
241 }
242 }
243
244 pub fn type_name(&self) -> &'static str {
245 match self {
246 VmValue::String(_) => "string",
247 VmValue::Bytes(_) => "bytes",
248 VmValue::Int(_) => "int",
249 VmValue::Float(_) => "float",
250 VmValue::Bool(_) => "bool",
251 VmValue::Nil => "nil",
252 VmValue::List(_) => "list",
253 VmValue::Dict(_) => "dict",
254 VmValue::Closure(_) => "closure",
255 VmValue::BuiltinRef(_) => "builtin",
256 VmValue::BuiltinRefId { .. } => "builtin",
257 VmValue::Duration(_) => "duration",
258 VmValue::EnumVariant(_) => "enum",
259 VmValue::StructInstance { .. } => "struct",
260 VmValue::TaskHandle(_) => "task_handle",
261 VmValue::Channel(_) => "channel",
262 VmValue::Atomic(_) => "atomic",
263 VmValue::Rng(_) => "rng",
264 VmValue::SyncPermit(_) => "sync_permit",
265 VmValue::McpClient(_) => "mcp_client",
266 VmValue::Set(_) => "set",
267 VmValue::Generator(_) => "generator",
268 VmValue::Stream(_) => "stream",
269 VmValue::Range(_) => "range",
270 VmValue::Iter(_) => "iter",
271 VmValue::Pair(_) => "pair",
272 VmValue::Harness(h) => h.type_name(),
273 }
274 }
275
276 pub fn struct_name(&self) -> Option<&str> {
277 match self {
278 VmValue::StructInstance { layout, .. } => Some(layout.struct_name()),
279 _ => None,
280 }
281 }
282
283 pub fn struct_field(&self, field_name: &str) -> Option<&VmValue> {
284 match self {
285 VmValue::StructInstance { layout, fields } => layout
286 .field_index(field_name)
287 .and_then(|index| fields.get(index))
288 .and_then(Option::as_ref),
289 _ => None,
290 }
291 }
292
293 pub fn struct_fields_map(&self) -> Option<BTreeMap<String, VmValue>> {
294 match self {
295 VmValue::StructInstance { layout, fields } => {
296 Some(struct_fields_to_map(layout, fields))
297 }
298 _ => None,
299 }
300 }
301
302 pub fn struct_instance_from_map(
303 struct_name: impl Into<String>,
304 fields: BTreeMap<String, VmValue>,
305 ) -> Self {
306 let layout = Rc::new(StructLayout::from_map(struct_name, &fields));
307 let slots = layout
308 .field_names()
309 .iter()
310 .map(|name| fields.get(name).cloned())
311 .collect();
312 VmValue::StructInstance {
313 layout,
314 fields: Rc::new(slots),
315 }
316 }
317
318 pub fn struct_instance_with_layout(
319 struct_name: impl Into<String>,
320 field_names: Vec<String>,
321 field_values: BTreeMap<String, VmValue>,
322 ) -> Self {
323 let layout = Rc::new(StructLayout::new(struct_name, field_names));
324 let fields = layout
325 .field_names()
326 .iter()
327 .map(|name| field_values.get(name).cloned())
328 .collect();
329 VmValue::StructInstance {
330 layout,
331 fields: Rc::new(fields),
332 }
333 }
334
335 pub fn struct_instance_with_property(
336 &self,
337 field_name: String,
338 value: VmValue,
339 ) -> Option<Self> {
340 let VmValue::StructInstance { layout, fields } = self else {
341 return None;
342 };
343
344 let mut new_fields = fields.as_ref().clone();
345 let layout = match layout.field_index(&field_name) {
346 Some(index) => {
347 if index >= new_fields.len() {
348 new_fields.resize(index + 1, None);
349 }
350 new_fields[index] = Some(value);
351 Rc::clone(layout)
352 }
353 None => {
354 let new_layout = Rc::new(layout.with_appended_field(field_name));
355 new_fields.push(Some(value));
356 new_layout
357 }
358 };
359
360 Some(VmValue::StructInstance {
361 layout,
362 fields: Rc::new(new_fields),
363 })
364 }
365
366 pub fn display(&self) -> String {
367 let mut out = String::new();
368 self.write_display(&mut out);
369 out
370 }
371
372 pub fn write_display(&self, out: &mut String) {
375 use std::fmt::Write;
376
377 match self {
378 VmValue::Int(n) => {
379 let _ = write!(out, "{n}");
380 }
381 VmValue::Float(n) => {
382 if *n == (*n as i64) as f64 && n.abs() < 1e15 {
383 let _ = write!(out, "{n:.1}");
384 } else {
385 let _ = write!(out, "{n}");
386 }
387 }
388 VmValue::String(s) => out.push_str(s),
389 VmValue::Bytes(bytes) => {
390 const MAX_PREVIEW_BYTES: usize = 32;
391
392 out.push_str("b\"");
393 for byte in bytes.iter().take(MAX_PREVIEW_BYTES) {
394 let _ = write!(out, "{byte:02x}");
395 }
396 if bytes.len() > MAX_PREVIEW_BYTES {
397 let _ = write!(out, "...+{}", bytes.len() - MAX_PREVIEW_BYTES);
398 }
399 out.push('"');
400 }
401 VmValue::Bool(b) => out.push_str(if *b { "true" } else { "false" }),
402 VmValue::Nil => out.push_str("nil"),
403 VmValue::List(items) => {
404 out.push('[');
405 for (i, item) in items.iter().enumerate() {
406 if i > 0 {
407 out.push_str(", ");
408 }
409 item.write_display(out);
410 }
411 out.push(']');
412 }
413 VmValue::Dict(map) => {
414 out.push('{');
415 for (i, (k, v)) in map.iter().enumerate() {
416 if i > 0 {
417 out.push_str(", ");
418 }
419 out.push_str(k);
420 out.push_str(": ");
421 v.write_display(out);
422 }
423 out.push('}');
424 }
425 VmValue::Closure(c) => {
426 let names: Vec<&str> = c.func.param_names().collect();
427 let _ = write!(out, "<fn({})>", names.join(", "));
428 }
429 VmValue::BuiltinRef(name) => {
430 let _ = write!(out, "<builtin {name}>");
431 }
432 VmValue::BuiltinRefId { name, .. } => {
433 let _ = write!(out, "<builtin {name}>");
434 }
435 VmValue::Duration(ms) => {
436 let sign = if *ms < 0 { "-" } else { "" };
437 let abs_ms = ms.unsigned_abs();
438 if abs_ms >= 604_800_000 && abs_ms % 604_800_000 == 0 {
439 let _ = write!(out, "{}{}w", sign, abs_ms / 604_800_000);
440 } else if abs_ms >= 86_400_000 && abs_ms % 86_400_000 == 0 {
441 let _ = write!(out, "{}{}d", sign, abs_ms / 86_400_000);
442 } else if abs_ms >= 3_600_000 && abs_ms % 3_600_000 == 0 {
443 let _ = write!(out, "{}{}h", sign, abs_ms / 3_600_000);
444 } else if abs_ms >= 60_000 && abs_ms % 60_000 == 0 {
445 let _ = write!(out, "{}{}m", sign, abs_ms / 60_000);
446 } else if abs_ms >= 1000 && abs_ms % 1000 == 0 {
447 let _ = write!(out, "{}{}s", sign, abs_ms / 1000);
448 } else {
449 let _ = write!(out, "{}{}ms", sign, abs_ms);
450 }
451 }
452 VmValue::EnumVariant(enum_variant) => {
453 if enum_variant.fields.is_empty() {
454 let _ = write!(out, "{}.{}", enum_variant.enum_name, enum_variant.variant);
455 } else {
456 let _ = write!(out, "{}.{}(", enum_variant.enum_name, enum_variant.variant);
457 for (i, v) in enum_variant.fields.iter().enumerate() {
458 if i > 0 {
459 out.push_str(", ");
460 }
461 v.write_display(out);
462 }
463 out.push(')');
464 }
465 }
466 VmValue::StructInstance { layout, fields } => {
467 let _ = write!(out, "{} {{", layout.struct_name());
468 for (i, (k, v)) in struct_fields_to_map(layout, fields).iter().enumerate() {
469 if i > 0 {
470 out.push_str(", ");
471 }
472 out.push_str(k);
473 out.push_str(": ");
474 v.write_display(out);
475 }
476 out.push('}');
477 }
478 VmValue::TaskHandle(id) => {
479 let _ = write!(out, "<task:{id}>");
480 }
481 VmValue::Channel(ch) => {
482 let _ = write!(out, "<channel:{}>", ch.name);
483 }
484 VmValue::Atomic(a) => {
485 let _ = write!(out, "<atomic:{}>", a.value.load(Ordering::SeqCst));
486 }
487 VmValue::Rng(_) => {
488 out.push_str("<rng>");
489 }
490 VmValue::SyncPermit(p) => {
491 let _ = write!(out, "<sync_permit:{}:{}>", p.kind(), p.key());
492 }
493 VmValue::McpClient(c) => {
494 let _ = write!(out, "<mcp_client:{}>", c.name);
495 }
496 VmValue::Set(items) => {
497 out.push_str("set(");
498 for (i, item) in items.iter().enumerate() {
499 if i > 0 {
500 out.push_str(", ");
501 }
502 item.write_display(out);
503 }
504 out.push(')');
505 }
506 VmValue::Generator(g) => {
507 if g.done.get() {
508 out.push_str("<generator (done)>");
509 } else {
510 out.push_str("<generator>");
511 }
512 }
513 VmValue::Stream(s) => {
514 if s.done.get() {
515 out.push_str("<stream (done)>");
516 } else {
517 out.push_str("<stream>");
518 }
519 }
520 VmValue::Range(r) => {
523 let _ = write!(out, "{} to {}", r.start, r.end);
524 if !r.inclusive {
525 out.push_str(" exclusive");
526 }
527 }
528 VmValue::Iter(h) => {
529 if matches!(&*h.borrow(), crate::vm::iter::VmIter::Exhausted) {
530 out.push_str("<iter (exhausted)>");
531 } else {
532 out.push_str("<iter>");
533 }
534 }
535 VmValue::Harness(h) => {
536 let _ = write!(out, "<{}>", h.type_name());
537 }
538 VmValue::Pair(p) => {
539 out.push('(');
540 p.0.write_display(out);
541 out.push_str(", ");
542 p.1.write_display(out);
543 out.push(')');
544 }
545 }
546 }
547
548 pub fn as_dict(&self) -> Option<&BTreeMap<String, VmValue>> {
550 if let VmValue::Dict(d) = self {
551 Some(d)
552 } else {
553 None
554 }
555 }
556
557 pub fn as_int(&self) -> Option<i64> {
558 if let VmValue::Int(n) = self {
559 Some(*n)
560 } else {
561 None
562 }
563 }
564
565 pub fn as_bytes(&self) -> Option<&[u8]> {
566 if let VmValue::Bytes(bytes) = self {
567 Some(bytes.as_slice())
568 } else {
569 None
570 }
571 }
572}
573
574pub fn struct_fields_to_map(
575 layout: &StructLayout,
576 fields: &[Option<VmValue>],
577) -> BTreeMap<String, VmValue> {
578 layout
579 .field_names()
580 .iter()
581 .enumerate()
582 .filter_map(|(index, name)| {
583 fields
584 .get(index)
585 .and_then(Option::as_ref)
586 .map(|value| (name.clone(), value.clone()))
587 })
588 .collect()
589}
590
591pub type VmBuiltinFn = Rc<dyn Fn(&[VmValue], &mut String) -> Result<VmValue, VmError>>;