Skip to main content

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