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(¶ms[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(¶ms[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(¶ms[index]) {
1062 Ok(())
1063 } else {
1064 Err(argument_type_mismatch(
1065 function_name,
1066 index,
1067 <T as IntoLustValue>::type_description(),
1068 ¶ms[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}