1#![allow(clippy::needless_pass_by_value)]
26#![allow(clippy::unnecessary_wraps)]
27
28use std::{error::Error, fmt, sync::Arc};
29
30use crate::{FromValue, IntoValue, Value};
31
32pub mod capitalize;
33pub mod ends_with;
34pub mod entries;
35pub mod enumerate;
36pub mod first;
37pub mod iter;
38pub mod last;
39pub mod len;
40pub mod reading_time;
41pub mod replace;
42pub mod reverse;
43pub mod round;
44pub mod skip;
45pub mod slugify;
46pub mod sort;
47pub mod split;
48pub mod starts_with;
49pub mod take;
50pub mod to_string;
51pub mod trim;
52pub mod word_count;
53
54pub type FunctionError = Box<dyn Error>;
55pub type FunctionResult<T> = Result<T, FunctionError>;
56
57#[derive(Clone)]
58pub struct Function(Arc<dyn Fn(Vec<Value>) -> FunctionResult<Value> + Send + Sync>);
59
60impl Function {
61 pub fn new<
62 Args: AsArguments + 'static,
63 Return: IntoValue,
64 F: Callable<Args, Return> + Send + Sync + 'static,
65 >(
66 func: F,
67 ) -> Self {
68 Self::new_raw(move |args: Vec<Value>| {
71 func.call(Args::as_arguments(args)?)
72 .map(IntoValue::into_value)
73 })
74 }
75
76 pub fn new_raw<F: Fn(Vec<Value>) -> FunctionResult<Value> + Send + Sync + 'static>(f: F) -> Self {
83 Self(Arc::new(f))
84 }
85
86 pub fn call(&self, args: Vec<Value>) -> Result<Value, Box<dyn Error>> {
92 (self.0)(args)
93 }
94}
95
96impl fmt::Debug for Function {
97 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98 f.debug_tuple("Function").finish()
99 }
100}
101
102pub trait Callable<Args, Return> {
105 fn call(&self, args: Args) -> Result<Return, Box<dyn Error>>;
111}
112
113pub trait AsArguments {
116 fn as_arguments(val: Vec<Value>) -> Result<Self, Box<dyn Error>>
122 where
123 Self: Sized;
124}
125
126macro_rules! gen_impl {
127 ( $num_args:literal, $(($n:tt, $T:ident)),+ ) => {
128 impl<Func, Return, $($T: FromValue,)+> Callable<($($T,)+), Return> for Func
129 where
130 Func: Fn($($T,)+) -> Result<Return, Box<dyn Error>>,
131 {
132 fn call(&self, args: ($($T,)+)) -> Result<Return, Box<dyn Error>> {
133 (self)($(args.$n,)+)
134 }
135 }
136
137 impl<$($T: FromValue,)+> AsArguments for ($($T,)+) {
138 fn as_arguments(mut val: Vec<Value>) -> Result<Self, Box<dyn Error>> {
139 if val.len() > $num_args {
140 Err(format!("expected {} argument{}, found {}", $num_args, if $num_args > 1 { "s" } else { "" }, val.len()).into())
141 } else if val.len() < $num_args {
142 Ok(($(if $n < val.len() { $T::from_value(val.remove(0))? } else { $T::from_value(Value::Null)? },)+))
143 } else {
144 Ok(($($T::from_value(val.remove(0))?,)+))
145 }
146 }
147 }
148 }
149}
150
151#[rustfmt::skip]
152mod impls {
153 use super::{AsArguments, Callable, Error, FromValue, Value};
154
155 impl<Func, Return> Callable<(), Return> for Func
156 where
157 Func: Fn() -> Result<Return, Box<dyn Error>>,
158 {
159 fn call(&self, _args: ()) -> Result<Return, Box<dyn Error>> {
160 (self)()
161 }
162 }
163
164 impl AsArguments for () {
165 fn as_arguments(val: Vec<Value>) -> Result<Self, Box<dyn Error>> {
166 if val.is_empty() {
167 Ok(())
168 } else {
169 Err(format!("expected 0 arguments, found {}", val.len()).into())
170 }
171 }
172 }
173
174 gen_impl!(1, (0, A));
175 gen_impl!(2, (0, A), (1, B));
176 gen_impl!(3, (0, A), (1, B), (2, C));
177 gen_impl!(4, (0, A), (1, B), (2, C), (3, D));
178 gen_impl!(5, (0, A), (1, B), (2, C), (3, D), (4, E));
179 gen_impl!(6, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F));
180 gen_impl!(7, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G));
181 gen_impl!(8, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H));
182 gen_impl!(9, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I));
183 gen_impl!(10, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I), (9, J));
184 gen_impl!(11, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I), (9, J), (10, K));
185 gen_impl!(12, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I), (9, J), (10, K), (11, L));
186 gen_impl!(13, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I), (9, J), (10, K), (11, L), (12, M));
187 gen_impl!(14, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I), (9, J), (10, K), (11, L), (12, M), (13, N));
188 gen_impl!(15, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I), (9, J), (10, K), (11, L), (12, M), (13, N), (14, O));
189 gen_impl!(16, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I), (9, J), (10, K), (11, L), (12, M), (13, N), (14, O), (15, P));
190}