Skip to main content

lust/embed/
conversions.rs

1use super::values::{
2    matches_array_handle_type, matches_array_type, matches_function_handle_type, matches_lust_enum,
3    matches_lust_struct, matches_map_handle_type, ArrayHandle, EnumInstance, FunctionHandle,
4    MapHandle, StringRef, StructHandle, StructInstance, TypedValue, ValueRef,
5};
6use crate::ast::{Span, Type, TypeKind};
7use crate::bytecode::Value;
8use crate::number::{LustFloat, LustInt};
9use crate::{LustError, Result};
10use std::any::TypeId;
11use std::rc::Rc;
12
13fn struct_field_type_error(field: &str, expected: &str, actual: &Value) -> LustError {
14    LustError::TypeError {
15        message: format!(
16            "Struct field '{}' expects '{}' but received value of type '{:?}'",
17            field,
18            expected,
19            actual.type_of()
20        ),
21    }
22}
23
24pub trait FromStructField<'a>: Sized {
25    fn from_value(field: &str, value: ValueRef<'a>) -> Result<Self>;
26}
27
28impl<'a> FromStructField<'a> for ValueRef<'a> {
29    fn from_value(_field: &str, value: ValueRef<'a>) -> Result<Self> {
30        Ok(value)
31    }
32}
33
34impl<'a> FromStructField<'a> for StructHandle {
35    fn from_value(field: &str, value: ValueRef<'a>) -> Result<Self> {
36        value
37            .as_struct_handle()
38            .ok_or_else(|| struct_field_type_error(field, "struct", value.as_value()))
39    }
40}
41
42impl<'a> FromStructField<'a> for StructInstance {
43    fn from_value(field: &str, value: ValueRef<'a>) -> Result<Self> {
44        value
45            .as_struct_handle()
46            .map(|handle| handle.to_instance())
47            .ok_or_else(|| struct_field_type_error(field, "struct", value.as_value()))
48    }
49}
50
51impl<'a> FromStructField<'a> for ArrayHandle {
52    fn from_value(field: &str, value: ValueRef<'a>) -> Result<Self> {
53        value
54            .as_array_handle()
55            .ok_or_else(|| struct_field_type_error(field, "array", value.as_value()))
56    }
57}
58
59impl<'a> FromStructField<'a> for MapHandle {
60    fn from_value(field: &str, value: ValueRef<'a>) -> Result<Self> {
61        value
62            .as_map_handle()
63            .ok_or_else(|| struct_field_type_error(field, "map", value.as_value()))
64    }
65}
66
67impl<'a> FromStructField<'a> for FunctionHandle {
68    fn from_value(field: &str, value: ValueRef<'a>) -> Result<Self> {
69        let owned = value.to_owned();
70        FunctionHandle::from_value(owned)
71            .map_err(|_| struct_field_type_error(field, "function", value.as_value()))
72    }
73}
74
75impl<'a> FromStructField<'a> for LustInt {
76    fn from_value(field: &str, value: ValueRef<'a>) -> Result<Self> {
77        value
78            .as_int()
79            .ok_or_else(|| struct_field_type_error(field, "int", value.as_value()))
80    }
81}
82
83impl<'a> FromStructField<'a> for LustFloat {
84    fn from_value(field: &str, value: ValueRef<'a>) -> Result<Self> {
85        value
86            .as_float()
87            .ok_or_else(|| struct_field_type_error(field, "float", value.as_value()))
88    }
89}
90
91impl<'a> FromStructField<'a> for bool {
92    fn from_value(field: &str, value: ValueRef<'a>) -> Result<Self> {
93        value
94            .as_bool()
95            .ok_or_else(|| struct_field_type_error(field, "bool", value.as_value()))
96    }
97}
98
99impl<'a> FromStructField<'a> for Rc<String> {
100    fn from_value(field: &str, value: ValueRef<'a>) -> Result<Self> {
101        value
102            .as_rc_string()
103            .ok_or_else(|| struct_field_type_error(field, "string", value.as_value()))
104    }
105}
106
107impl<'a> FromStructField<'a> for Value {
108    fn from_value(_field: &str, value: ValueRef<'a>) -> Result<Self> {
109        Ok(value.into_owned())
110    }
111}
112
113impl<'a, T> FromStructField<'a> for Option<T>
114where
115    T: FromStructField<'a>,
116{
117    fn from_value(field: &str, value: ValueRef<'a>) -> Result<Self> {
118        if matches!(value.as_value(), Value::Nil) {
119            Ok(None)
120        } else {
121            T::from_value(field, value).map(Some)
122        }
123    }
124}
125
126impl<'a> FromStructField<'a> for StringRef<'a> {
127    fn from_value(field: &str, value: ValueRef<'a>) -> Result<Self> {
128        if value.as_string().is_some() {
129            Ok(StringRef::new(value))
130        } else {
131            Err(struct_field_type_error(field, "string", value.as_value()))
132        }
133    }
134}
135
136impl<'a> FromStructField<'a> for EnumInstance {
137    fn from_value(field: &str, value: ValueRef<'a>) -> Result<Self> {
138        match value.as_value() {
139            Value::Enum { .. } => <EnumInstance as FromLustValue>::from_value(value.into_owned()),
140            other => Err(struct_field_type_error(field, "enum", other)),
141        }
142    }
143}
144
145pub trait LustStructView<'a>: Sized {
146    const TYPE_NAME: &'static str;
147
148    fn from_handle(handle: &'a StructHandle) -> Result<Self>;
149}
150
151pub trait IntoTypedValue {
152    fn into_typed_value(self) -> TypedValue;
153}
154
155impl IntoTypedValue for Value {
156    fn into_typed_value(self) -> TypedValue {
157        TypedValue::new(self, |_value, _ty| true, "Value")
158    }
159}
160
161impl IntoTypedValue for StructInstance {
162    fn into_typed_value(self) -> TypedValue {
163        let value = self.into_value();
164        TypedValue::new(value, |v, ty| matches_lust_struct(v, ty), "struct")
165    }
166}
167
168impl IntoTypedValue for StructHandle {
169    fn into_typed_value(self) -> TypedValue {
170        <StructInstance as IntoTypedValue>::into_typed_value(self.into_instance())
171    }
172}
173
174impl IntoTypedValue for EnumInstance {
175    fn into_typed_value(self) -> TypedValue {
176        let value = self.into_value();
177        TypedValue::new(value, |v, ty| matches_lust_enum(v, ty), "enum")
178    }
179}
180
181impl IntoTypedValue for FunctionHandle {
182    fn into_typed_value(self) -> TypedValue {
183        let value = self.into_value();
184        TypedValue::new(value, |_v, ty| matches_function_handle_type(ty), "function")
185    }
186}
187
188macro_rules! impl_into_typed_for_primitive {
189    ($ty:ty, $desc:expr, $matcher:expr) => {
190        impl IntoTypedValue for $ty {
191            fn into_typed_value(self) -> TypedValue {
192                let value = self.into_value();
193                TypedValue::new(value, $matcher, $desc)
194            }
195        }
196    };
197}
198
199impl_into_typed_for_primitive!(LustInt, "int", |_, ty: &Type| match &ty.kind {
200    TypeKind::Int | TypeKind::Unknown => true,
201    TypeKind::Union(types) => types
202        .iter()
203        .any(|alt| matches!(&alt.kind, TypeKind::Int | TypeKind::Unknown)),
204    _ => false,
205});
206impl_into_typed_for_primitive!(LustFloat, "float", |_, ty: &Type| match &ty.kind {
207    TypeKind::Float | TypeKind::Unknown => true,
208    TypeKind::Union(types) => types
209        .iter()
210        .any(|alt| matches!(&alt.kind, TypeKind::Float | TypeKind::Unknown)),
211    _ => false,
212});
213impl_into_typed_for_primitive!(bool, "bool", |_, ty: &Type| match &ty.kind {
214    TypeKind::Bool | TypeKind::Unknown => true,
215    TypeKind::Union(types) => types
216        .iter()
217        .any(|alt| matches!(&alt.kind, TypeKind::Bool | TypeKind::Unknown)),
218    _ => false,
219});
220impl IntoTypedValue for String {
221    fn into_typed_value(self) -> TypedValue {
222        let value = self.into_value();
223        TypedValue::new(value, string_matcher, "string")
224    }
225}
226
227impl<'a> IntoTypedValue for &'a str {
228    fn into_typed_value(self) -> TypedValue {
229        let value = self.into_value();
230        TypedValue::new(value, string_matcher, "string")
231    }
232}
233
234impl<'a> IntoTypedValue for &'a String {
235    fn into_typed_value(self) -> TypedValue {
236        let value = self.into_value();
237        TypedValue::new(value, string_matcher, "string")
238    }
239}
240
241impl IntoTypedValue for () {
242    fn into_typed_value(self) -> TypedValue {
243        TypedValue::new(
244            Value::Nil,
245            |_, ty| matches!(ty.kind, TypeKind::Unit | TypeKind::Unknown),
246            "unit",
247        )
248    }
249}
250
251impl<T> IntoTypedValue for Vec<T>
252where
253    T: IntoLustValue,
254{
255    fn into_typed_value(self) -> TypedValue {
256        let values = self.into_iter().map(|item| item.into_value()).collect();
257        TypedValue::new(
258            Value::array(values),
259            |_, ty| matches_array_type(ty, &T::matches_lust_type),
260            "array",
261        )
262    }
263}
264
265impl IntoTypedValue for ArrayHandle {
266    fn into_typed_value(self) -> TypedValue {
267        let value = self.into_value();
268        TypedValue::new(value, |_, ty| matches_array_handle_type(ty), "array")
269    }
270}
271
272impl IntoTypedValue for MapHandle {
273    fn into_typed_value(self) -> TypedValue {
274        let value = self.into_value();
275        TypedValue::new(value, |_, ty| matches_map_handle_type(ty), "map")
276    }
277}
278
279fn string_matcher(_: &Value, ty: &Type) -> bool {
280    match &ty.kind {
281        TypeKind::String | TypeKind::Unknown => true,
282        TypeKind::Union(types) => types
283            .iter()
284            .any(|alt| matches!(&alt.kind, TypeKind::String | TypeKind::Unknown)),
285        _ => false,
286    }
287}
288
289pub trait FromLustArgs: Sized {
290    fn from_values(values: &[Value]) -> std::result::Result<Self, String>;
291    fn matches_signature(params: &[Type]) -> bool;
292}
293
294macro_rules! impl_from_lust_args_tuple {
295    ($( $name:ident ),+) => {
296        impl<$($name),+> FromLustArgs for ($($name,)+)
297        where
298            $($name: FromLustValue,)+
299        {
300            fn from_values(values: &[Value]) -> std::result::Result<Self, String> {
301                let expected = count_idents!($($name),+);
302                if values.len() != expected {
303                    return Err(format!(
304                        "Native function expected {} argument(s) but received {}",
305                        expected,
306                        values.len()
307                    ));
308                }
309
310                let mut idx = 0;
311                let result = (
312                    $(
313                        {
314                            let value = $name::from_value(values[idx].clone()).map_err(|e| e.to_string())?;
315                            idx += 1;
316                            value
317                        },
318                    )+
319                );
320                let _ = idx;
321                Ok(result)
322            }
323
324            fn matches_signature(params: &[Type]) -> bool {
325                let expected = count_idents!($($name),+);
326                params.len() == expected && {
327                    let mut idx = 0;
328                    let mut ok = true;
329                    $(
330                        if ok && !$name::matches_lust_type(&params[idx]) {
331                            ok = false;
332                        }
333
334                        idx += 1;
335                    )+
336                    let _ = idx;
337                    ok
338                }
339
340            }
341
342        }
343
344    };
345}
346
347macro_rules! count_idents {
348    ($($name:ident),*) => {
349        <[()]>::len(&[$(count_idents!(@sub $name)),*])
350    };
351    (@sub $name:ident) => { () };
352}
353
354impl_from_lust_args_tuple!(A);
355impl_from_lust_args_tuple!(A, B);
356impl_from_lust_args_tuple!(A, B, C);
357impl_from_lust_args_tuple!(A, B, C, D);
358impl_from_lust_args_tuple!(A, B, C, D, E);
359impl<T> FromLustArgs for T
360where
361    T: FromLustValue,
362{
363    fn from_values(values: &[Value]) -> std::result::Result<Self, String> {
364        match values.len() {
365            0 => T::from_value(Value::Nil).map_err(|e| e.to_string()),
366            1 => T::from_value(values[0].clone()).map_err(|e| e.to_string()),
367            count => Err(format!(
368                "Native function expected 1 argument but received {}",
369                count
370            )),
371        }
372    }
373
374    fn matches_signature(params: &[Type]) -> bool {
375        if params.is_empty() {
376            let unit = Type::new(TypeKind::Unit, Span::new(0, 0, 0, 0));
377            return T::matches_lust_type(&unit);
378        }
379
380        params.len() == 1 && T::matches_lust_type(&params[0])
381    }
382}
383
384pub trait IntoLustValue: Sized {
385    fn into_value(self) -> Value;
386    fn matches_lust_type(ty: &Type) -> bool;
387    fn type_description() -> &'static str;
388}
389
390pub trait FromLustValue: Sized {
391    fn from_value(value: Value) -> Result<Self>;
392    fn matches_lust_type(ty: &Type) -> bool;
393    fn type_description() -> &'static str;
394}
395
396pub trait FunctionArgs {
397    fn into_values(self) -> Vec<Value>;
398    fn validate_signature(function_name: &str, params: &[Type]) -> Result<()>;
399}
400
401impl IntoLustValue for Value {
402    fn into_value(self) -> Value {
403        self
404    }
405
406    fn matches_lust_type(_: &Type) -> bool {
407        true
408    }
409
410    fn type_description() -> &'static str {
411        "Value"
412    }
413}
414
415impl FromLustValue for Value {
416    fn from_value(value: Value) -> Result<Self> {
417        Ok(value)
418    }
419
420    fn matches_lust_type(_: &Type) -> bool {
421        true
422    }
423
424    fn type_description() -> &'static str {
425        "Value"
426    }
427}
428
429impl IntoLustValue for () {
430    fn into_value(self) -> Value {
431        Value::Nil
432    }
433
434    fn matches_lust_type(ty: &Type) -> bool {
435        matches!(ty.kind, TypeKind::Unit | TypeKind::Unknown)
436    }
437
438    fn type_description() -> &'static str {
439        "unit"
440    }
441}
442
443impl IntoLustValue for LustInt {
444    fn into_value(self) -> Value {
445        Value::Int(self)
446    }
447
448    fn matches_lust_type(ty: &Type) -> bool {
449        matches!(ty.kind, TypeKind::Int | TypeKind::Unknown)
450    }
451
452    fn type_description() -> &'static str {
453        "int"
454    }
455}
456
457impl FromLustValue for LustInt {
458    fn from_value(value: Value) -> Result<Self> {
459        match value {
460            Value::Int(v) => Ok(v),
461            other => Err(LustError::RuntimeError {
462                message: format!("Expected Lust value 'int' but received '{:?}'", other),
463            }),
464        }
465    }
466
467    fn matches_lust_type(ty: &Type) -> bool {
468        matches!(ty.kind, TypeKind::Int | TypeKind::Unknown)
469    }
470
471    fn type_description() -> &'static str {
472        "int"
473    }
474}
475
476impl IntoLustValue for LustFloat {
477    fn into_value(self) -> Value {
478        Value::Float(self)
479    }
480
481    fn matches_lust_type(ty: &Type) -> bool {
482        matches!(ty.kind, TypeKind::Float | TypeKind::Unknown)
483    }
484
485    fn type_description() -> &'static str {
486        "float"
487    }
488}
489
490impl FromLustValue for LustFloat {
491    fn from_value(value: Value) -> Result<Self> {
492        match value {
493            Value::Float(v) => Ok(v),
494            other => Err(LustError::RuntimeError {
495                message: format!("Expected Lust value 'float' but received '{:?}'", other),
496            }),
497        }
498    }
499
500    fn matches_lust_type(ty: &Type) -> bool {
501        matches!(ty.kind, TypeKind::Float | TypeKind::Unknown)
502    }
503
504    fn type_description() -> &'static str {
505        "float"
506    }
507}
508
509impl IntoLustValue for bool {
510    fn into_value(self) -> Value {
511        Value::Bool(self)
512    }
513
514    fn matches_lust_type(ty: &Type) -> bool {
515        matches!(ty.kind, TypeKind::Bool | TypeKind::Unknown)
516    }
517
518    fn type_description() -> &'static str {
519        "bool"
520    }
521}
522
523impl FromLustValue for bool {
524    fn from_value(value: Value) -> Result<Self> {
525        match value {
526            Value::Bool(b) => Ok(b),
527            other => Err(LustError::RuntimeError {
528                message: format!("Expected Lust value 'bool' but received '{:?}'", other),
529            }),
530        }
531    }
532
533    fn matches_lust_type(ty: &Type) -> bool {
534        matches!(ty.kind, TypeKind::Bool | TypeKind::Unknown)
535    }
536
537    fn type_description() -> &'static str {
538        "bool"
539    }
540}
541
542impl IntoLustValue for String {
543    fn into_value(self) -> Value {
544        Value::String(Rc::new(self))
545    }
546
547    fn matches_lust_type(ty: &Type) -> bool {
548        matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
549    }
550
551    fn type_description() -> &'static str {
552        "string"
553    }
554}
555
556impl IntoLustValue for Rc<String> {
557    fn into_value(self) -> Value {
558        Value::String(self)
559    }
560
561    fn matches_lust_type(ty: &Type) -> bool {
562        matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
563    }
564
565    fn type_description() -> &'static str {
566        "string"
567    }
568}
569
570impl IntoLustValue for StructInstance {
571    fn into_value(self) -> Value {
572        self.into_value()
573    }
574
575    fn matches_lust_type(ty: &Type) -> bool {
576        match &ty.kind {
577            TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
578            TypeKind::Union(types) => types
579                .iter()
580                .any(|alt| <Self as IntoLustValue>::matches_lust_type(alt)),
581            _ => false,
582        }
583    }
584
585    fn type_description() -> &'static str {
586        "struct"
587    }
588}
589
590impl IntoLustValue for StructHandle {
591    fn into_value(self) -> Value {
592        <StructInstance as IntoLustValue>::into_value(self.into_instance())
593    }
594
595    fn matches_lust_type(ty: &Type) -> bool {
596        <StructInstance as IntoLustValue>::matches_lust_type(ty)
597    }
598
599    fn type_description() -> &'static str {
600        <StructInstance as IntoLustValue>::type_description()
601    }
602}
603
604impl IntoLustValue for FunctionHandle {
605    fn into_value(self) -> Value {
606        self.into_value()
607    }
608
609    fn matches_lust_type(ty: &Type) -> bool {
610        matches_function_handle_type(ty)
611    }
612
613    fn type_description() -> &'static str {
614        "function"
615    }
616}
617
618impl FromLustValue for StructInstance {
619    fn from_value(value: Value) -> Result<Self> {
620        match &value {
621            Value::Struct { name, .. } => Ok(StructInstance::new(name.clone(), value)),
622            other => Err(LustError::RuntimeError {
623                message: format!("Expected Lust value 'struct' but received '{:?}'", other),
624            }),
625        }
626    }
627
628    fn matches_lust_type(ty: &Type) -> bool {
629        match &ty.kind {
630            TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
631            TypeKind::Union(types) => types
632                .iter()
633                .any(|alt| <Self as FromLustValue>::matches_lust_type(alt)),
634            _ => false,
635        }
636    }
637
638    fn type_description() -> &'static str {
639        "struct"
640    }
641}
642
643impl FromLustValue for StructHandle {
644    fn from_value(value: Value) -> Result<Self> {
645        <StructInstance as FromLustValue>::from_value(value).map(StructHandle::from)
646    }
647
648    fn matches_lust_type(ty: &Type) -> bool {
649        <StructInstance as FromLustValue>::matches_lust_type(ty)
650    }
651
652    fn type_description() -> &'static str {
653        <StructInstance as FromLustValue>::type_description()
654    }
655}
656
657impl FromLustValue for FunctionHandle {
658    fn from_value(value: Value) -> Result<Self> {
659        if FunctionHandle::is_callable_value(&value) {
660            Ok(FunctionHandle::new_unchecked(value))
661        } else {
662            Err(LustError::RuntimeError {
663                message: format!("Expected Lust value 'function' but received '{:?}'", value),
664            })
665        }
666    }
667
668    fn matches_lust_type(ty: &Type) -> bool {
669        matches_function_handle_type(ty)
670    }
671
672    fn type_description() -> &'static str {
673        "function"
674    }
675}
676
677impl IntoLustValue for EnumInstance {
678    fn into_value(self) -> Value {
679        self.into_value()
680    }
681
682    fn matches_lust_type(ty: &Type) -> bool {
683        match &ty.kind {
684            TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
685            TypeKind::Union(types) => types
686                .iter()
687                .any(|alt| <Self as IntoLustValue>::matches_lust_type(alt)),
688            _ => false,
689        }
690    }
691
692    fn type_description() -> &'static str {
693        "enum"
694    }
695}
696
697impl FromLustValue for EnumInstance {
698    fn from_value(value: Value) -> Result<Self> {
699        match &value {
700            Value::Enum {
701                enum_name, variant, ..
702            } => Ok(EnumInstance::new(enum_name.clone(), variant.clone(), value)),
703            other => Err(LustError::RuntimeError {
704                message: format!("Expected Lust value 'enum' but received '{:?}'", other),
705            }),
706        }
707    }
708
709    fn matches_lust_type(ty: &Type) -> bool {
710        match &ty.kind {
711            TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
712            TypeKind::Union(types) => types
713                .iter()
714                .any(|alt| <Self as FromLustValue>::matches_lust_type(alt)),
715            _ => false,
716        }
717    }
718
719    fn type_description() -> &'static str {
720        "enum"
721    }
722}
723
724impl<T> IntoLustValue for Vec<T>
725where
726    T: IntoLustValue,
727{
728    fn into_value(self) -> Value {
729        let values = self.into_iter().map(|item| item.into_value()).collect();
730        Value::array(values)
731    }
732
733    fn matches_lust_type(ty: &Type) -> bool {
734        matches_array_type(ty, &T::matches_lust_type)
735    }
736
737    fn type_description() -> &'static str {
738        "array"
739    }
740}
741
742impl IntoLustValue for ArrayHandle {
743    fn into_value(self) -> Value {
744        self.into_value()
745    }
746
747    fn matches_lust_type(ty: &Type) -> bool {
748        matches_array_handle_type(ty)
749    }
750
751    fn type_description() -> &'static str {
752        "array"
753    }
754}
755
756impl IntoLustValue for MapHandle {
757    fn into_value(self) -> Value {
758        self.into_value()
759    }
760
761    fn matches_lust_type(ty: &Type) -> bool {
762        matches_map_handle_type(ty)
763    }
764
765    fn type_description() -> &'static str {
766        "map"
767    }
768}
769
770impl<T> FromLustValue for Vec<T>
771where
772    T: FromLustValue,
773{
774    fn from_value(value: Value) -> Result<Self> {
775        match value {
776            Value::Array(items) => {
777                let borrowed = items.borrow();
778                let mut result = Vec::with_capacity(borrowed.len());
779                for item in borrowed.iter() {
780                    result.push(T::from_value(item.clone())?);
781                }
782
783                Ok(result)
784            }
785
786            other => Err(LustError::RuntimeError {
787                message: format!("Expected Lust value 'array' but received '{:?}'", other),
788            }),
789        }
790    }
791
792    fn matches_lust_type(ty: &Type) -> bool {
793        matches_array_type(ty, &T::matches_lust_type)
794    }
795
796    fn type_description() -> &'static str {
797        "array"
798    }
799}
800
801impl FromLustValue for ArrayHandle {
802    fn from_value(value: Value) -> Result<Self> {
803        match value {
804            Value::Array(items) => Ok(ArrayHandle::from_rc(items)),
805            other => Err(LustError::RuntimeError {
806                message: format!("Expected Lust value 'array' but received '{:?}'", other),
807            }),
808        }
809    }
810
811    fn matches_lust_type(ty: &Type) -> bool {
812        matches_array_handle_type(ty)
813    }
814
815    fn type_description() -> &'static str {
816        "array"
817    }
818}
819
820impl FromLustValue for MapHandle {
821    fn from_value(value: Value) -> Result<Self> {
822        match value {
823            Value::Map(map) => Ok(MapHandle::from_rc(map)),
824            other => Err(LustError::RuntimeError {
825                message: format!("Expected Lust value 'map' but received '{:?}'", other),
826            }),
827        }
828    }
829
830    fn matches_lust_type(ty: &Type) -> bool {
831        matches_map_handle_type(ty)
832    }
833
834    fn type_description() -> &'static str {
835        "map"
836    }
837}
838
839impl<'a> IntoLustValue for &'a str {
840    fn into_value(self) -> Value {
841        Value::String(Rc::new(self.to_owned()))
842    }
843
844    fn matches_lust_type(ty: &Type) -> bool {
845        matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
846    }
847
848    fn type_description() -> &'static str {
849        "string"
850    }
851}
852
853impl<'a> IntoLustValue for &'a String {
854    fn into_value(self) -> Value {
855        Value::String(Rc::new(self.clone()))
856    }
857
858    fn matches_lust_type(ty: &Type) -> bool {
859        matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
860    }
861
862    fn type_description() -> &'static str {
863        "string"
864    }
865}
866
867impl FromLustValue for String {
868    fn from_value(value: Value) -> Result<Self> {
869        match value {
870            Value::String(s) => Ok((*s).clone()),
871            other => Err(LustError::RuntimeError {
872                message: format!("Expected Lust value 'string' but received '{:?}'", other),
873            }),
874        }
875    }
876
877    fn matches_lust_type(ty: &Type) -> bool {
878        matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
879    }
880
881    fn type_description() -> &'static str {
882        "string"
883    }
884}
885
886impl FromLustValue for Rc<String> {
887    fn from_value(value: Value) -> Result<Self> {
888        match value {
889            Value::String(s) => Ok(s),
890            other => Err(LustError::RuntimeError {
891                message: format!("Expected Lust value 'string' but received '{:?}'", other),
892            }),
893        }
894    }
895
896    fn matches_lust_type(ty: &Type) -> bool {
897        matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
898    }
899
900    fn type_description() -> &'static str {
901        "string"
902    }
903}
904
905impl FromLustValue for () {
906    fn from_value(value: Value) -> Result<Self> {
907        match value {
908            Value::Nil => Ok(()),
909            other => Err(LustError::RuntimeError {
910                message: format!("Expected Lust value 'unit' but received '{:?}'", other),
911            }),
912        }
913    }
914
915    fn matches_lust_type(ty: &Type) -> bool {
916        matches!(ty.kind, TypeKind::Unit | TypeKind::Unknown)
917    }
918
919    fn type_description() -> &'static str {
920        "unit"
921    }
922}
923
924impl<T> FunctionArgs for T
925where
926    T: IntoLustValue + 'static,
927{
928    fn into_values(self) -> Vec<Value> {
929        if TypeId::of::<T>() == TypeId::of::<()>() {
930            Vec::new()
931        } else {
932            vec![self.into_value()]
933        }
934    }
935
936    fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
937        if TypeId::of::<T>() == TypeId::of::<()>() {
938            ensure_arity(function_name, params, 0)
939        } else {
940            ensure_arity(function_name, params, 1)?;
941            ensure_arg_type::<T>(function_name, params, 0)
942        }
943    }
944}
945
946impl<A, B> FunctionArgs for (A, B)
947where
948    A: IntoLustValue,
949    B: IntoLustValue,
950{
951    fn into_values(self) -> Vec<Value> {
952        vec![self.0.into_value(), self.1.into_value()]
953    }
954
955    fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
956        ensure_arity(function_name, params, 2)?;
957        ensure_arg_type::<A>(function_name, params, 0)?;
958        ensure_arg_type::<B>(function_name, params, 1)?;
959        Ok(())
960    }
961}
962
963impl<A, B, C> FunctionArgs for (A, B, C)
964where
965    A: IntoLustValue,
966    B: IntoLustValue,
967    C: IntoLustValue,
968{
969    fn into_values(self) -> Vec<Value> {
970        vec![
971            self.0.into_value(),
972            self.1.into_value(),
973            self.2.into_value(),
974        ]
975    }
976
977    fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
978        ensure_arity(function_name, params, 3)?;
979        ensure_arg_type::<A>(function_name, params, 0)?;
980        ensure_arg_type::<B>(function_name, params, 1)?;
981        ensure_arg_type::<C>(function_name, params, 2)?;
982        Ok(())
983    }
984}
985
986impl<A, B, C, D> FunctionArgs for (A, B, C, D)
987where
988    A: IntoLustValue,
989    B: IntoLustValue,
990    C: IntoLustValue,
991    D: IntoLustValue,
992{
993    fn into_values(self) -> Vec<Value> {
994        vec![
995            self.0.into_value(),
996            self.1.into_value(),
997            self.2.into_value(),
998            self.3.into_value(),
999        ]
1000    }
1001
1002    fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
1003        ensure_arity(function_name, params, 4)?;
1004        ensure_arg_type::<A>(function_name, params, 0)?;
1005        ensure_arg_type::<B>(function_name, params, 1)?;
1006        ensure_arg_type::<C>(function_name, params, 2)?;
1007        ensure_arg_type::<D>(function_name, params, 3)?;
1008        Ok(())
1009    }
1010}
1011
1012impl<A, B, C, D, E> FunctionArgs for (A, B, C, D, E)
1013where
1014    A: IntoLustValue,
1015    B: IntoLustValue,
1016    C: IntoLustValue,
1017    D: IntoLustValue,
1018    E: IntoLustValue,
1019{
1020    fn into_values(self) -> Vec<Value> {
1021        vec![
1022            self.0.into_value(),
1023            self.1.into_value(),
1024            self.2.into_value(),
1025            self.3.into_value(),
1026            self.4.into_value(),
1027        ]
1028    }
1029
1030    fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
1031        ensure_arity(function_name, params, 5)?;
1032        ensure_arg_type::<A>(function_name, params, 0)?;
1033        ensure_arg_type::<B>(function_name, params, 1)?;
1034        ensure_arg_type::<C>(function_name, params, 2)?;
1035        ensure_arg_type::<D>(function_name, params, 3)?;
1036        ensure_arg_type::<E>(function_name, params, 4)?;
1037        Ok(())
1038    }
1039}
1040
1041fn ensure_arity(function_name: &str, params: &[Type], provided: usize) -> Result<()> {
1042    if params.len() == provided {
1043        Ok(())
1044    } else {
1045        Err(LustError::TypeError {
1046            message: format!(
1047                "Function '{}' expects {} argument(s) but {} were supplied",
1048                function_name,
1049                params.len(),
1050                provided
1051            ),
1052        })
1053    }
1054}
1055
1056fn ensure_arg_type<T: IntoLustValue>(
1057    function_name: &str,
1058    params: &[Type],
1059    index: usize,
1060) -> Result<()> {
1061    if <T as IntoLustValue>::matches_lust_type(&params[index]) {
1062        Ok(())
1063    } else {
1064        Err(argument_type_mismatch(
1065            function_name,
1066            index,
1067            <T as IntoLustValue>::type_description(),
1068            &params[index],
1069        ))
1070    }
1071}
1072
1073fn argument_type_mismatch(
1074    function_name: &str,
1075    index: usize,
1076    rust_type: &str,
1077    lust_type: &Type,
1078) -> LustError {
1079    LustError::TypeError {
1080        message: format!(
1081            "Function '{}' parameter {} expects Lust type '{}' but Rust provided '{}'",
1082            function_name,
1083            index + 1,
1084            lust_type,
1085            rust_type
1086        ),
1087    }
1088}