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