1use std::fmt::{self, Debug};
2use std::sync::Arc;
3
4use ecow::eco_vec;
5
6use super::{Context, Error, TryFromValue, Type, Value};
7
8type FuncImpl<T> =
10 Arc<dyn Fn(&Context<T>, &[Value<T>]) -> Result<Value<T>, Error> + Send + Sync + 'static>;
11
12#[derive(Clone)]
15pub struct Func<T>(FuncImpl<T>);
16
17impl<T> Func<T> {
18 pub fn new<F>(f: F) -> Self
20 where
21 F: Fn(&Context<T>, &[Value<T>]) -> Result<Value<T>, Error> + Send + Sync + 'static,
22 {
23 Self(Arc::new(f) as _)
24 }
25
26 pub fn call(&self, ctx: &Context<T>, args: &[Value<T>]) -> Result<Value<T>, Error> {
28 (self.0)(ctx, args)
29 }
30}
31
32impl<T> Debug for Func<T> {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 f.debug_tuple("Func").field(&..).finish()
35 }
36}
37
38impl<T> Func<T> {
39 pub fn expect_no_args(id: &str, _ctx: &Context<T>, args: &[Value<T>]) -> Result<(), Error> {
41 if args.is_empty() {
42 Ok(())
43 } else {
44 Err(Error::InvalidArgumentCount {
45 func: id.into(),
46 expected: 0,
47 is_min: false,
48 found: args.len(),
49 })
50 }
51 }
52
53 pub fn expect_args_exact<V: TryFromValue<T> + Debug, const N: usize>(
56 func: &str,
57 _ctx: &Context<T>,
58 args: &[Value<T>],
59 ) -> Result<[V; N], Error>
60 where
61 T: Clone,
62 {
63 if args.len() < N {
64 return Err(Error::InvalidArgumentCount {
65 func: func.into(),
66 expected: N,
67 is_min: false,
68 found: args.len(),
69 });
70 }
71
72 Ok(args
73 .iter()
74 .take(N)
75 .cloned()
76 .map(V::try_from_value)
77 .collect::<Result<Vec<_>, _>>()?
78 .try_into()
79 .expect("we checked both min and max of the args"))
80 }
81
82 pub fn expect_args_min<V: TryFromValue<T> + Debug, const N: usize>(
85 func: &str,
86 _ctx: &Context<T>,
87 args: &[Value<T>],
88 ) -> Result<([V; N], Vec<V>), Error>
89 where
90 T: Clone,
91 {
92 if args.len() < N {
93 return Err(Error::InvalidArgumentCount {
94 func: func.into(),
95 expected: N,
96 is_min: true,
97 found: args.len(),
98 });
99 }
100
101 let min = args
102 .iter()
103 .take(N)
104 .cloned()
105 .map(V::try_from_value)
106 .collect::<Result<Vec<_>, _>>()?
107 .try_into()
108 .expect("we checked both min and max of the args");
109
110 Ok((
111 min,
112 args[N..]
113 .iter()
114 .cloned()
115 .map(V::try_from_value)
116 .collect::<Result<_, _>>()?,
117 ))
118 }
119}
120
121impl<T> TryFromValue<T> for Func<T> {
122 fn try_from_value(value: Value<T>) -> Result<Self, Error> {
123 Ok(match value {
124 Value::Func(set) => set,
125 _ => {
126 return Err(Error::TypeMismatch {
127 expected: eco_vec![Type::Func],
128 found: value.as_type(),
129 })
130 }
131 })
132 }
133}
134
135#[allow(dead_code)]
137fn assert_traits() {
138 tytanic_utils::assert::send::<Func<()>>();
139 tytanic_utils::assert::sync::<Func<()>>();
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145 use crate::ast::Num;
146
147 const NUM: Num = Num(0);
148 const VAL: Value<()> = Value::Num(NUM);
149
150 #[test]
151 fn test_expect_args_variadic_min_length() {
152 let ctx = Context::new();
153
154 assert_eq!(
155 Func::expect_args_min::<Num, 0>("f", &ctx, &[]).unwrap(),
156 ([], vec![]),
157 );
158 assert_eq!(
159 Func::expect_args_min("f", &ctx, &[VAL]).unwrap(),
160 ([], vec![NUM]),
161 );
162 assert_eq!(
163 Func::expect_args_min("f", &ctx, &[VAL, VAL]).unwrap(),
164 ([], vec![NUM, NUM]),
165 );
166
167 assert!(Func::expect_args_min::<Num, 1>("f", &ctx, &[]).is_err());
168 assert_eq!(
169 Func::expect_args_min("f", &ctx, &[VAL]).unwrap(),
170 ([NUM], vec![]),
171 );
172 assert_eq!(
173 Func::expect_args_min("f", &ctx, &[VAL, VAL]).unwrap(),
174 ([NUM], vec![NUM]),
175 );
176
177 assert!(Func::expect_args_min::<Num, 2>("f", &ctx, &[]).is_err());
178 assert!(Func::expect_args_min::<Num, 2>("f", &ctx, &[VAL]).is_err(),);
179 assert_eq!(
180 Func::expect_args_min("f", &ctx, &[VAL, VAL]).unwrap(),
181 ([NUM, NUM], vec![]),
182 );
183 }
184}