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::{
951 struct_field_decl, AsyncDriver, EmbeddedProgram, FunctionBuilder, LustStructView,
952 StructBuilder,
953 };
954 use std::rc::Rc;
955
956 fn serial_guard() -> std::sync::MutexGuard<'static, ()> {
957 static LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
958 LOCK.lock().unwrap_or_else(|err| err.into_inner())
959 }
960
961 fn build_program(source: &str) -> EmbeddedProgram {
962 EmbeddedProgram::builder()
963 .module("main", source)
964 .entry_module("main")
965 .compile()
966 .expect("compile embedded program")
967 }
968
969 #[test]
970 fn struct_instance_supports_mixed_field_types() {
971 let _guard = serial_guard();
972 let source = r#"
973 struct Mixed
974 count: int
975 label: string
976 enabled: bool
977 end
978 "#;
979
980 let program = build_program(source);
981 let mixed = program
982 .struct_instance(
983 "main.Mixed",
984 [
985 struct_field("count", 7_i64),
986 struct_field("label", "hi"),
987 struct_field("enabled", true),
988 ],
989 )
990 .expect("struct instance");
991
992 assert_eq!(mixed.field::<i64>("count").expect("count field"), 7);
993 assert_eq!(mixed.field::<String>("label").expect("label field"), "hi");
994 assert!(mixed.field::<bool>("enabled").expect("enabled field"));
995 }
996
997 #[test]
998 fn struct_instance_borrow_field_provides_reference_view() {
999 let _guard = serial_guard();
1000 let source = r#"
1001 struct Sample
1002 name: string
1003 end
1004 "#;
1005
1006 let program = build_program(source);
1007 let sample = program
1008 .struct_instance("main.Sample", [struct_field("name", "Borrowed")])
1009 .expect("struct instance");
1010
1011 let name_ref = sample.borrow_field("name").expect("borrow name field");
1012 assert_eq!(name_ref.as_string().unwrap(), "Borrowed");
1013 assert!(name_ref.as_array_handle().is_none());
1014 }
1015
1016 #[test]
1017 fn array_handle_allows_in_place_mutation() {
1018 let _guard = serial_guard();
1019 let value = Value::array(vec![Value::Int(1)]);
1020 let handle = <ArrayHandle as FromLustValue>::from_value(value).expect("array handle");
1021
1022 {
1023 let mut slots = handle.borrow_mut();
1024 slots.push(Value::Int(2));
1025 slots.push(Value::Int(3));
1026 }
1027
1028 let snapshot: Vec<_> = handle
1029 .borrow()
1030 .iter()
1031 .map(|value| value.as_int().expect("int value"))
1032 .collect();
1033 assert_eq!(snapshot, vec![1, 2, 3]);
1034 }
1035
1036 #[test]
1037 fn struct_instance_allows_setting_fields() {
1038 let _guard = serial_guard();
1039 let source = r#"
1040 struct Mixed
1041 count: int
1042 label: string
1043 enabled: bool
1044 end
1045 "#;
1046
1047 let program = build_program(source);
1048 let mixed = program
1049 .struct_instance(
1050 "main.Mixed",
1051 [
1052 struct_field("count", 1_i64),
1053 struct_field("label", "start"),
1054 struct_field("enabled", false),
1055 ],
1056 )
1057 .expect("struct instance");
1058
1059 mixed
1060 .set_field("count", 11_i64)
1061 .expect("update count field");
1062 assert_eq!(mixed.field::<i64>("count").expect("count field"), 11);
1063
1064 let err = mixed
1065 .set_field("count", "oops")
1066 .expect_err("type mismatch should fail");
1067 match err {
1068 LustError::TypeError { message } => {
1069 assert!(message.contains("count"));
1070 assert!(message.contains("int"));
1071 }
1072 other => panic!("unexpected error: {other:?}"),
1073 }
1074 assert_eq!(mixed.field::<i64>("count").expect("count field"), 11);
1075
1076 mixed
1077 .set_field("label", String::from("updated"))
1078 .expect("update label");
1079 assert_eq!(
1080 mixed.field::<String>("label").expect("label field"),
1081 "updated"
1082 );
1083
1084 mixed.set_field("enabled", true).expect("update enabled");
1085 assert!(mixed.field::<bool>("enabled").expect("enabled field"));
1086 }
1087
1088 #[test]
1089 fn struct_instance_accepts_nested_structs() {
1090 let _guard = serial_guard();
1091 let source = r#"
1092 struct Child
1093 value: int
1094 end
1095
1096 struct Parent
1097 child: main.Child
1098 end
1099 "#;
1100
1101 let program = build_program(source);
1102 let child = program
1103 .struct_instance("main.Child", [struct_field("value", 42_i64)])
1104 .expect("child struct");
1105 let parent = program
1106 .struct_instance("main.Parent", [struct_field("child", child.clone())])
1107 .expect("parent struct");
1108
1109 let nested: StructInstance = parent.field("child").expect("child field");
1110 assert_eq!(nested.field::<i64>("value").expect("value field"), 42);
1111 }
1112
1113 #[test]
1114 fn struct_handle_allows_field_mutation() {
1115 let _guard = serial_guard();
1116 let source = r#"
1117 struct Counter
1118 value: int
1119 end
1120 "#;
1121
1122 let program = build_program(source);
1123 let counter = program
1124 .struct_instance("main.Counter", [struct_field("value", 1_i64)])
1125 .expect("counter struct");
1126 let handle = counter.to_handle();
1127
1128 handle
1129 .set_field("value", 7_i64)
1130 .expect("update through handle");
1131 assert_eq!(handle.field::<i64>("value").expect("value field"), 7);
1132 assert_eq!(counter.field::<i64>("value").expect("value field"), 7);
1133
1134 handle
1135 .update_field("value", |current| match current {
1136 Value::Int(v) => Ok(v + 1),
1137 other => Err(LustError::RuntimeError {
1138 message: format!("unexpected value {other:?}"),
1139 }),
1140 })
1141 .expect("increment value");
1142 assert_eq!(counter.field::<i64>("value").expect("value field"), 8);
1143 }
1144
1145 #[test]
1146 fn value_ref_can_materialize_struct_handle() {
1147 let _guard = serial_guard();
1148 let source = r#"
1149 struct Child
1150 value: int
1151 end
1152
1153 struct Parent
1154 child: main.Child
1155 end
1156 "#;
1157
1158 let program = build_program(source);
1159 let child = program
1160 .struct_instance("main.Child", [struct_field("value", 10_i64)])
1161 .expect("child struct");
1162 let parent = program
1163 .struct_instance("main.Parent", [struct_field("child", child)])
1164 .expect("parent struct");
1165
1166 let handle = {
1167 let child_ref = parent.borrow_field("child").expect("child field borrow");
1168 child_ref
1169 .as_struct_handle()
1170 .expect("struct handle from value ref")
1171 };
1172 handle
1173 .set_field("value", 55_i64)
1174 .expect("update nested value");
1175
1176 let nested = parent
1177 .field::<StructInstance>("child")
1178 .expect("child field");
1179 assert_eq!(nested.field::<i64>("value").expect("value field"), 55);
1180 }
1181
1182 #[derive(crate::LustStructView)]
1183 #[lust(type = "main.Child", crate = "crate")]
1184 struct ChildView<'a> {
1185 #[lust(field = "value")]
1186 value: ValueRef<'a>,
1187 }
1188
1189 #[derive(crate::LustStructView)]
1190 #[lust(type = "main.Parent", crate = "crate")]
1191 struct ParentView<'a> {
1192 #[lust(field = "child")]
1193 child: StructHandle,
1194 #[lust(field = "label")]
1195 label: StringRef<'a>,
1196 }
1197
1198 #[test]
1199 fn derive_struct_view_zero_copy() {
1200 let _guard = serial_guard();
1201 let source = r#"
1202 struct Child
1203 value: int
1204 end
1205
1206 struct Parent
1207 child: main.Child
1208 label: string
1209 end
1210 "#;
1211
1212 let program = build_program(source);
1213 let child = program
1214 .struct_instance("main.Child", [struct_field("value", 7_i64)])
1215 .expect("child struct");
1216 let parent = program
1217 .struct_instance(
1218 "main.Parent",
1219 [
1220 struct_field("child", child.clone()),
1221 struct_field("label", "parent label"),
1222 ],
1223 )
1224 .expect("parent struct");
1225
1226 let handle = parent.to_handle();
1227 let view = ParentView::from_handle(&handle).expect("construct view");
1228 assert_eq!(view.child.field::<i64>("value").expect("child value"), 7);
1229 let label_rc_from_view = view.label.as_rc();
1230 assert_eq!(&*label_rc_from_view, "parent label");
1231
1232 let label_ref = parent.borrow_field("label").expect("borrow label");
1233 let label_rc = label_ref.as_rc_string().expect("label rc");
1234 assert!(Rc::ptr_eq(&label_rc_from_view, &label_rc));
1235
1236 let child_view = ChildView::from_handle(&view.child).expect("child view");
1237 assert_eq!(child_view.value.as_int().expect("child value"), 7);
1238
1239 match ParentView::from_handle(&child.to_handle()) {
1240 Ok(_) => panic!("expected type mismatch"),
1241 Err(LustError::TypeError { message }) => {
1242 assert!(message.contains("Parent"), "unexpected message: {message}");
1243 }
1244 Err(other) => panic!("unexpected error: {other:?}"),
1245 }
1246 }
1247
1248 #[test]
1249 fn globals_snapshot_exposes_lust_values() {
1250 let _guard = serial_guard();
1251 let source = r#"
1252 struct Child
1253 value: int
1254 end
1255
1256 struct Parent
1257 child: unknown
1258 end
1259
1260 function make_parent(): Parent
1261 return Parent { child = Child { value = 3 } }
1262 end
1263 "#;
1264
1265 let mut program = build_program(source);
1266 program.run_entry_script().expect("run entry script");
1267 let parent: StructInstance = program
1268 .call_typed("main.make_parent", ())
1269 .expect("call make_parent");
1270 program.set_global_value("main.some_nested_structure", parent.clone());
1271
1272 let globals = program.globals();
1273 let (_, value) = globals
1274 .into_iter()
1275 .find(|(name, _)| name.ends_with("some_nested_structure"))
1276 .expect("global binding present");
1277 let stored =
1278 <StructInstance as FromLustValue>::from_value(value).expect("convert to struct");
1279 let child_value = stored
1280 .field::<StructInstance>("child")
1281 .expect("nested child");
1282 assert_eq!(child_value.field::<i64>("value").expect("child value"), 3);
1283 }
1284
1285 #[test]
1286 fn function_handle_supports_typed_and_raw_calls() {
1287 let _guard = serial_guard();
1288 let source = r#"
1289 pub function add(a: int, b: int): int
1290 return a + b
1291 end
1292 "#;
1293
1294 let mut program = build_program(source);
1295 let handle = program
1296 .function_handle("main.add")
1297 .expect("function handle");
1298
1299 let typed: i64 = handle
1300 .call_typed(&mut program, (2_i64, 3_i64))
1301 .expect("typed call");
1302 assert_eq!(typed, 5);
1303
1304 let raw = handle
1305 .call_raw(&mut program, vec![Value::Int(4_i64), Value::Int(6_i64)])
1306 .expect("raw call");
1307 assert_eq!(raw.as_int(), Some(10));
1308
1309 let signature = program.signature("main.add").expect("signature").clone();
1310 handle
1311 .validate_signature(&program, &signature)
1312 .expect("matching signature");
1313
1314 let mut mismatched = signature.clone();
1315 mismatched.return_type = Type::new(TypeKind::Bool, Span::new(0, 0, 0, 0));
1316 assert!(
1317 handle.validate_signature(&program, &mismatched).is_err(),
1318 "expected signature mismatch"
1319 );
1320 }
1321
1322 #[test]
1323 fn async_task_native_returns_task_handle() {
1324 let _guard = serial_guard();
1325 let source = r#"
1326 extern
1327 function fetch_value(): Task
1328 end
1329
1330 pub function start(): Task
1331 return fetch_value()
1332 end
1333 "#;
1334
1335 let mut program = build_program(source);
1336 program
1337 .register_async_task_native::<(), LustInt, _, _>("fetch_value", move |_| async move {
1338 Ok(42_i64)
1339 })
1340 .expect("register async task native");
1341
1342 let task_value = program
1343 .call_raw("main.start", Vec::new())
1344 .expect("call start");
1345 let handle = match task_value {
1346 Value::Task(handle) => handle,
1347 other => panic!("expected task handle, found {other:?}"),
1348 };
1349
1350 {
1351 let mut driver = AsyncDriver::new(&mut program);
1352 driver.pump_until_idle().expect("poll async");
1353 }
1354
1355 let (state_label, last_result, err) = {
1356 let vm = program.vm_mut();
1357 let task = vm.get_task_instance(handle).expect("task instance");
1358 (
1359 task.state.as_str().to_string(),
1360 task.last_result.clone(),
1361 task.error.clone(),
1362 )
1363 };
1364 assert_eq!(state_label, "completed");
1365 assert!(err.is_none());
1366 let int_value = last_result
1367 .and_then(|value| value.as_int())
1368 .expect("int result");
1369 assert_eq!(int_value, 42);
1370 }
1371
1372 #[test]
1373 fn rust_declared_struct_and_static_method_are_available() {
1374 let _guard = serial_guard();
1375 let struct_def = StructBuilder::new("externs.math.Point")
1376 .field(struct_field_decl(
1377 "x",
1378 Type::new(TypeKind::Int, Span::dummy()),
1379 ))
1380 .field(struct_field_decl(
1381 "y",
1382 Type::new(TypeKind::Int, Span::dummy()),
1383 ))
1384 .finish();
1385 let origin_fn = FunctionBuilder::new("externs.math.origin_x")
1386 .return_type(Type::new(TypeKind::Int, Span::dummy()))
1387 .finish();
1388
1389 let module = r#"
1390 pub function make(): externs.math.Point
1391 return externs.math.Point { x = 10, y = 20 }
1392 end
1393 "#;
1394
1395 let mut program = EmbeddedProgram::builder()
1396 .module("main", module)
1397 .entry_module("main")
1398 .declare_struct(struct_def)
1399 .declare_function(origin_fn)
1400 .compile()
1401 .expect("compile program");
1402
1403 let point_value = program
1404 .call_raw("main.make", Vec::new())
1405 .expect("call make");
1406 match point_value {
1407 Value::Struct { name, .. } => assert_eq!(name, "externs.math.Point"),
1408 other => panic!("expected struct value, found {other:?}"),
1409 }
1410
1411 program
1412 .register_typed_native::<(), LustInt, _>("externs.math.origin_x", |_| Ok(123_i64))
1413 .expect("register static origin");
1414 let signature = program.signature("externs.math.origin_x");
1415 assert!(signature.is_some());
1416 }
1417
1418 #[test]
1419 fn update_field_modifies_value_in_place() {
1420 let _guard = serial_guard();
1421 let source = r#"
1422 struct Counter
1423 value: int
1424 end
1425 "#;
1426
1427 let program = build_program(source);
1428 let counter = program
1429 .struct_instance("main.Counter", [struct_field("value", 10_i64)])
1430 .expect("counter struct");
1431
1432 counter
1433 .update_field("value", |current| match current {
1434 Value::Int(v) => Ok(v + 5),
1435 other => Err(LustError::RuntimeError {
1436 message: format!("unexpected value {other:?}"),
1437 }),
1438 })
1439 .expect("update in place");
1440 assert_eq!(counter.field::<i64>("value").expect("value field"), 15);
1441
1442 let err = counter
1443 .update_field("value", |_| Ok(String::from("oops")))
1444 .expect_err("string should fail type check");
1445 match err {
1446 LustError::TypeError { message } => {
1447 assert!(message.contains("value"));
1448 assert!(message.contains("int"));
1449 }
1450 other => panic!("unexpected error: {other:?}"),
1451 }
1452 assert_eq!(counter.field::<i64>("value").expect("value field"), 15);
1453
1454 let err = counter
1455 .update_field("value", |_| -> Result<i64> {
1456 Err(LustError::RuntimeError {
1457 message: "closure failure".to_string(),
1458 })
1459 })
1460 .expect_err("closure error should propagate");
1461 match err {
1462 LustError::RuntimeError { message } => assert_eq!(message, "closure failure"),
1463 other => panic!("unexpected error: {other:?}"),
1464 }
1465 assert_eq!(counter.field::<i64>("value").expect("value field"), 15);
1466 }
1467}