lust/embed/
values.rs

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}