1use crate::ast::Type;
2use crate::jit;
3use crate::number::{
4 float_from_int, float_is_nan, float_to_hash_bits, int_from_float, int_from_usize, LustFloat,
5 LustInt,
6};
7use crate::vm::{pop_vm_ptr, push_vm_ptr, VM};
8use alloc::{
9 borrow::ToOwned,
10 format,
11 rc::{Rc, Weak},
12 string::{String, ToString},
13 vec,
14 vec::Vec,
15};
16use core::cell::RefCell;
17use core::fmt;
18use core::hash::{Hash, Hasher};
19use core::{ptr, slice, str};
20use hashbrown::HashMap;
21#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
22pub struct TaskHandle(pub u64);
23impl TaskHandle {
24 pub fn id(&self) -> u64 {
25 self.0
26 }
27}
28
29#[derive(Clone, Debug)]
30pub enum ValueKey {
31 Int(LustInt),
32 Float(LustFloat),
33 String(Rc<String>),
34 Bool(bool),
35}
36
37impl ValueKey {
38 pub fn from_value(value: &Value) -> Option<Self> {
39 match value {
40 Value::Int(i) => Some(ValueKey::Int(*i)),
41 Value::Float(f) => Some(ValueKey::Float(*f)),
42 Value::String(s) => Some(ValueKey::String(s.clone())),
43 Value::Bool(b) => Some(ValueKey::Bool(*b)),
44 _ => None,
45 }
46 }
47
48 pub fn string<S>(value: S) -> Self
49 where
50 S: Into<String>,
51 {
52 ValueKey::String(Rc::new(value.into()))
53 }
54
55 pub fn to_value(&self) -> Value {
56 match self {
57 ValueKey::Int(i) => Value::Int(*i),
58 ValueKey::Float(f) => Value::Float(*f),
59 ValueKey::String(s) => Value::String(s.clone()),
60 ValueKey::Bool(b) => Value::Bool(*b),
61 }
62 }
63}
64
65impl PartialEq for ValueKey {
66 fn eq(&self, other: &Self) -> bool {
67 match (self, other) {
68 (ValueKey::Int(a), ValueKey::Int(b)) => a == b,
69 (ValueKey::Float(a), ValueKey::Float(b)) => {
70 if float_is_nan(*a) && float_is_nan(*b) {
71 true
72 } else {
73 a == b
74 }
75 }
76
77 (ValueKey::String(a), ValueKey::String(b)) => a == b,
78 (ValueKey::Bool(a), ValueKey::Bool(b)) => a == b,
79 _ => false,
80 }
81 }
82}
83
84impl Eq for ValueKey {}
85impl Hash for ValueKey {
86 fn hash<H: Hasher>(&self, state: &mut H) {
87 match self {
88 ValueKey::Int(i) => {
89 0u8.hash(state);
90 i.hash(state);
91 }
92
93 ValueKey::Float(f) => {
94 1u8.hash(state);
95 if float_is_nan(*f) {
96 u64::MAX.hash(state);
97 } else {
98 float_to_hash_bits(*f).hash(state);
99 }
100 }
101
102 ValueKey::String(s) => {
103 2u8.hash(state);
104 s.hash(state);
105 }
106
107 ValueKey::Bool(b) => {
108 3u8.hash(state);
109 b.hash(state);
110 }
111 }
112 }
113}
114
115impl fmt::Display for ValueKey {
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 match self {
118 ValueKey::Int(i) => write!(f, "{}", i),
119 ValueKey::Float(fl) => write!(f, "{}", fl),
120 ValueKey::String(s) => write!(f, "{}", s),
121 ValueKey::Bool(b) => write!(f, "{}", b),
122 }
123 }
124}
125
126impl From<LustInt> for ValueKey {
127 fn from(value: LustInt) -> Self {
128 ValueKey::Int(value)
129 }
130}
131
132impl From<LustFloat> for ValueKey {
133 fn from(value: LustFloat) -> Self {
134 ValueKey::Float(value)
135 }
136}
137
138impl From<bool> for ValueKey {
139 fn from(value: bool) -> Self {
140 ValueKey::Bool(value)
141 }
142}
143
144impl From<String> for ValueKey {
145 fn from(value: String) -> Self {
146 ValueKey::String(Rc::new(value))
147 }
148}
149
150impl From<&str> for ValueKey {
151 fn from(value: &str) -> Self {
152 ValueKey::String(Rc::new(value.to_owned()))
153 }
154}
155
156impl From<Rc<String>> for ValueKey {
157 fn from(value: Rc<String>) -> Self {
158 ValueKey::String(value)
159 }
160}
161
162#[repr(u8)]
163#[derive(Debug, Clone, Copy, PartialEq, Eq)]
164pub enum ValueTag {
165 Nil,
166 Bool,
167 Int,
168 Float,
169 String,
170 Array,
171 Tuple,
172 Map,
173 Struct,
174 Enum,
175 Function,
176 NativeFunction,
177 Closure,
178 Iterator,
179 Task,
180}
181
182impl ValueTag {
183 #[inline]
184 pub const fn as_u8(self) -> u8 {
185 self as u8
186 }
187}
188
189#[derive(Debug, Clone, Copy, PartialEq, Eq)]
190pub enum FieldStorage {
191 Strong,
192 Weak,
193}
194
195#[derive(Debug)]
196pub struct StructLayout {
197 name: String,
198 field_names: Vec<Rc<String>>,
199 field_lookup_ptr: HashMap<usize, usize>,
200 field_lookup_str: HashMap<String, usize>,
201 field_storage: Vec<FieldStorage>,
202 field_types: Vec<Type>,
203 weak_targets: Vec<Option<Type>>,
204}
205
206impl StructLayout {
207 pub fn new(
208 name: String,
209 field_names: Vec<Rc<String>>,
210 field_storage: Vec<FieldStorage>,
211 field_types: Vec<Type>,
212 weak_targets: Vec<Option<Type>>,
213 ) -> Self {
214 debug_assert_eq!(
215 field_names.len(),
216 field_storage.len(),
217 "StructLayout::new expects field names and storage metadata to align"
218 );
219 debug_assert_eq!(
220 field_names.len(),
221 field_types.len(),
222 "StructLayout::new expects field names and type metadata to align"
223 );
224 debug_assert_eq!(
225 field_names.len(),
226 weak_targets.len(),
227 "StructLayout::new expects field names and weak target metadata to align"
228 );
229 let mut field_lookup_ptr = HashMap::with_capacity(field_names.len());
230 let mut field_lookup_str = HashMap::with_capacity(field_names.len());
231 for (index, field_name_rc) in field_names.iter().enumerate() {
232 let ptr = Rc::as_ptr(field_name_rc) as usize;
233 field_lookup_ptr.insert(ptr, index);
234 field_lookup_str.insert((**field_name_rc).clone(), index);
235 }
236
237 Self {
238 name,
239 field_names,
240 field_lookup_ptr,
241 field_lookup_str,
242 field_storage,
243 field_types,
244 weak_targets,
245 }
246 }
247
248 #[inline]
249 pub fn name(&self) -> &str {
250 &self.name
251 }
252
253 #[inline]
254 pub fn field_names(&self) -> &[Rc<String>] {
255 &self.field_names
256 }
257
258 #[inline]
259 pub fn index_of_rc(&self, key: &Rc<String>) -> Option<usize> {
260 let ptr = Rc::as_ptr(key) as usize;
261 self.field_lookup_ptr
262 .get(&ptr)
263 .copied()
264 .or_else(|| self.field_lookup_str.get(key.as_str()).copied())
265 }
266
267 #[inline]
268 pub fn index_of_str(&self, key: &str) -> Option<usize> {
269 self.field_lookup_str.get(key).copied()
270 }
271
272 #[inline]
273 pub fn field_storage(&self, index: usize) -> FieldStorage {
274 self.field_storage[index]
275 }
276
277 #[inline]
278 pub fn field_type(&self, index: usize) -> &Type {
279 &self.field_types[index]
280 }
281
282 #[inline]
283 pub fn weak_target(&self, index: usize) -> Option<&Type> {
284 self.weak_targets[index].as_ref()
285 }
286
287 #[inline]
288 pub fn is_weak(&self, index: usize) -> bool {
289 matches!(self.field_storage(index), FieldStorage::Weak)
290 }
291
292 pub fn canonicalize_field_value(&self, index: usize, value: Value) -> Result<Value, String> {
293 match self.field_storage(index) {
294 FieldStorage::Strong => Ok(value),
295 FieldStorage::Weak => self.canonicalize_weak_field(index, value),
296 }
297 }
298
299 pub fn materialize_field_value(&self, index: usize, value: Value) -> Value {
300 match self.field_storage(index) {
301 FieldStorage::Strong => value,
302 FieldStorage::Weak => self.materialize_weak_field(value),
303 }
304 }
305
306 fn canonicalize_weak_field(&self, index: usize, value: Value) -> Result<Value, String> {
307 let field_name = self.field_names[index].as_str();
308 match value {
309 Value::Enum {
310 enum_name,
311 variant,
312 values,
313 } if enum_name == "Option" => {
314 if variant == "Some" {
315 if let Some(inner_values) = values {
316 if let Some(inner) = inner_values.get(0) {
317 let coerced = self.to_weak_struct(field_name, inner.clone())?;
318 Ok(Value::enum_variant("Option", "Some", vec![coerced]))
319 } else {
320 Ok(Value::enum_unit("Option", "None"))
321 }
322 } else {
323 Ok(Value::enum_unit("Option", "None"))
324 }
325 } else if variant == "None" {
326 Ok(Value::enum_unit("Option", "None"))
327 } else {
328 Err(format!(
329 "Struct '{}' field '{}' uses 'ref' and must store Option values; received variant '{}'",
330 self.name, field_name, variant
331 ))
332 }
333 }
334
335 Value::Nil => Ok(Value::enum_unit("Option", "None")),
336 other => {
337 let coerced = self.to_weak_struct(field_name, other)?;
338 Ok(Value::enum_variant("Option", "Some", vec![coerced]))
339 }
340 }
341 }
342
343 fn materialize_weak_field(&self, value: Value) -> Value {
344 match value {
345 Value::Enum {
346 enum_name,
347 variant,
348 values,
349 } if enum_name == "Option" => {
350 if variant == "Some" {
351 if let Some(inner_values) = values {
352 if let Some(inner) = inner_values.get(0) {
353 match inner {
354 Value::WeakStruct(ref weak) => {
355 if let Some(upgraded) = weak.upgrade() {
356 Value::enum_variant("Option", "Some", vec![upgraded])
357 } else {
358 Value::enum_unit("Option", "None")
359 }
360 }
361
362 _ => Value::enum_variant("Option", "Some", vec![inner.clone()]),
363 }
364 } else {
365 Value::enum_unit("Option", "None")
366 }
367 } else {
368 Value::enum_unit("Option", "None")
369 }
370 } else {
371 Value::enum_unit("Option", "None")
372 }
373 }
374
375 Value::Nil => Value::enum_unit("Option", "None"),
376 other => Value::enum_variant("Option", "Some", vec![other]),
377 }
378 }
379
380 fn to_weak_struct(&self, field_name: &str, value: Value) -> Result<Value, String> {
381 match value {
382 Value::Struct {
383 name,
384 layout,
385 fields,
386 } => Ok(Value::WeakStruct(WeakStructRef::new(name, layout, &fields))),
387 Value::WeakStruct(_) => Ok(value),
388 other => {
389 let ty = other.type_of();
390 Err(format!(
391 "Struct '{}' field '{}' expects a struct reference but received value of type '{:?}'",
392 self.name, field_name, ty
393 ))
394 }
395 }
396 }
397}
398
399#[repr(C, u8)]
400#[derive(Clone)]
401pub enum Value {
402 Nil,
403 Bool(bool),
404 Int(LustInt),
405 Float(LustFloat),
406 String(Rc<String>),
407 Array(Rc<RefCell<Vec<Value>>>),
408 Tuple(Rc<Vec<Value>>),
409 Map(Rc<RefCell<HashMap<ValueKey, Value>>>),
410 Struct {
411 name: String,
412 layout: Rc<StructLayout>,
413 fields: Rc<RefCell<Vec<Value>>>,
414 },
415 WeakStruct(WeakStructRef),
416 Enum {
417 enum_name: String,
418 variant: String,
419 values: Option<Rc<Vec<Value>>>,
420 },
421 Function(usize),
422 NativeFunction(NativeFn),
423 Closure {
424 function_idx: usize,
425 upvalues: Rc<Vec<Upvalue>>,
426 },
427 Iterator(Rc<RefCell<IteratorState>>),
428 Task(TaskHandle),
429}
430
431#[derive(Debug, Clone)]
432pub struct WeakStructRef {
433 name: String,
434 layout: Rc<StructLayout>,
435 fields: Weak<RefCell<Vec<Value>>>,
436}
437
438impl WeakStructRef {
439 pub fn new(name: String, layout: Rc<StructLayout>, fields: &Rc<RefCell<Vec<Value>>>) -> Self {
440 Self {
441 name,
442 layout,
443 fields: Rc::downgrade(fields),
444 }
445 }
446
447 pub fn upgrade(&self) -> Option<Value> {
448 self.fields.upgrade().map(|fields| Value::Struct {
449 name: self.name.clone(),
450 layout: self.layout.clone(),
451 fields,
452 })
453 }
454
455 pub fn struct_name(&self) -> &str {
456 &self.name
457 }
458}
459
460#[derive(Clone)]
461pub enum IteratorState {
462 Array {
463 items: Vec<Value>,
464 index: usize,
465 },
466 MapPairs {
467 items: Vec<(ValueKey, Value)>,
468 index: usize,
469 },
470}
471
472#[derive(Clone)]
473pub struct Upvalue {
474 value: Rc<RefCell<Value>>,
475}
476
477impl Upvalue {
478 pub fn new(value: Value) -> Self {
479 Self {
480 value: Rc::new(RefCell::new(value)),
481 }
482 }
483
484 pub fn get(&self) -> Value {
485 self.value.borrow().clone()
486 }
487
488 pub fn set(&self, value: Value) {
489 *self.value.borrow_mut() = value;
490 }
491}
492
493impl fmt::Debug for Upvalue {
494 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
495 write!(f, "Upvalue({:?})", self.value.borrow())
496 }
497}
498
499#[derive(Debug, Clone)]
500pub enum NativeCallResult {
501 Return(Value),
502 Yield(Value),
503 Stop(Value),
504}
505
506impl From<Value> for NativeCallResult {
507 fn from(value: Value) -> Self {
508 NativeCallResult::Return(value)
509 }
510}
511
512pub type NativeFn = Rc<dyn Fn(&[Value]) -> Result<NativeCallResult, String>>;
513#[derive(Debug, Clone, Copy, PartialEq, Eq)]
514pub enum ValueType {
515 Nil,
516 Bool,
517 Int,
518 Float,
519 String,
520 Array,
521 Tuple,
522 Map,
523 Struct,
524 Enum,
525 Function,
526 NativeFunction,
527 Closure,
528 Iterator,
529 Task,
530}
531
532impl Value {
533 #[inline]
534 pub fn tag(&self) -> ValueTag {
535 match self {
536 Value::Nil => ValueTag::Nil,
537 Value::Bool(_) => ValueTag::Bool,
538 Value::Int(_) => ValueTag::Int,
539 Value::Float(_) => ValueTag::Float,
540 Value::String(_) => ValueTag::String,
541 Value::Array(_) => ValueTag::Array,
542 Value::Tuple(_) => ValueTag::Tuple,
543 Value::Map(_) => ValueTag::Map,
544 Value::Struct { .. } | Value::WeakStruct(_) => ValueTag::Struct,
545 Value::Enum { .. } => ValueTag::Enum,
546 Value::Function(_) => ValueTag::Function,
547 Value::NativeFunction(_) => ValueTag::NativeFunction,
548 Value::Closure { .. } => ValueTag::Closure,
549 Value::Iterator(_) => ValueTag::Iterator,
550 Value::Task(_) => ValueTag::Task,
551 }
552 }
553
554 pub fn type_of(&self) -> ValueType {
555 match self {
556 Value::Nil => ValueType::Nil,
557 Value::Bool(_) => ValueType::Bool,
558 Value::Int(_) => ValueType::Int,
559 Value::Float(_) => ValueType::Float,
560 Value::String(_) => ValueType::String,
561 Value::Array(_) => ValueType::Array,
562 Value::Tuple(_) => ValueType::Tuple,
563 Value::Map(_) => ValueType::Map,
564 Value::Struct { .. } | Value::WeakStruct(_) => ValueType::Struct,
565 Value::Enum { .. } => ValueType::Enum,
566 Value::Function(_) => ValueType::Function,
567 Value::NativeFunction(_) => ValueType::NativeFunction,
568 Value::Closure { .. } => ValueType::Closure,
569 Value::Iterator(_) => ValueType::Iterator,
570 Value::Task(_) => ValueType::Task,
571 }
572 }
573
574 pub fn is_truthy(&self) -> bool {
575 match self {
576 Value::Nil => false,
577 Value::Bool(false) => false,
578 Value::Enum {
579 enum_name, variant, ..
580 } if enum_name == "Option" && variant == "None" => false,
581 _ => true,
582 }
583 }
584
585 pub fn to_bool(&self) -> bool {
586 self.is_truthy()
587 }
588
589 pub fn as_int(&self) -> Option<LustInt> {
590 match self {
591 Value::Int(i) => Some(*i),
592 Value::Float(f) => Some(int_from_float(*f)),
593 _ => None,
594 }
595 }
596
597 pub fn as_float(&self) -> Option<LustFloat> {
598 match self {
599 Value::Float(f) => Some(*f),
600 Value::Int(i) => Some(float_from_int(*i)),
601 _ => None,
602 }
603 }
604
605 pub fn as_string(&self) -> Option<&str> {
606 match self {
607 Value::String(s) => Some(s.as_str()),
608 _ => None,
609 }
610 }
611
612 pub fn as_string_rc(&self) -> Option<Rc<String>> {
613 match self {
614 Value::String(s) => Some(s.clone()),
615 _ => None,
616 }
617 }
618
619 pub fn as_task_handle(&self) -> Option<TaskHandle> {
620 match self {
621 Value::Task(handle) => Some(*handle),
622 _ => None,
623 }
624 }
625
626 pub fn as_array(&self) -> Option<Vec<Value>> {
627 match self {
628 Value::Array(arr) => Some(arr.borrow().clone()),
629 _ => None,
630 }
631 }
632
633 pub fn array_len(&self) -> Option<usize> {
634 match self {
635 Value::Array(arr) => Some(arr.borrow().len()),
636 _ => None,
637 }
638 }
639
640 pub fn array_get(&self, index: usize) -> Option<Value> {
641 match self {
642 Value::Array(arr) => arr.borrow().get(index).cloned(),
643 _ => None,
644 }
645 }
646
647 pub fn array_push(&self, value: Value) -> Result<(), String> {
648 match self {
649 Value::Array(arr) => {
650 arr.borrow_mut().push(value);
651 Ok(())
652 }
653
654 _ => Err("Cannot push to non-array".to_string()),
655 }
656 }
657
658 pub fn array_pop(&self) -> Result<Option<Value>, String> {
659 match self {
660 Value::Array(arr) => Ok(arr.borrow_mut().pop()),
661 _ => Err("Cannot pop from non-array".to_string()),
662 }
663 }
664
665 pub fn as_map(&self) -> Option<HashMap<ValueKey, Value>> {
666 match self {
667 Value::Map(map) => Some(map.borrow().clone()),
668 _ => None,
669 }
670 }
671
672 pub fn map_get(&self, key: &ValueKey) -> Option<Value> {
673 match self {
674 Value::Map(map) => map.borrow().get(key).cloned(),
675 _ => None,
676 }
677 }
678
679 pub fn map_set(&self, key: ValueKey, value: Value) -> Result<(), String> {
680 match self {
681 Value::Map(map) => {
682 map.borrow_mut().insert(key, value);
683 Ok(())
684 }
685
686 _ => Err("Cannot set key on non-map".to_string()),
687 }
688 }
689
690 pub fn map_has(&self, key: &ValueKey) -> Option<bool> {
691 match self {
692 Value::Map(map) => Some(map.borrow().contains_key(key)),
693 _ => None,
694 }
695 }
696
697 pub fn map_delete(&self, key: &ValueKey) -> Result<Option<Value>, String> {
698 match self {
699 Value::Map(map) => Ok(map.borrow_mut().remove(key)),
700 _ => Err("Cannot delete key from non-map".to_string()),
701 }
702 }
703
704 pub fn map_len(&self) -> Option<usize> {
705 match self {
706 Value::Map(map) => Some(map.borrow().len()),
707 _ => None,
708 }
709 }
710
711 pub fn string(s: impl Into<String>) -> Self {
712 Value::String(Rc::new(s.into()))
713 }
714
715 pub fn array(values: Vec<Value>) -> Self {
716 Value::Array(Rc::new(RefCell::new(values)))
717 }
718
719 pub fn tuple(values: Vec<Value>) -> Self {
720 Value::Tuple(Rc::new(values))
721 }
722
723 pub fn tuple_len(&self) -> Option<usize> {
724 match self {
725 Value::Tuple(values) => Some(values.len()),
726 _ => None,
727 }
728 }
729
730 pub fn tuple_get(&self, index: usize) -> Option<Value> {
731 match self {
732 Value::Tuple(values) => values.get(index).cloned(),
733 _ => None,
734 }
735 }
736
737 pub fn map(entries: HashMap<ValueKey, Value>) -> Self {
738 Value::Map(Rc::new(RefCell::new(entries)))
739 }
740
741 pub fn task(handle: TaskHandle) -> Self {
742 Value::Task(handle)
743 }
744
745 pub fn struct_get_field_rc(&self, field: &Rc<String>) -> Option<Value> {
746 match self {
747 Value::Struct { layout, fields, .. } => layout
748 .index_of_rc(field)
749 .or_else(|| layout.index_of_str(field.as_str()))
750 .and_then(|idx| {
751 fields
752 .borrow()
753 .get(idx)
754 .cloned()
755 .map(|value| layout.materialize_field_value(idx, value))
756 }),
757 _ => None,
758 }
759 }
760
761 pub fn struct_get_field(&self, field: &str) -> Option<Value> {
762 match self {
763 Value::Struct { layout, fields, .. } => layout.index_of_str(field).and_then(|idx| {
764 fields
765 .borrow()
766 .get(idx)
767 .cloned()
768 .map(|value| layout.materialize_field_value(idx, value))
769 }),
770 _ => None,
771 }
772 }
773
774 pub fn struct_get_field_indexed(&self, index: usize) -> Option<Value> {
775 match self {
776 Value::Struct { layout, fields, .. } => fields
777 .borrow()
778 .get(index)
779 .cloned()
780 .map(|value| layout.materialize_field_value(index, value)),
781 _ => None,
782 }
783 }
784
785 pub fn struct_set_field_rc(&self, field: &Rc<String>, value: Value) -> Result<(), String> {
786 match self {
787 Value::Struct { layout, .. } => {
788 if let Some(index) = layout
789 .index_of_rc(field)
790 .or_else(|| layout.index_of_str(field.as_str()))
791 {
792 self.struct_set_field_indexed(index, value)
793 } else {
794 Err(format!(
795 "Struct '{}' has no field '{}'",
796 layout.name(),
797 field.as_str()
798 ))
799 }
800 }
801
802 _ => Err("Attempted to set field on non-struct value".to_string()),
803 }
804 }
805
806 pub fn struct_set_field(&self, field: &str, value: Value) -> Result<(), String> {
807 match self {
808 Value::Struct { layout, .. } => {
809 if let Some(index) = layout.index_of_str(field) {
810 self.struct_set_field_indexed(index, value)
811 } else {
812 Err(format!(
813 "Struct '{}' has no field '{}'",
814 layout.name(),
815 field
816 ))
817 }
818 }
819
820 _ => Err("Attempted to set field on non-struct value".to_string()),
821 }
822 }
823
824 pub fn struct_set_field_indexed(&self, index: usize, value: Value) -> Result<(), String> {
825 match self {
826 Value::Struct {
827 name,
828 layout,
829 fields,
830 } => {
831 let mut borrowed = fields.borrow_mut();
832 if index < borrowed.len() {
833 let canonical = layout.canonicalize_field_value(index, value)?;
834 borrowed[index] = canonical;
835 Ok(())
836 } else {
837 Err(format!(
838 "Struct '{}' field index {} out of bounds (len {})",
839 name,
840 index,
841 borrowed.len()
842 ))
843 }
844 }
845
846 _ => Err("Attempted to set field on non-struct value".to_string()),
847 }
848 }
849
850 pub fn enum_unit(enum_name: impl Into<String>, variant: impl Into<String>) -> Self {
851 Value::Enum {
852 enum_name: enum_name.into(),
853 variant: variant.into(),
854 values: None,
855 }
856 }
857
858 pub fn enum_variant(
859 enum_name: impl Into<String>,
860 variant: impl Into<String>,
861 values: Vec<Value>,
862 ) -> Self {
863 Value::Enum {
864 enum_name: enum_name.into(),
865 variant: variant.into(),
866 values: Some(Rc::new(values)),
867 }
868 }
869
870 pub fn as_enum(&self) -> Option<(&str, &str, Option<&[Value]>)> {
871 match self {
872 Value::Enum {
873 enum_name,
874 variant,
875 values,
876 } => Some((
877 enum_name.as_str(),
878 variant.as_str(),
879 values.as_ref().map(|v| v.as_slice()),
880 )),
881 _ => None,
882 }
883 }
884
885 pub fn is_enum_variant(&self, enum_name: &str, variant: &str) -> bool {
886 match self {
887 Value::Enum {
888 enum_name: en,
889 variant: v,
890 ..
891 } => (enum_name.is_empty() || en == enum_name) && v == variant,
892 _ => false,
893 }
894 }
895
896 pub fn some(value: Value) -> Self {
897 Value::enum_variant("Option", "Some", vec![value])
898 }
899
900 pub fn none() -> Self {
901 Value::enum_unit("Option", "None")
902 }
903
904 pub fn ok(value: Value) -> Self {
905 Value::enum_variant("Result", "Ok", vec![value])
906 }
907
908 pub fn err(error: Value) -> Self {
909 Value::enum_variant("Result", "Err", vec![error])
910 }
911
912 pub fn to_string(&self) -> String {
913 format!("{}", self)
914 }
915}
916
917impl fmt::Debug for Value {
918 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
919 match self {
920 Value::Nil => write!(f, "Nil"),
921 Value::Bool(b) => write!(f, "Bool({})", b),
922 Value::Int(i) => write!(f, "Int({})", i),
923 Value::Float(fl) => write!(f, "Float({})", fl),
924 Value::String(s) => write!(f, "String({:?})", s),
925 Value::Array(arr) => write!(f, "Array({:?})", arr.borrow()),
926 Value::Tuple(values) => write!(f, "Tuple({:?})", values),
927 Value::Map(map) => write!(f, "Map({:?})", map.borrow()),
928 Value::Struct {
929 name,
930 layout,
931 fields,
932 } => {
933 let borrowed = fields.borrow();
934 let mut display_fields = Vec::with_capacity(borrowed.len());
935 for (idx, field_name) in layout.field_names().iter().enumerate() {
936 let value = borrowed.get(idx).cloned().unwrap_or(Value::Nil);
937 display_fields.push((field_name.as_str().to_string(), value));
938 }
939
940 write!(
941 f,
942 "Struct {{ name: {:?}, fields: {:?} }}",
943 name, display_fields
944 )
945 }
946
947 Value::WeakStruct(weak) => {
948 if let Some(upgraded) = weak.upgrade() {
949 write!(f, "WeakStruct({:?})", upgraded)
950 } else {
951 write!(f, "WeakStruct(<dangling>)")
952 }
953 }
954
955 Value::Enum {
956 enum_name,
957 variant,
958 values,
959 } => {
960 write!(
961 f,
962 "Enum {{ enum: {:?}, variant: {:?}, values: {:?} }}",
963 enum_name, variant, values
964 )
965 }
966
967 Value::Function(idx) => write!(f, "Function({})", idx),
968 Value::NativeFunction(_) => write!(f, "NativeFunction(<fn>)"),
969 Value::Closure {
970 function_idx,
971 upvalues,
972 } => {
973 write!(
974 f,
975 "Closure {{ function: {}, upvalues: {:?} }}",
976 function_idx, upvalues
977 )
978 }
979
980 Value::Iterator(_) => write!(f, "Iterator(<state>)"),
981 Value::Task(handle) => write!(f, "Task({})", handle.0),
982 }
983 }
984}
985
986impl fmt::Display for Value {
987 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
988 match self {
989 Value::Nil => write!(f, "nil"),
990 Value::Bool(b) => write!(f, "{}", b),
991 Value::Int(i) => write!(f, "{}", i),
992 Value::Float(fl) => write!(f, "{}", fl),
993 Value::String(s) => write!(f, "{}", s),
994 Value::Array(arr) => {
995 write!(f, "[")?;
996 let borrowed = arr.borrow();
997 for (i, val) in borrowed.iter().enumerate() {
998 if i > 0 {
999 write!(f, ", ")?;
1000 }
1001
1002 write!(f, "{}", val)?;
1003 }
1004
1005 write!(f, "]")
1006 }
1007
1008 Value::Tuple(values) => {
1009 write!(f, "(")?;
1010 for (i, val) in values.iter().enumerate() {
1011 if i > 0 {
1012 write!(f, ", ")?;
1013 }
1014
1015 write!(f, "{}", val)?;
1016 }
1017
1018 write!(f, ")")
1019 }
1020
1021 Value::Map(map) => {
1022 write!(f, "{{")?;
1023 let borrowed = map.borrow();
1024 for (i, (k, v)) in borrowed.iter().enumerate() {
1025 if i > 0 {
1026 write!(f, ", ")?;
1027 }
1028
1029 write!(f, "{}: {}", k, v)?;
1030 }
1031
1032 write!(f, "}}")
1033 }
1034
1035 Value::Struct {
1036 name,
1037 layout,
1038 fields,
1039 } => {
1040 let borrowed = fields.borrow();
1041 write!(f, "{} {{", name)?;
1042 for (i, field_name) in layout.field_names().iter().enumerate() {
1043 if i > 0 {
1044 write!(f, ", ")?;
1045 }
1046
1047 let value = borrowed.get(i).unwrap_or(&Value::Nil);
1048 write!(f, "{}: {}", field_name, value)?;
1049 }
1050
1051 write!(f, "}}")
1052 }
1053
1054 Value::WeakStruct(weak) => {
1055 if let Some(strong) = weak.upgrade() {
1056 strong.fmt(f)
1057 } else {
1058 write!(f, "nil")
1059 }
1060 }
1061
1062 Value::Enum {
1063 enum_name,
1064 variant,
1065 values,
1066 } => {
1067 write!(f, "{}.{}", enum_name, variant)?;
1068 if let Some(vals) = values {
1069 write!(f, "(")?;
1070 for (i, val) in vals.iter().enumerate() {
1071 if i > 0 {
1072 write!(f, ", ")?;
1073 }
1074
1075 write!(f, "{}", val)?;
1076 }
1077
1078 write!(f, ")")?;
1079 }
1080
1081 Ok(())
1082 }
1083
1084 Value::Function(idx) => write!(f, "<function@{}>", idx),
1085 Value::NativeFunction(_) => write!(f, "<native function>"),
1086 Value::Closure { function_idx, .. } => write!(f, "<closure@{}>", function_idx),
1087 Value::Iterator(_) => write!(f, "<iterator>"),
1088 Value::Task(handle) => write!(f, "<task {}>", handle.0),
1089 }
1090 }
1091}
1092
1093impl PartialEq for Value {
1094 fn eq(&self, other: &Self) -> bool {
1095 match (self, other) {
1096 (Value::Nil, Value::Nil) => true,
1097 (Value::Bool(a), Value::Bool(b)) => a == b,
1098 (Value::Int(a), Value::Int(b)) => a == b,
1099 (Value::Float(a), Value::Float(b)) => a == b,
1100 (Value::String(a), Value::String(b)) => a == b,
1101 (Value::Array(a), Value::Array(b)) => *a.borrow() == *b.borrow(),
1102 (Value::Tuple(a), Value::Tuple(b)) => *a == *b,
1103 (Value::Map(a), Value::Map(b)) => *a.borrow() == *b.borrow(),
1104 (
1105 Value::Struct {
1106 name: n1,
1107 layout: l1,
1108 fields: f1,
1109 },
1110 Value::Struct {
1111 name: n2,
1112 layout: l2,
1113 fields: f2,
1114 },
1115 ) => {
1116 if n1 != n2 {
1117 return false;
1118 }
1119
1120 let borrowed_f1 = f1.borrow();
1121 let borrowed_f2 = f2.borrow();
1122 if borrowed_f1.len() != borrowed_f2.len() {
1123 return false;
1124 }
1125
1126 if Rc::ptr_eq(l1, l2) {
1127 return borrowed_f1
1128 .iter()
1129 .zip(borrowed_f2.iter())
1130 .all(|(a, b)| a == b);
1131 }
1132
1133 l1.field_names()
1134 .iter()
1135 .enumerate()
1136 .all(|(idx, field_name)| {
1137 if let Some(other_idx) = l2.index_of_rc(field_name) {
1138 borrowed_f1
1139 .get(idx)
1140 .zip(borrowed_f2.get(other_idx))
1141 .map(|(a, b)| a == b)
1142 .unwrap_or(false)
1143 } else {
1144 false
1145 }
1146 })
1147 }
1148
1149 (Value::WeakStruct(a), Value::WeakStruct(b)) => match (a.upgrade(), b.upgrade()) {
1150 (Some(left), Some(right)) => left == right,
1151 (None, None) => true,
1152 _ => false,
1153 },
1154 (Value::WeakStruct(a), other) => a
1155 .upgrade()
1156 .map(|upgraded| upgraded == *other)
1157 .unwrap_or(matches!(other, Value::Nil)),
1158 (value, Value::WeakStruct(b)) => b
1159 .upgrade()
1160 .map(|upgraded| *value == upgraded)
1161 .unwrap_or(matches!(value, Value::Nil)),
1162 (
1163 Value::Enum {
1164 enum_name: e1,
1165 variant: v1,
1166 values: vals1,
1167 },
1168 Value::Enum {
1169 enum_name: e2,
1170 variant: v2,
1171 values: vals2,
1172 },
1173 ) => e1 == e2 && v1 == v2 && vals1 == vals2,
1174 (Value::Function(a), Value::Function(b)) => a == b,
1175 (
1176 Value::Closure {
1177 function_idx: f1,
1178 upvalues: u1,
1179 },
1180 Value::Closure {
1181 function_idx: f2,
1182 upvalues: u2,
1183 },
1184 ) => f1 == f2 && Rc::ptr_eq(u1, u2),
1185 (Value::Iterator(_), Value::Iterator(_)) => false,
1186 (Value::Task(a), Value::Task(b)) => a == b,
1187 _ => false,
1188 }
1189 }
1190}
1191
1192#[cfg(feature = "std")]
1193#[no_mangle]
1194pub unsafe extern "C" fn jit_array_get_safe(
1195 array_value_ptr: *const Value,
1196 index: i64,
1197 out: *mut Value,
1198) -> u8 {
1199 if array_value_ptr.is_null() || out.is_null() {
1200 eprintln!("❌ jit_array_get_safe: null pointer detected!");
1201 return 0;
1202 }
1203
1204 let array_value = &*array_value_ptr;
1205 let arr = match array_value {
1206 Value::Array(arr) => arr,
1207 _ => {
1208 return 0;
1209 }
1210 };
1211 if index < 0 {
1212 return 0;
1213 }
1214
1215 let idx = index as usize;
1216 let borrowed = match arr.try_borrow() {
1217 Ok(b) => b,
1218 Err(_) => {
1219 return 0;
1220 }
1221 };
1222 if idx >= borrowed.len() {
1223 return 0;
1224 }
1225
1226 ptr::write(out, borrowed[idx].clone());
1227 1
1228}
1229
1230#[cfg(feature = "std")]
1231#[no_mangle]
1232pub unsafe extern "C" fn jit_array_len_safe(array_value_ptr: *const Value) -> i64 {
1233 if array_value_ptr.is_null() {
1234 return -1;
1235 }
1236
1237 let array_value = &*array_value_ptr;
1238 match array_value {
1239 Value::Array(arr) => match arr.try_borrow() {
1240 Ok(borrowed) => int_from_usize(borrowed.len()),
1241 Err(_) => -1,
1242 },
1243 _ => -1,
1244 }
1245}
1246
1247#[cfg(feature = "std")]
1248#[no_mangle]
1249pub unsafe extern "C" fn jit_concat_safe(
1250 left_value_ptr: *const Value,
1251 right_value_ptr: *const Value,
1252 out: *mut Value,
1253) -> u8 {
1254 if left_value_ptr.is_null() || right_value_ptr.is_null() || out.is_null() {
1255 return 0;
1256 }
1257
1258 let left = &*left_value_ptr;
1259 let right = &*right_value_ptr;
1260 const NO_VM_ERROR: &str = "task API requires a running VM";
1261 let left_str = match VM::with_current(|vm| {
1262 let left_copy = left.clone();
1263 vm.value_to_string_for_concat(&left_copy)
1264 .map_err(|err| err.to_string())
1265 }) {
1266 Ok(rc) => rc,
1267 Err(err) if err == NO_VM_ERROR => Rc::new(left.to_string()),
1268 Err(_) => return 0,
1269 };
1270 let right_str = match VM::with_current(|vm| {
1271 let right_copy = right.clone();
1272 vm.value_to_string_for_concat(&right_copy)
1273 .map_err(|err| err.to_string())
1274 }) {
1275 Ok(rc) => rc,
1276 Err(err) if err == NO_VM_ERROR => Rc::new(right.to_string()),
1277 Err(_) => return 0,
1278 };
1279 let mut combined = String::with_capacity(left_str.len() + right_str.len());
1280 combined.push_str(left_str.as_ref());
1281 combined.push_str(right_str.as_ref());
1282 let result = Value::string(combined);
1283 ptr::write(out, result);
1284 1
1285}
1286
1287#[no_mangle]
1288pub unsafe extern "C" fn jit_guard_native_function(
1289 value_ptr: *const Value,
1290 expected_fn_ptr: *const (),
1291 register_index: u8,
1292) -> u8 {
1293 if value_ptr.is_null() || expected_fn_ptr.is_null() {
1294 jit::log(|| "jit_guard_native_function: null pointer input".to_string());
1295 return 0;
1296 }
1297
1298 match &*value_ptr {
1299 Value::NativeFunction(func) => {
1300 let actual = Rc::as_ptr(func) as *const ();
1301 if actual == expected_fn_ptr {
1302 1
1303 } else {
1304 jit::log(|| {
1305 format!(
1306 "jit_guard_native_function: pointer mismatch (reg {}) actual={:p} expected={:p}",
1307 register_index, actual, expected_fn_ptr
1308 )
1309 });
1310 0
1311 }
1312 }
1313
1314 other => {
1315 jit::log(|| {
1316 format!(
1317 "jit_guard_native_function: value not native in reg {} ({:?})",
1318 register_index,
1319 other.tag()
1320 )
1321 });
1322 0
1323 }
1324 }
1325}
1326
1327#[no_mangle]
1328pub unsafe extern "C" fn jit_call_native_safe(
1329 vm_ptr: *mut VM,
1330 callee_ptr: *const Value,
1331 expected_fn_ptr: *const (),
1332 args_ptr: *const Value,
1333 arg_count: u8,
1334 out: *mut Value,
1335) -> u8 {
1336 if vm_ptr.is_null() || callee_ptr.is_null() || expected_fn_ptr.is_null() || out.is_null() {
1337 jit::log(|| "jit_call_native_safe: null argument".to_string());
1338 return 0;
1339 }
1340
1341 let callee = &*callee_ptr;
1342 let native_fn = match callee {
1343 Value::NativeFunction(func) => func.clone(),
1344 other => {
1345 jit::log(|| {
1346 format!(
1347 "jit_call_native_safe: callee not native ({:?})",
1348 other.tag()
1349 )
1350 });
1351 return 0;
1352 }
1353 };
1354
1355 if Rc::as_ptr(&native_fn) as *const () != expected_fn_ptr {
1356 jit::log(|| {
1357 format!(
1358 "jit_call_native_safe: pointer mismatch actual={:p} expected={:p}",
1359 Rc::as_ptr(&native_fn),
1360 expected_fn_ptr
1361 )
1362 });
1363 return 0;
1364 }
1365
1366 let mut args = Vec::with_capacity(arg_count as usize);
1367 if arg_count > 0 {
1368 if args_ptr.is_null() {
1369 jit::log(|| "jit_call_native_safe: args_ptr null with non-zero arg_count".to_string());
1370 return 0;
1371 }
1372
1373 for i in 0..(arg_count as usize) {
1374 let arg = &*args_ptr.add(i);
1375 args.push(arg.clone());
1376 }
1377 }
1378
1379 push_vm_ptr(vm_ptr);
1380 let outcome = native_fn(&args);
1381 pop_vm_ptr();
1382
1383 let outcome = match outcome {
1384 Ok(result) => result,
1385 Err(err) => {
1386 jit::log(|| format!("jit_call_native_safe: native returned error: {}", err));
1387 return 0;
1388 }
1389 };
1390
1391 match outcome {
1392 NativeCallResult::Return(value) => {
1393 ptr::write(out, value);
1394 1
1395 }
1396
1397 NativeCallResult::Yield(_) => {
1398 jit::log(|| "jit_call_native_safe: native attempted to yield".to_string());
1399 0
1400 }
1401
1402 NativeCallResult::Stop(_) => {
1403 jit::log(|| "jit_call_native_safe: native attempted to stop".to_string());
1404 0
1405 }
1406 }
1407}
1408
1409#[no_mangle]
1410pub unsafe extern "C" fn jit_call_method_safe(
1411 object_ptr: *const Value,
1412 method_name_ptr: *const u8,
1413 method_name_len: usize,
1414 args_ptr: *const Value,
1415 arg_count: u8,
1416 out: *mut Value,
1417) -> u8 {
1418 if object_ptr.is_null() || method_name_ptr.is_null() || out.is_null() {
1419 return 0;
1420 }
1421
1422 if arg_count > 0 && args_ptr.is_null() {
1423 return 0;
1424 }
1425
1426 let method_name_slice = slice::from_raw_parts(method_name_ptr, method_name_len);
1427 let method_name = match str::from_utf8(method_name_slice) {
1428 Ok(s) => s,
1429 Err(_) => return 0,
1430 };
1431 let object = &*object_ptr;
1432 if matches!(object, Value::Struct { .. }) {
1433 return 0;
1434 }
1435
1436 let mut args = Vec::with_capacity(arg_count as usize);
1437 for i in 0..arg_count {
1438 let arg_ptr = args_ptr.add(i as usize);
1439 args.push((&*arg_ptr).clone());
1440 }
1441
1442 let result = match call_builtin_method_simple(object, method_name, args) {
1443 Ok(val) => val,
1444 Err(_) => return 0,
1445 };
1446 ptr::write(out, result);
1447 1
1448}
1449
1450fn call_builtin_method_simple(
1451 object: &Value,
1452 method_name: &str,
1453 args: Vec<Value>,
1454) -> Result<Value, String> {
1455 match object {
1456 Value::Struct { name, .. } => Err(format!(
1457 "User-defined methods on {} require deoptimization",
1458 name
1459 )),
1460 Value::Iterator(state_rc) => match method_name {
1461 "next" => {
1462 let mut state = state_rc.borrow_mut();
1463 match &mut *state {
1464 IteratorState::Array { items, index } => {
1465 if *index < items.len() {
1466 let v = items[*index].clone();
1467 *index += 1;
1468 Ok(Value::some(v))
1469 } else {
1470 Ok(Value::none())
1471 }
1472 }
1473
1474 IteratorState::MapPairs { items, index } => {
1475 if *index < items.len() {
1476 let (k, v) = items[*index].clone();
1477 *index += 1;
1478 Ok(Value::some(Value::array(vec![k.to_value(), v])))
1479 } else {
1480 Ok(Value::none())
1481 }
1482 }
1483 }
1484 }
1485
1486 _ => Err(format!(
1487 "Iterator method '{}' not supported in JIT",
1488 method_name
1489 )),
1490 },
1491 Value::Enum {
1492 enum_name,
1493 variant,
1494 values,
1495 } if enum_name == "Option" => match method_name {
1496 "unwrap" => {
1497 if variant == "Some" {
1498 if let Some(vals) = values {
1499 if vals.len() == 1 {
1500 Ok(vals[0].clone())
1501 } else {
1502 Err("Option::Some should have exactly 1 value".to_string())
1503 }
1504 } else {
1505 Err("Option::Some should have a value".to_string())
1506 }
1507 } else {
1508 Err("Called unwrap() on Option::None".to_string())
1509 }
1510 }
1511
1512 _ => Err(format!(
1513 "Option method '{}' not supported in JIT",
1514 method_name
1515 )),
1516 },
1517 Value::Array(arr) => match method_name {
1518 "len" => Ok(Value::Int(int_from_usize(arr.borrow().len()))),
1519 "push" => {
1520 let value = args
1521 .get(0)
1522 .cloned()
1523 .ok_or_else(|| "Array:push requires a value argument".to_string())?;
1524 arr.borrow_mut().push(value);
1525 Ok(Value::Nil)
1526 }
1527 "pop" => {
1528 let popped = arr.borrow_mut().pop();
1529 Ok(popped.map(Value::some).unwrap_or_else(Value::none))
1530 }
1531 "first" => {
1532 let borrowed = arr.borrow();
1533 Ok(borrowed
1534 .first()
1535 .cloned()
1536 .map(Value::some)
1537 .unwrap_or_else(Value::none))
1538 }
1539 "last" => {
1540 let borrowed = arr.borrow();
1541 Ok(borrowed
1542 .last()
1543 .cloned()
1544 .map(Value::some)
1545 .unwrap_or_else(Value::none))
1546 }
1547 "get" => {
1548 let index = args
1549 .get(0)
1550 .and_then(Value::as_int)
1551 .ok_or_else(|| "Array:get requires an integer index".to_string())?;
1552 let borrowed = arr.borrow();
1553 Ok(borrowed
1554 .get(index as usize)
1555 .cloned()
1556 .map(Value::some)
1557 .unwrap_or_else(Value::none))
1558 }
1559 "iter" => {
1560 let items = arr.borrow().clone();
1561 let iter = IteratorState::Array { items, index: 0 };
1562 Ok(Value::Iterator(Rc::new(RefCell::new(iter))))
1563 }
1564 _ => Err(format!(
1565 "Array method '{}' not supported in JIT",
1566 method_name
1567 )),
1568 },
1569 _ => Err(format!(
1570 "Method '{}' not supported in JIT (deoptimizing)",
1571 method_name
1572 )),
1573 }
1574}
1575
1576#[no_mangle]
1577pub unsafe extern "C" fn jit_get_field_safe(
1578 object_ptr: *const Value,
1579 field_name_ptr: *const u8,
1580 field_name_len: usize,
1581 out: *mut Value,
1582) -> u8 {
1583 if object_ptr.is_null() || field_name_ptr.is_null() || out.is_null() {
1584 return 0;
1585 }
1586
1587 let field_name_slice = slice::from_raw_parts(field_name_ptr, field_name_len);
1588 let field_name = match str::from_utf8(field_name_slice) {
1589 Ok(s) => s,
1590 Err(_) => return 0,
1591 };
1592 let object = &*object_ptr;
1593 let field_value = match object {
1594 Value::Struct { layout, fields, .. } => match layout.index_of_str(field_name) {
1595 Some(idx) => match fields.borrow().get(idx) {
1596 Some(val) => val.clone(),
1597 None => return 0,
1598 },
1599 None => return 0,
1600 },
1601 _ => return 0,
1602 };
1603 ptr::write(out, field_value);
1604 1
1605}
1606
1607#[no_mangle]
1608pub unsafe extern "C" fn jit_set_field_safe(
1609 object_ptr: *const Value,
1610 field_name_ptr: *const u8,
1611 field_name_len: usize,
1612 value_ptr: *const Value,
1613) -> u8 {
1614 if object_ptr.is_null() || field_name_ptr.is_null() || value_ptr.is_null() {
1615 return 0;
1616 }
1617
1618 let field_name_slice = slice::from_raw_parts(field_name_ptr, field_name_len);
1619 let field_name = match str::from_utf8(field_name_slice) {
1620 Ok(s) => s,
1621 Err(_) => return 0,
1622 };
1623 let object = &*object_ptr;
1624 let value = (&*value_ptr).clone();
1625 match object {
1626 Value::Struct { .. } => match object.struct_set_field(field_name, value) {
1627 Ok(()) => 1,
1628 Err(_) => 0,
1629 },
1630 Value::Map(map) => {
1631 use crate::bytecode::ValueKey;
1632 let key = ValueKey::String(Rc::new(field_name.to_string()));
1633 map.borrow_mut().insert(key, value);
1634 1
1635 }
1636
1637 _ => 0,
1638 }
1639}
1640
1641#[no_mangle]
1642pub unsafe extern "C" fn jit_get_field_indexed_safe(
1643 object_ptr: *const Value,
1644 field_index: usize,
1645 out: *mut Value,
1646) -> u8 {
1647 if object_ptr.is_null() || out.is_null() {
1648 return 0;
1649 }
1650
1651 let object = &*object_ptr;
1652 match object.struct_get_field_indexed(field_index) {
1653 Some(value) => {
1654 ptr::write(out, value);
1655 1
1656 }
1657
1658 None => 0,
1659 }
1660}
1661
1662#[no_mangle]
1663pub unsafe extern "C" fn jit_set_field_indexed_safe(
1664 object_ptr: *const Value,
1665 field_index: usize,
1666 value_ptr: *const Value,
1667) -> u8 {
1668 if object_ptr.is_null() || value_ptr.is_null() {
1669 return 0;
1670 }
1671
1672 let object = &*object_ptr;
1673 let value = (&*value_ptr).clone();
1674 match object.struct_set_field_indexed(field_index, value) {
1675 Ok(()) => 1,
1676 Err(_) => 0,
1677 }
1678}
1679
1680#[no_mangle]
1681pub unsafe extern "C" fn jit_get_field_indexed_int_fast(
1682 object_ptr: *const Value,
1683 field_index: usize,
1684 out: *mut Value,
1685) -> u8 {
1686 if object_ptr.is_null() || out.is_null() {
1687 return 0;
1688 }
1689
1690 let object = &*object_ptr;
1691 let out_ref = &mut *out;
1692 match object {
1693 Value::Struct { layout, fields, .. } => {
1694 if layout.is_weak(field_index) {
1695 return 0;
1696 }
1697
1698 if let Ok(borrowed) = fields.try_borrow() {
1699 if let Some(Value::Int(val)) = borrowed.get(field_index) {
1700 *out_ref = Value::Int(*val);
1701 return 1;
1702 }
1703 }
1704
1705 0
1706 }
1707
1708 _ => 0,
1709 }
1710}
1711
1712#[no_mangle]
1713pub unsafe extern "C" fn jit_set_field_indexed_int_fast(
1714 object_ptr: *const Value,
1715 field_index: usize,
1716 value_ptr: *const Value,
1717) -> u8 {
1718 if object_ptr.is_null() || value_ptr.is_null() {
1719 return 0;
1720 }
1721
1722 let object = &*object_ptr;
1723 let value = &*value_ptr;
1724 let new_value = match value {
1725 Value::Int(v) => *v,
1726 _ => return 0,
1727 };
1728 match object {
1729 Value::Struct { layout, fields, .. } => {
1730 if layout.is_weak(field_index) {
1731 return 0;
1732 }
1733
1734 if let Ok(mut borrowed) = fields.try_borrow_mut() {
1735 if field_index < borrowed.len() {
1736 borrowed[field_index] = Value::Int(new_value);
1737 return 1;
1738 }
1739 }
1740
1741 0
1742 }
1743
1744 _ => 0,
1745 }
1746}
1747
1748#[no_mangle]
1749pub unsafe extern "C" fn jit_new_struct_safe(
1750 struct_name_ptr: *const u8,
1751 struct_name_len: usize,
1752 field_names_ptr: *const *const u8,
1753 field_name_lens_ptr: *const usize,
1754 field_values_ptr: *const Value,
1755 field_count: usize,
1756 out: *mut Value,
1757) -> u8 {
1758 if struct_name_ptr.is_null() || out.is_null() {
1759 return 0;
1760 }
1761
1762 if field_count > 0
1763 && (field_names_ptr.is_null()
1764 || field_name_lens_ptr.is_null()
1765 || field_values_ptr.is_null())
1766 {
1767 return 0;
1768 }
1769
1770 let struct_name_slice = slice::from_raw_parts(struct_name_ptr, struct_name_len);
1771 let struct_name = match str::from_utf8(struct_name_slice) {
1772 Ok(s) => s.to_string(),
1773 Err(_) => return 0,
1774 };
1775 let mut fields = Vec::with_capacity(field_count);
1776 for i in 0..field_count {
1777 let field_name_ptr = *field_names_ptr.add(i);
1778 let field_name_len = *field_name_lens_ptr.add(i);
1779 let field_name_slice = slice::from_raw_parts(field_name_ptr, field_name_len);
1780 let field_name = match str::from_utf8(field_name_slice) {
1781 Ok(s) => Rc::new(s.to_string()),
1782 Err(_) => return 0,
1783 };
1784 let field_value_ptr = field_values_ptr.add(i);
1785 let field_value = (&*field_value_ptr).clone();
1786 fields.push((field_name, field_value));
1787 }
1788
1789 let struct_value = match crate::vm::VM::with_current(move |vm| {
1790 vm.instantiate_struct(&struct_name, fields)
1791 .map_err(|err| err.to_string())
1792 }) {
1793 Ok(value) => value,
1794 Err(_) => return 0,
1795 };
1796 ptr::write(out, struct_value);
1797 1
1798}
1799
1800#[no_mangle]
1801pub unsafe extern "C" fn jit_move_safe(src_ptr: *const Value, dest_ptr: *mut Value) -> u8 {
1802 if src_ptr.is_null() || dest_ptr.is_null() {
1803 return 0;
1804 }
1805
1806 let src_value = &*src_ptr;
1807 let cloned_value = src_value.clone();
1808 ptr::write(dest_ptr, cloned_value);
1809 1
1810}