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