1use super::conversions::{FromLustValue, FunctionArgs, IntoTypedValue};
2use super::program::{ensure_return_type, normalize_global_name, EmbeddedProgram};
3use crate::ast::{Type, TypeKind};
4use crate::bytecode::{FieldStorage, StructLayout, Value, ValueKey};
5use crate::number::{LustFloat, LustInt};
6use crate::typechecker::FunctionSignature;
7use crate::{LustError, Result};
8use hashbrown::HashMap;
9use std::cell::{Ref, RefCell, RefMut};
10use std::ops::Deref;
11use std::rc::Rc;
12
13pub struct TypedValue {
14 value: Value,
15 matcher: Box<dyn Fn(&Value, &Type) -> bool>,
16 description: &'static str,
17}
18
19impl TypedValue {
20 pub(crate) fn new<F>(value: Value, matcher: F, description: &'static str) -> Self
21 where
22 F: Fn(&Value, &Type) -> bool + 'static,
23 {
24 Self {
25 value,
26 matcher: Box::new(matcher),
27 description,
28 }
29 }
30
31 pub(crate) fn matches(&self, ty: &Type) -> bool {
32 match &ty.kind {
33 TypeKind::Union(types) => types.iter().any(|alt| (self.matcher)(&self.value, alt)),
34 _ => (self.matcher)(&self.value, ty),
35 }
36 }
37
38 pub(crate) fn description(&self) -> &'static str {
39 self.description
40 }
41
42 pub(crate) fn into_value(self) -> Value {
43 self.value
44 }
45
46 pub(crate) fn as_value(&self) -> &Value {
47 &self.value
48 }
49}
50
51pub struct StructField {
52 name: String,
53 value: TypedValue,
54}
55
56impl StructField {
57 pub fn new(name: impl Into<String>, value: impl IntoTypedValue) -> Self {
58 Self {
59 name: name.into(),
60 value: value.into_typed_value(),
61 }
62 }
63
64 pub fn name(&self) -> &str {
65 &self.name
66 }
67
68 pub(crate) fn into_parts(self) -> (String, TypedValue) {
69 (self.name, self.value)
70 }
71}
72
73pub fn struct_field(name: impl Into<String>, value: impl IntoTypedValue) -> StructField {
74 StructField::new(name, value)
75}
76
77impl<K, V> From<(K, V)> for StructField
78where
79 K: Into<String>,
80 V: IntoTypedValue,
81{
82 fn from((name, value): (K, V)) -> Self {
83 StructField::new(name, value)
84 }
85}
86
87#[derive(Clone)]
88pub struct StructInstance {
89 type_name: String,
90 value: Value,
91}
92
93impl StructInstance {
94 pub(crate) fn new(type_name: String, value: Value) -> Self {
95 debug_assert!(matches!(value, Value::Struct { .. }));
96 Self { type_name, value }
97 }
98
99 pub fn type_name(&self) -> &str {
100 &self.type_name
101 }
102
103 pub fn field<T: FromLustValue>(&self, field: &str) -> Result<T> {
104 let value_ref = self.borrow_field(field)?;
105 T::from_value(value_ref.into_owned())
106 }
107
108 pub fn borrow_field(&self, field: &str) -> Result<ValueRef<'_>> {
109 match &self.value {
110 Value::Struct { layout, fields, .. } => {
111 let index = layout
112 .index_of_str(field)
113 .ok_or_else(|| LustError::RuntimeError {
114 message: format!(
115 "Struct '{}' has no field named '{}'",
116 self.type_name, field
117 ),
118 })?;
119 match layout.field_storage(index) {
120 FieldStorage::Strong => {
121 let slots = fields.borrow();
122 if slots.get(index).is_none() {
123 return Err(LustError::RuntimeError {
124 message: format!(
125 "Struct '{}' field '{}' is unavailable",
126 self.type_name, field
127 ),
128 });
129 }
130
131 Ok(ValueRef::borrowed(Ref::map(slots, move |values| {
132 &values[index]
133 })))
134 }
135
136 FieldStorage::Weak => {
137 let stored = {
138 let slots = fields.borrow();
139 slots
140 .get(index)
141 .cloned()
142 .ok_or_else(|| LustError::RuntimeError {
143 message: format!(
144 "Struct '{}' field '{}' is unavailable",
145 self.type_name, field
146 ),
147 })?
148 };
149 let materialized = layout.materialize_field_value(index, stored);
150 Ok(ValueRef::owned(materialized))
151 }
152 }
153 }
154
155 _ => Err(LustError::RuntimeError {
156 message: "StructInstance does not contain a struct value".to_string(),
157 }),
158 }
159 }
160
161 pub fn set_field<V: IntoTypedValue>(&self, field: &str, value: V) -> Result<()> {
162 match &self.value {
163 Value::Struct { layout, fields, .. } => {
164 let index = layout
165 .index_of_str(field)
166 .ok_or_else(|| LustError::RuntimeError {
167 message: format!(
168 "Struct '{}' has no field named '{}'",
169 self.type_name, field
170 ),
171 })?;
172 let typed_value = value.into_typed_value();
173 let matches_declared = typed_value.matches(layout.field_type(index));
174 let matches_ref_inner = layout.is_weak(index)
175 && layout
176 .weak_target(index)
177 .map(|inner| typed_value.matches(inner))
178 .unwrap_or(false);
179 if !(matches_declared || matches_ref_inner) {
180 return Err(LustError::TypeError {
181 message: format!(
182 "Struct '{}' field '{}' expects Lust type '{}' but Rust provided '{}'",
183 self.type_name,
184 field,
185 layout.field_type(index),
186 typed_value.description()
187 ),
188 });
189 }
190
191 let canonical_value = layout
192 .canonicalize_field_value(index, typed_value.into_value())
193 .map_err(|message| LustError::TypeError { message })?;
194 fields.borrow_mut()[index] = canonical_value;
195 Ok(())
196 }
197
198 _ => Err(LustError::RuntimeError {
199 message: "StructInstance does not contain a struct value".to_string(),
200 }),
201 }
202 }
203
204 pub fn update_field<F, V>(&self, field: &str, update: F) -> Result<()>
205 where
206 F: FnOnce(Value) -> Result<V>,
207 V: IntoTypedValue,
208 {
209 match &self.value {
210 Value::Struct { layout, fields, .. } => {
211 let index = layout
212 .index_of_str(field)
213 .ok_or_else(|| LustError::RuntimeError {
214 message: format!(
215 "Struct '{}' has no field named '{}'",
216 self.type_name, field
217 ),
218 })?;
219 let mut slots = fields.borrow_mut();
220 let slot = slots
221 .get_mut(index)
222 .ok_or_else(|| LustError::RuntimeError {
223 message: format!(
224 "Struct '{}' field '{}' is unavailable",
225 self.type_name, field
226 ),
227 })?;
228 let fallback = slot.clone();
229 let current_canonical = std::mem::replace(slot, Value::Nil);
230 let current_materialized = layout.materialize_field_value(index, current_canonical);
231 let updated = match update(current_materialized) {
232 Ok(value) => value,
233 Err(err) => {
234 *slot = fallback;
235 return Err(err);
236 }
237 };
238 let typed_value = updated.into_typed_value();
239 let matches_declared = typed_value.matches(layout.field_type(index));
240 let matches_ref_inner = layout.is_weak(index)
241 && layout
242 .weak_target(index)
243 .map(|inner| typed_value.matches(inner))
244 .unwrap_or(false);
245 if !(matches_declared || matches_ref_inner) {
246 *slot = fallback;
247 return Err(LustError::TypeError {
248 message: format!(
249 "Struct '{}' field '{}' expects Lust type '{}' but Rust provided '{}'",
250 self.type_name,
251 field,
252 layout.field_type(index),
253 typed_value.description()
254 ),
255 });
256 }
257
258 let canonical_value = layout
259 .canonicalize_field_value(index, typed_value.into_value())
260 .map_err(|message| LustError::TypeError { message })?;
261 *slot = canonical_value;
262 Ok(())
263 }
264
265 _ => Err(LustError::RuntimeError {
266 message: "StructInstance does not contain a struct value".to_string(),
267 }),
268 }
269 }
270
271 pub fn as_value(&self) -> &Value {
272 &self.value
273 }
274
275 pub(crate) fn into_value(self) -> Value {
276 self.value
277 }
278}
279
280#[derive(Clone)]
281pub struct FunctionHandle {
282 value: Value,
283}
284
285impl FunctionHandle {
286 pub(crate) fn is_callable_value(value: &Value) -> bool {
287 matches!(
288 value,
289 Value::Function(_) | Value::Closure { .. } | Value::NativeFunction(_)
290 )
291 }
292
293 pub(crate) fn new_unchecked(value: Value) -> Self {
294 Self { value }
295 }
296
297 pub fn from_value(value: Value) -> Result<Self> {
298 if Self::is_callable_value(&value) {
299 Ok(Self::new_unchecked(value))
300 } else {
301 Err(LustError::RuntimeError {
302 message: format!("Expected Lust value 'function' but received '{:?}'", value),
303 })
304 }
305 }
306
307 pub fn as_value(&self) -> &Value {
308 &self.value
309 }
310
311 pub fn into_value(self) -> Value {
312 self.value
313 }
314
315 fn function_index(&self) -> Option<usize> {
316 match &self.value {
317 Value::Function(idx) => Some(*idx),
318 Value::Closure { function_idx, .. } => Some(*function_idx),
319 _ => None,
320 }
321 }
322
323 fn function_name<'a>(&'a self, program: &'a EmbeddedProgram) -> Option<&'a str> {
324 let idx = self.function_index()?;
325 program.vm().function_name(idx)
326 }
327
328 pub fn signature<'a>(
329 &'a self,
330 program: &'a EmbeddedProgram,
331 ) -> Option<(&'a str, &'a FunctionSignature)> {
332 let name = self.function_name(program)?;
333 program.signature(name).map(|sig| (name, sig))
334 }
335
336 pub fn matches_signature(
337 &self,
338 program: &EmbeddedProgram,
339 expected: &FunctionSignature,
340 ) -> bool {
341 match self.signature(program) {
342 Some((_, actual)) => signatures_match(actual, expected),
343 None => false,
344 }
345 }
346
347 pub fn validate_signature(
348 &self,
349 program: &EmbeddedProgram,
350 expected: &FunctionSignature,
351 ) -> Result<()> {
352 let (name, actual) = self.signature(program).ok_or_else(|| LustError::TypeError {
353 message: "No type information available for function value; use call_raw if the function is dynamically typed"
354 .into(),
355 })?;
356 if signatures_match(actual, expected) {
357 Ok(())
358 } else {
359 Err(LustError::TypeError {
360 message: format!(
361 "Function '{}' signature mismatch: expected {}, found {}",
362 name,
363 signature_to_string(expected),
364 signature_to_string(actual)
365 ),
366 })
367 }
368 }
369
370 pub fn call_raw(&self, program: &mut EmbeddedProgram, args: Vec<Value>) -> Result<Value> {
371 program.vm_mut().call_value(self.as_value(), args)
372 }
373
374 pub fn call_typed<Args, R>(&self, program: &mut EmbeddedProgram, args: Args) -> Result<R>
375 where
376 Args: FunctionArgs,
377 R: FromLustValue,
378 {
379 let program_ref: &EmbeddedProgram = &*program;
380 let values = args.into_values();
381 if let Some((name, signature)) = self.signature(program_ref) {
382 Args::validate_signature(name, &signature.params)?;
383 ensure_return_type::<R>(name, &signature.return_type)?;
384 let value = program.vm_mut().call_value(self.as_value(), values)?;
385 R::from_value(value)
386 } else {
387 let value = program.vm_mut().call_value(self.as_value(), values)?;
388 R::from_value(value)
389 }
390 }
391}
392
393#[derive(Clone)]
394pub struct StructHandle {
395 instance: StructInstance,
396}
397
398impl StructHandle {
399 fn from_instance(instance: StructInstance) -> Self {
400 Self { instance }
401 }
402
403 fn from_parts(
404 name: &String,
405 layout: &Rc<StructLayout>,
406 fields: &Rc<RefCell<Vec<Value>>>,
407 ) -> Self {
408 let value = Value::Struct {
409 name: name.clone(),
410 layout: layout.clone(),
411 fields: fields.clone(),
412 };
413 Self::from_instance(StructInstance::new(name.clone(), value))
414 }
415
416 pub fn from_value(value: Value) -> Result<Self> {
417 <StructInstance as FromLustValue>::from_value(value).map(StructHandle::from)
418 }
419
420 pub fn type_name(&self) -> &str {
421 self.instance.type_name()
422 }
423
424 pub fn field<T: FromLustValue>(&self, field: &str) -> Result<T> {
425 self.instance.field(field)
426 }
427
428 pub fn borrow_field(&self, field: &str) -> Result<ValueRef<'_>> {
429 self.instance.borrow_field(field)
430 }
431
432 pub fn set_field<V: IntoTypedValue>(&self, field: &str, value: V) -> Result<()> {
433 self.instance.set_field(field, value)
434 }
435
436 pub fn update_field<F, V>(&self, field: &str, update: F) -> Result<()>
437 where
438 F: FnOnce(Value) -> Result<V>,
439 V: IntoTypedValue,
440 {
441 self.instance.update_field(field, update)
442 }
443
444 pub fn as_value(&self) -> &Value {
445 self.instance.as_value()
446 }
447
448 pub fn to_instance(&self) -> StructInstance {
449 self.instance.clone()
450 }
451
452 pub fn into_instance(self) -> StructInstance {
453 self.instance
454 }
455
456 pub fn matches_type(&self, expected: &str) -> bool {
457 lust_type_names_match(self.type_name(), expected)
458 }
459
460 pub fn ensure_type(&self, expected: &str) -> Result<()> {
461 if self.matches_type(expected) {
462 Ok(())
463 } else {
464 Err(LustError::TypeError {
465 message: format!(
466 "Struct '{}' does not match expected type '{}'",
467 self.type_name(),
468 expected
469 ),
470 })
471 }
472 }
473}
474
475impl StructInstance {
476 pub fn to_handle(&self) -> StructHandle {
477 StructHandle::from_instance(self.clone())
478 }
479
480 pub fn into_handle(self) -> StructHandle {
481 StructHandle::from_instance(self)
482 }
483}
484
485impl From<StructInstance> for StructHandle {
486 fn from(instance: StructInstance) -> Self {
487 StructHandle::from_instance(instance)
488 }
489}
490
491impl From<StructHandle> for StructInstance {
492 fn from(handle: StructHandle) -> Self {
493 handle.into_instance()
494 }
495}
496
497pub enum ValueRef<'a> {
498 Borrowed(Ref<'a, Value>),
499 Owned(Value),
500}
501
502impl<'a> ValueRef<'a> {
503 fn borrowed(inner: Ref<'a, Value>) -> Self {
504 Self::Borrowed(inner)
505 }
506
507 fn owned(value: Value) -> Self {
508 Self::Owned(value)
509 }
510
511 pub fn as_value(&self) -> &Value {
512 match self {
513 ValueRef::Borrowed(inner) => &*inner,
514 ValueRef::Owned(value) => value,
515 }
516 }
517
518 pub fn to_owned(&self) -> Value {
519 self.as_value().clone()
520 }
521
522 pub fn into_owned(self) -> Value {
523 match self {
524 ValueRef::Borrowed(inner) => inner.clone(),
525 ValueRef::Owned(value) => value,
526 }
527 }
528
529 pub fn as_bool(&self) -> Option<bool> {
530 match self.as_value() {
531 Value::Bool(value) => Some(*value),
532 _ => None,
533 }
534 }
535
536 pub fn as_int(&self) -> Option<LustInt> {
537 self.as_value().as_int()
538 }
539
540 pub fn as_float(&self) -> Option<LustFloat> {
541 self.as_value().as_float()
542 }
543
544 pub fn as_string(&self) -> Option<&str> {
545 self.as_value().as_string()
546 }
547
548 pub fn as_rc_string(&self) -> Option<Rc<String>> {
549 match self.as_value() {
550 Value::String(value) => Some(value.clone()),
551 _ => None,
552 }
553 }
554
555 pub fn as_array_handle(&self) -> Option<ArrayHandle> {
556 match self.as_value() {
557 Value::Array(items) => Some(ArrayHandle::from_rc(items.clone())),
558 _ => None,
559 }
560 }
561
562 pub fn as_map_handle(&self) -> Option<MapHandle> {
563 match self.as_value() {
564 Value::Map(map) => Some(MapHandle::from_rc(map.clone())),
565 _ => None,
566 }
567 }
568
569 pub fn as_struct_handle(&self) -> Option<StructHandle> {
570 match self.as_value() {
571 Value::Struct {
572 name,
573 layout,
574 fields,
575 } => Some(StructHandle::from_parts(name, layout, fields)),
576 Value::WeakStruct(weak) => weak
577 .upgrade()
578 .and_then(|value| StructHandle::from_value(value).ok()),
579 _ => None,
580 }
581 }
582}
583
584pub struct StringRef<'a> {
585 value: ValueRef<'a>,
586}
587
588impl<'a> StringRef<'a> {
589 pub(crate) fn new(value: ValueRef<'a>) -> Self {
590 Self { value }
591 }
592
593 pub fn as_str(&self) -> &str {
594 self.value
595 .as_string()
596 .expect("StringRef must wrap a Lust string")
597 }
598
599 pub fn as_rc(&self) -> Rc<String> {
600 self.value
601 .as_rc_string()
602 .expect("StringRef must wrap a Lust string")
603 }
604
605 pub fn to_value(&self) -> &Value {
606 self.value.as_value()
607 }
608
609 pub fn into_value_ref(self) -> ValueRef<'a> {
610 self.value
611 }
612}
613
614impl<'a> Deref for StringRef<'a> {
615 type Target = str;
616
617 fn deref(&self) -> &Self::Target {
618 self.as_str()
619 }
620}
621
622#[derive(Clone)]
623pub struct ArrayHandle {
624 inner: Rc<RefCell<Vec<Value>>>,
625}
626
627impl ArrayHandle {
628 pub(crate) fn from_rc(inner: Rc<RefCell<Vec<Value>>>) -> Self {
629 Self { inner }
630 }
631
632 pub fn len(&self) -> usize {
633 self.inner.borrow().len()
634 }
635
636 pub fn is_empty(&self) -> bool {
637 self.len() == 0
638 }
639
640 pub fn borrow(&self) -> Ref<'_, [Value]> {
641 Ref::map(self.inner.borrow(), |values| values.as_slice())
642 }
643
644 pub fn borrow_mut(&self) -> RefMut<'_, Vec<Value>> {
645 self.inner.borrow_mut()
646 }
647
648 pub fn push(&self, value: Value) {
649 self.inner.borrow_mut().push(value);
650 }
651
652 pub fn extend<I>(&self, iter: I)
653 where
654 I: IntoIterator<Item = Value>,
655 {
656 self.inner.borrow_mut().extend(iter);
657 }
658
659 pub fn get(&self, index: usize) -> Option<ValueRef<'_>> {
660 {
661 let values = self.inner.borrow();
662 if values.get(index).is_none() {
663 return None;
664 }
665 }
666
667 let values = self.inner.borrow();
668 Some(ValueRef::borrowed(Ref::map(values, move |items| {
669 &items[index]
670 })))
671 }
672
673 pub fn with_ref<R>(&self, f: impl FnOnce(&[Value]) -> R) -> R {
674 let values = self.inner.borrow();
675 f(values.as_slice())
676 }
677
678 pub fn with_mut<R>(&self, f: impl FnOnce(&mut Vec<Value>) -> R) -> R {
679 let mut values = self.inner.borrow_mut();
680 f(&mut values)
681 }
682
683 pub(crate) fn into_value(self) -> Value {
684 Value::Array(self.inner)
685 }
686}
687
688#[derive(Clone)]
689pub struct MapHandle {
690 inner: Rc<RefCell<HashMap<ValueKey, Value>>>,
691}
692
693impl MapHandle {
694 pub(crate) fn from_rc(inner: Rc<RefCell<HashMap<ValueKey, Value>>>) -> Self {
695 Self { inner }
696 }
697
698 pub fn len(&self) -> usize {
699 self.inner.borrow().len()
700 }
701
702 pub fn is_empty(&self) -> bool {
703 self.len() == 0
704 }
705
706 pub fn borrow(&self) -> Ref<'_, HashMap<ValueKey, Value>> {
707 self.inner.borrow()
708 }
709
710 pub fn borrow_mut(&self) -> RefMut<'_, HashMap<ValueKey, Value>> {
711 self.inner.borrow_mut()
712 }
713
714 pub fn contains_key<K>(&self, key: K) -> bool
715 where
716 K: Into<ValueKey>,
717 {
718 self.inner.borrow().contains_key(&key.into())
719 }
720
721 pub fn get<K>(&self, key: K) -> Option<ValueRef<'_>>
722 where
723 K: Into<ValueKey>,
724 {
725 let key = key.into();
726 {
727 if !self.inner.borrow().contains_key(&key) {
728 return None;
729 }
730 }
731 let lookup = key.clone();
732 let map = self.inner.borrow();
733 Some(ValueRef::borrowed(Ref::map(map, move |values| {
734 values
735 .get(&lookup)
736 .expect("lookup key should be present after contains_key")
737 })))
738 }
739
740 pub fn insert<K>(&self, key: K, value: Value) -> Option<Value>
741 where
742 K: Into<ValueKey>,
743 {
744 self.inner.borrow_mut().insert(key.into(), value)
745 }
746
747 pub fn remove<K>(&self, key: K) -> Option<Value>
748 where
749 K: Into<ValueKey>,
750 {
751 self.inner.borrow_mut().remove(&key.into())
752 }
753
754 pub fn with_ref<R>(&self, f: impl FnOnce(&HashMap<ValueKey, Value>) -> R) -> R {
755 let map = self.inner.borrow();
756 f(&map)
757 }
758
759 pub fn with_mut<R>(&self, f: impl FnOnce(&mut HashMap<ValueKey, Value>) -> R) -> R {
760 let mut map = self.inner.borrow_mut();
761 f(&mut map)
762 }
763
764 pub(crate) fn into_value(self) -> Value {
765 Value::Map(self.inner)
766 }
767}
768
769#[derive(Clone)]
770pub struct EnumInstance {
771 type_name: String,
772 variant: String,
773 value: Value,
774}
775
776impl EnumInstance {
777 pub(crate) fn new(type_name: String, variant: String, value: Value) -> Self {
778 debug_assert!(matches!(value, Value::Enum { .. }));
779 Self {
780 type_name,
781 variant,
782 value,
783 }
784 }
785
786 pub fn type_name(&self) -> &str {
787 &self.type_name
788 }
789
790 pub fn variant(&self) -> &str {
791 &self.variant
792 }
793
794 pub fn payload_len(&self) -> usize {
795 match &self.value {
796 Value::Enum { values, .. } => values.as_ref().map(|v| v.len()).unwrap_or(0),
797 _ => 0,
798 }
799 }
800
801 pub fn payload<T: FromLustValue>(&self, index: usize) -> Result<T> {
802 match &self.value {
803 Value::Enum { values, .. } => {
804 let values = values.as_ref().ok_or_else(|| LustError::RuntimeError {
805 message: format!(
806 "Enum variant '{}.{}' carries no payload",
807 self.type_name, self.variant
808 ),
809 })?;
810 let stored = values
811 .get(index)
812 .cloned()
813 .ok_or_else(|| LustError::RuntimeError {
814 message: format!(
815 "Enum variant '{}.{}' payload index {} is out of bounds",
816 self.type_name, self.variant, index
817 ),
818 })?;
819 T::from_value(stored)
820 }
821
822 _ => Err(LustError::RuntimeError {
823 message: "EnumInstance does not contain an enum value".to_string(),
824 }),
825 }
826 }
827
828 pub fn as_value(&self) -> &Value {
829 &self.value
830 }
831
832 pub(crate) fn into_value(self) -> Value {
833 self.value
834 }
835}
836
837pub(crate) fn matches_lust_struct(value: &Value, ty: &Type) -> bool {
838 match (value, &ty.kind) {
839 (Value::Struct { name, .. }, TypeKind::Named(expected)) => {
840 lust_type_names_match(name, expected)
841 }
842 (Value::Struct { name, .. }, TypeKind::GenericInstance { name: expected, .. }) => {
843 lust_type_names_match(name, expected)
844 }
845
846 (value, TypeKind::Union(types)) => types.iter().any(|alt| matches_lust_struct(value, alt)),
847 (_, TypeKind::Unknown) => true,
848 _ => false,
849 }
850}
851
852pub(crate) fn matches_lust_enum(value: &Value, ty: &Type) -> bool {
853 match (value, &ty.kind) {
854 (Value::Enum { enum_name, .. }, TypeKind::Named(expected)) => {
855 lust_type_names_match(enum_name, expected)
856 }
857 (Value::Enum { enum_name, .. }, TypeKind::GenericInstance { name: expected, .. }) => {
858 lust_type_names_match(enum_name, expected)
859 }
860
861 (value, TypeKind::Union(types)) => types.iter().any(|alt| matches_lust_enum(value, alt)),
862 (_, TypeKind::Unknown) => true,
863 _ => false,
864 }
865}
866
867pub(crate) fn lust_type_names_match(value: &str, expected: &str) -> bool {
868 if value == expected {
869 return true;
870 }
871
872 let normalized_value = normalize_global_name(value);
873 let normalized_expected = normalize_global_name(expected);
874 if normalized_value == normalized_expected {
875 return true;
876 }
877
878 simple_type_name(&normalized_value) == simple_type_name(&normalized_expected)
879}
880
881pub(crate) fn simple_type_name(name: &str) -> &str {
882 name.rsplit(|c| c == '.' || c == ':').next().unwrap_or(name)
883}
884
885pub(crate) fn matches_array_type<F>(ty: &Type, matcher: &F) -> bool
886where
887 F: Fn(&Type) -> bool,
888{
889 match &ty.kind {
890 TypeKind::Array(inner) => matcher(inner),
891 TypeKind::Unknown => true,
892 TypeKind::Union(types) => types.iter().any(|alt| matches_array_type(alt, matcher)),
893 _ => false,
894 }
895}
896
897pub(crate) fn matches_array_handle_type(ty: &Type) -> bool {
898 match &ty.kind {
899 TypeKind::Array(_) | TypeKind::Unknown => true,
900 TypeKind::Union(types) => types.iter().any(|alt| matches_array_handle_type(alt)),
901 _ => false,
902 }
903}
904
905pub(crate) fn matches_map_handle_type(ty: &Type) -> bool {
906 match &ty.kind {
907 TypeKind::Map(_, _) | TypeKind::Unknown => true,
908 TypeKind::Union(types) => types.iter().any(|alt| matches_map_handle_type(alt)),
909 _ => false,
910 }
911}
912
913pub(crate) fn matches_function_handle_type(ty: &Type) -> bool {
914 match &ty.kind {
915 TypeKind::Function { .. } | TypeKind::Unknown => true,
916 TypeKind::Union(types) => types.iter().any(|alt| matches_function_handle_type(alt)),
917 _ => false,
918 }
919}
920
921pub(crate) fn signatures_match(a: &FunctionSignature, b: &FunctionSignature) -> bool {
922 if a.is_method != b.is_method || a.params.len() != b.params.len() {
923 return false;
924 }
925
926 if a.return_type != b.return_type {
927 return false;
928 }
929
930 a.params
931 .iter()
932 .zip(&b.params)
933 .all(|(left, right)| left == right)
934}
935
936pub(crate) fn signature_to_string(signature: &FunctionSignature) -> String {
937 let params = signature
938 .params
939 .iter()
940 .map(|param| param.to_string())
941 .collect::<Vec<_>>()
942 .join(", ");
943 format!("function({}) -> {}", params, signature.return_type)
944}
945
946#[cfg(test)]
947mod tests {
948 use super::*;
949 use crate::ast::Span;
950 use crate::embed::{AsyncDriver, EmbeddedProgram, LustStructView};
951 use std::rc::Rc;
952
953 fn serial_guard() -> std::sync::MutexGuard<'static, ()> {
954 static LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
955 LOCK.lock().unwrap_or_else(|err| err.into_inner())
956 }
957
958 fn build_program(source: &str) -> EmbeddedProgram {
959 EmbeddedProgram::builder()
960 .module("main", source)
961 .entry_module("main")
962 .compile()
963 .expect("compile embedded program")
964 }
965
966 #[test]
967 fn struct_instance_supports_mixed_field_types() {
968 let _guard = serial_guard();
969 let source = r#"
970 struct Mixed
971 count: int
972 label: string
973 enabled: bool
974 end
975 "#;
976
977 let program = build_program(source);
978 let mixed = program
979 .struct_instance(
980 "main.Mixed",
981 [
982 struct_field("count", 7_i64),
983 struct_field("label", "hi"),
984 struct_field("enabled", true),
985 ],
986 )
987 .expect("struct instance");
988
989 assert_eq!(mixed.field::<i64>("count").expect("count field"), 7);
990 assert_eq!(mixed.field::<String>("label").expect("label field"), "hi");
991 assert!(mixed.field::<bool>("enabled").expect("enabled field"));
992 }
993
994 #[test]
995 fn struct_instance_borrow_field_provides_reference_view() {
996 let _guard = serial_guard();
997 let source = r#"
998 struct Sample
999 name: string
1000 end
1001 "#;
1002
1003 let program = build_program(source);
1004 let sample = program
1005 .struct_instance("main.Sample", [struct_field("name", "Borrowed")])
1006 .expect("struct instance");
1007
1008 let name_ref = sample.borrow_field("name").expect("borrow name field");
1009 assert_eq!(name_ref.as_string().unwrap(), "Borrowed");
1010 assert!(name_ref.as_array_handle().is_none());
1011 }
1012
1013 #[test]
1014 fn array_handle_allows_in_place_mutation() {
1015 let _guard = serial_guard();
1016 let value = Value::array(vec![Value::Int(1)]);
1017 let handle = <ArrayHandle as FromLustValue>::from_value(value).expect("array handle");
1018
1019 {
1020 let mut slots = handle.borrow_mut();
1021 slots.push(Value::Int(2));
1022 slots.push(Value::Int(3));
1023 }
1024
1025 let snapshot: Vec<_> = handle
1026 .borrow()
1027 .iter()
1028 .map(|value| value.as_int().expect("int value"))
1029 .collect();
1030 assert_eq!(snapshot, vec![1, 2, 3]);
1031 }
1032
1033 #[test]
1034 fn struct_instance_allows_setting_fields() {
1035 let _guard = serial_guard();
1036 let source = r#"
1037 struct Mixed
1038 count: int
1039 label: string
1040 enabled: bool
1041 end
1042 "#;
1043
1044 let program = build_program(source);
1045 let mixed = program
1046 .struct_instance(
1047 "main.Mixed",
1048 [
1049 struct_field("count", 1_i64),
1050 struct_field("label", "start"),
1051 struct_field("enabled", false),
1052 ],
1053 )
1054 .expect("struct instance");
1055
1056 mixed
1057 .set_field("count", 11_i64)
1058 .expect("update count field");
1059 assert_eq!(mixed.field::<i64>("count").expect("count field"), 11);
1060
1061 let err = mixed
1062 .set_field("count", "oops")
1063 .expect_err("type mismatch should fail");
1064 match err {
1065 LustError::TypeError { message } => {
1066 assert!(message.contains("count"));
1067 assert!(message.contains("int"));
1068 }
1069 other => panic!("unexpected error: {other:?}"),
1070 }
1071 assert_eq!(mixed.field::<i64>("count").expect("count field"), 11);
1072
1073 mixed
1074 .set_field("label", String::from("updated"))
1075 .expect("update label");
1076 assert_eq!(
1077 mixed.field::<String>("label").expect("label field"),
1078 "updated"
1079 );
1080
1081 mixed.set_field("enabled", true).expect("update enabled");
1082 assert!(mixed.field::<bool>("enabled").expect("enabled field"));
1083 }
1084
1085 #[test]
1086 fn struct_instance_accepts_nested_structs() {
1087 let _guard = serial_guard();
1088 let source = r#"
1089 struct Child
1090 value: int
1091 end
1092
1093 struct Parent
1094 child: main.Child
1095 end
1096 "#;
1097
1098 let program = build_program(source);
1099 let child = program
1100 .struct_instance("main.Child", [struct_field("value", 42_i64)])
1101 .expect("child struct");
1102 let parent = program
1103 .struct_instance("main.Parent", [struct_field("child", child.clone())])
1104 .expect("parent struct");
1105
1106 let nested: StructInstance = parent.field("child").expect("child field");
1107 assert_eq!(nested.field::<i64>("value").expect("value field"), 42);
1108 }
1109
1110 #[test]
1111 fn struct_handle_allows_field_mutation() {
1112 let _guard = serial_guard();
1113 let source = r#"
1114 struct Counter
1115 value: int
1116 end
1117 "#;
1118
1119 let program = build_program(source);
1120 let counter = program
1121 .struct_instance("main.Counter", [struct_field("value", 1_i64)])
1122 .expect("counter struct");
1123 let handle = counter.to_handle();
1124
1125 handle
1126 .set_field("value", 7_i64)
1127 .expect("update through handle");
1128 assert_eq!(handle.field::<i64>("value").expect("value field"), 7);
1129 assert_eq!(counter.field::<i64>("value").expect("value field"), 7);
1130
1131 handle
1132 .update_field("value", |current| match current {
1133 Value::Int(v) => Ok(v + 1),
1134 other => Err(LustError::RuntimeError {
1135 message: format!("unexpected value {other:?}"),
1136 }),
1137 })
1138 .expect("increment value");
1139 assert_eq!(counter.field::<i64>("value").expect("value field"), 8);
1140 }
1141
1142 #[test]
1143 fn value_ref_can_materialize_struct_handle() {
1144 let _guard = serial_guard();
1145 let source = r#"
1146 struct Child
1147 value: int
1148 end
1149
1150 struct Parent
1151 child: main.Child
1152 end
1153 "#;
1154
1155 let program = build_program(source);
1156 let child = program
1157 .struct_instance("main.Child", [struct_field("value", 10_i64)])
1158 .expect("child struct");
1159 let parent = program
1160 .struct_instance("main.Parent", [struct_field("child", child)])
1161 .expect("parent struct");
1162
1163 let handle = {
1164 let child_ref = parent.borrow_field("child").expect("child field borrow");
1165 child_ref
1166 .as_struct_handle()
1167 .expect("struct handle from value ref")
1168 };
1169 handle
1170 .set_field("value", 55_i64)
1171 .expect("update nested value");
1172
1173 let nested = parent
1174 .field::<StructInstance>("child")
1175 .expect("child field");
1176 assert_eq!(nested.field::<i64>("value").expect("value field"), 55);
1177 }
1178
1179 #[derive(crate::LustStructView)]
1180 #[lust(type = "main.Child", crate = "crate")]
1181 struct ChildView<'a> {
1182 #[lust(field = "value")]
1183 value: ValueRef<'a>,
1184 }
1185
1186 #[derive(crate::LustStructView)]
1187 #[lust(type = "main.Parent", crate = "crate")]
1188 struct ParentView<'a> {
1189 #[lust(field = "child")]
1190 child: StructHandle,
1191 #[lust(field = "label")]
1192 label: StringRef<'a>,
1193 }
1194
1195 #[test]
1196 fn derive_struct_view_zero_copy() {
1197 let _guard = serial_guard();
1198 let source = r#"
1199 struct Child
1200 value: int
1201 end
1202
1203 struct Parent
1204 child: main.Child
1205 label: string
1206 end
1207 "#;
1208
1209 let program = build_program(source);
1210 let child = program
1211 .struct_instance("main.Child", [struct_field("value", 7_i64)])
1212 .expect("child struct");
1213 let parent = program
1214 .struct_instance(
1215 "main.Parent",
1216 [
1217 struct_field("child", child.clone()),
1218 struct_field("label", "parent label"),
1219 ],
1220 )
1221 .expect("parent struct");
1222
1223 let handle = parent.to_handle();
1224 let view = ParentView::from_handle(&handle).expect("construct view");
1225 assert_eq!(view.child.field::<i64>("value").expect("child value"), 7);
1226 let label_rc_from_view = view.label.as_rc();
1227 assert_eq!(&*label_rc_from_view, "parent label");
1228
1229 let label_ref = parent.borrow_field("label").expect("borrow label");
1230 let label_rc = label_ref.as_rc_string().expect("label rc");
1231 assert!(Rc::ptr_eq(&label_rc_from_view, &label_rc));
1232
1233 let child_view = ChildView::from_handle(&view.child).expect("child view");
1234 assert_eq!(child_view.value.as_int().expect("child value"), 7);
1235
1236 match ParentView::from_handle(&child.to_handle()) {
1237 Ok(_) => panic!("expected type mismatch"),
1238 Err(LustError::TypeError { message }) => {
1239 assert!(message.contains("Parent"), "unexpected message: {message}");
1240 }
1241 Err(other) => panic!("unexpected error: {other:?}"),
1242 }
1243 }
1244
1245 #[test]
1246 fn globals_snapshot_exposes_lust_values() {
1247 let _guard = serial_guard();
1248 let source = r#"
1249 struct Child
1250 value: int
1251 end
1252
1253 struct Parent
1254 child: unknown
1255 end
1256
1257 function make_parent(): Parent
1258 return Parent { child = Child { value = 3 } }
1259 end
1260 "#;
1261
1262 let mut program = build_program(source);
1263 program.run_entry_script().expect("run entry script");
1264 let parent: StructInstance = program
1265 .call_typed("main.make_parent", ())
1266 .expect("call make_parent");
1267 program.set_global_value("main.some_nested_structure", parent.clone());
1268
1269 let globals = program.globals();
1270 let (_, value) = globals
1271 .into_iter()
1272 .find(|(name, _)| name.ends_with("some_nested_structure"))
1273 .expect("global binding present");
1274 let stored =
1275 <StructInstance as FromLustValue>::from_value(value).expect("convert to struct");
1276 let child_value = stored
1277 .field::<StructInstance>("child")
1278 .expect("nested child");
1279 assert_eq!(child_value.field::<i64>("value").expect("child value"), 3);
1280 }
1281
1282 #[test]
1283 fn function_handle_supports_typed_and_raw_calls() {
1284 let _guard = serial_guard();
1285 let source = r#"
1286 pub function add(a: int, b: int): int
1287 return a + b
1288 end
1289 "#;
1290
1291 let mut program = build_program(source);
1292 let handle = program
1293 .function_handle("main.add")
1294 .expect("function handle");
1295
1296 let typed: i64 = handle
1297 .call_typed(&mut program, (2_i64, 3_i64))
1298 .expect("typed call");
1299 assert_eq!(typed, 5);
1300
1301 let raw = handle
1302 .call_raw(&mut program, vec![Value::Int(4_i64), Value::Int(6_i64)])
1303 .expect("raw call");
1304 assert_eq!(raw.as_int(), Some(10));
1305
1306 let signature = program.signature("main.add").expect("signature").clone();
1307 handle
1308 .validate_signature(&program, &signature)
1309 .expect("matching signature");
1310
1311 let mut mismatched = signature.clone();
1312 mismatched.return_type = Type::new(TypeKind::Bool, Span::new(0, 0, 0, 0));
1313 assert!(
1314 handle.validate_signature(&program, &mismatched).is_err(),
1315 "expected signature mismatch"
1316 );
1317 }
1318
1319 #[test]
1320 fn async_task_native_returns_task_handle() {
1321 let _guard = serial_guard();
1322 let source = r#"
1323 extern {
1324 function fetch_value(): Task
1325 }
1326
1327 pub function start(): Task
1328 return fetch_value()
1329 end
1330 "#;
1331
1332 let mut program = build_program(source);
1333 program
1334 .register_async_task_native::<(), LustInt, _, _>("fetch_value", move |_| async move {
1335 Ok(42_i64)
1336 })
1337 .expect("register async task native");
1338
1339 let task_value = program
1340 .call_raw("main.start", Vec::new())
1341 .expect("call start");
1342 let handle = match task_value {
1343 Value::Task(handle) => handle,
1344 other => panic!("expected task handle, found {other:?}"),
1345 };
1346
1347 {
1348 let mut driver = AsyncDriver::new(&mut program);
1349 driver.pump_until_idle().expect("poll async");
1350 }
1351
1352 let (state_label, last_result, err) = {
1353 let vm = program.vm_mut();
1354 let task = vm.get_task_instance(handle).expect("task instance");
1355 (
1356 task.state.as_str().to_string(),
1357 task.last_result.clone(),
1358 task.error.clone(),
1359 )
1360 };
1361 assert_eq!(state_label, "completed");
1362 assert!(err.is_none());
1363 let int_value = last_result
1364 .and_then(|value| value.as_int())
1365 .expect("int result");
1366 assert_eq!(int_value, 42);
1367 }
1368
1369 #[test]
1370 fn update_field_modifies_value_in_place() {
1371 let _guard = serial_guard();
1372 let source = r#"
1373 struct Counter
1374 value: int
1375 end
1376 "#;
1377
1378 let program = build_program(source);
1379 let counter = program
1380 .struct_instance("main.Counter", [struct_field("value", 10_i64)])
1381 .expect("counter struct");
1382
1383 counter
1384 .update_field("value", |current| match current {
1385 Value::Int(v) => Ok(v + 5),
1386 other => Err(LustError::RuntimeError {
1387 message: format!("unexpected value {other:?}"),
1388 }),
1389 })
1390 .expect("update in place");
1391 assert_eq!(counter.field::<i64>("value").expect("value field"), 15);
1392
1393 let err = counter
1394 .update_field("value", |_| Ok(String::from("oops")))
1395 .expect_err("string should fail type check");
1396 match err {
1397 LustError::TypeError { message } => {
1398 assert!(message.contains("value"));
1399 assert!(message.contains("int"));
1400 }
1401 other => panic!("unexpected error: {other:?}"),
1402 }
1403 assert_eq!(counter.field::<i64>("value").expect("value field"), 15);
1404
1405 let err = counter
1406 .update_field("value", |_| -> Result<i64> {
1407 Err(LustError::RuntimeError {
1408 message: "closure failure".to_string(),
1409 })
1410 })
1411 .expect_err("closure error should propagate");
1412 match err {
1413 LustError::RuntimeError { message } => assert_eq!(message, "closure failure"),
1414 other => panic!("unexpected error: {other:?}"),
1415 }
1416 assert_eq!(counter.field::<i64>("value").expect("value field"), 15);
1417 }
1418}