1use std::{any::Any, rc::Rc};
2
3use crate::model::{FloatType, HashMapRc, IntType, List, RuntimeError, Symbol, Value};
4
5pub fn require_arg<'a>(
8 func_or_form_name: &str,
9 args: &'a [Value],
10 index: usize,
11) -> Result<&'a Value, RuntimeError> {
12 args.get(index).ok_or_else(|| RuntimeError {
13 msg: format!(
14 "\"{}\" requires an argument {}",
15 func_or_form_name,
16 index + 1
17 ),
18 })
19}
20
21pub fn require_typed_arg<'a, T>(
25 func_or_form_name: &str,
26 args: &'a [Value],
27 index: usize,
28) -> Result<T, RuntimeError>
29where
30 T: TryFrom<&'a Value> + TypeName,
31{
32 require_arg(func_or_form_name, args, index)?
33 .try_into()
34 .map_err(|_| RuntimeError {
35 msg: format!(
36 "\"{}\" requires argument {} to be a {}; got {}",
37 func_or_form_name,
38 index + 1,
39 T::get_name(),
40 args.get(index).unwrap_or(&Value::NIL)
41 ),
42 })
43}
44
45pub trait TypeName {
46 fn get_name() -> &'static str;
47}
48
49impl TypeName for IntType {
50 fn get_name() -> &'static str {
51 "int"
52 }
53}
54
55impl TypeName for FloatType {
56 fn get_name() -> &'static str {
57 "float"
58 }
59}
60
61impl TypeName for &String {
62 fn get_name() -> &'static str {
63 "string"
64 }
65}
66
67impl TypeName for &Symbol {
68 fn get_name() -> &'static str {
69 "symbol"
70 }
71}
72
73impl TypeName for &List {
74 fn get_name() -> &'static str {
75 "list"
76 }
77}
78
79impl TypeName for &HashMapRc {
80 fn get_name() -> &'static str {
81 "hash map"
82 }
83}
84
85impl TypeName for &Rc<dyn Any> {
86 fn get_name() -> &'static str {
87 "foreign value"
88 }
89}