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