1use crate::Value;
2use crate::args::Kwargs;
3use crate::errors::{Error, TeraResult};
4use crate::value::FunctionResult;
5use crate::vm::state::State;
6use std::sync::Arc;
7
8pub trait Function<Res: FunctionResult>: Sync + Send + 'static {
10 fn call(&self, kwargs: Kwargs, state: &State) -> Res;
12
13 fn is_safe(&self) -> bool {
16 false
17 }
18}
19
20impl<Func, Res> Function<Res> for Func
21where
22 Func: Fn(Kwargs, &State) -> Res + Sync + Send + 'static,
23 Res: FunctionResult,
24{
25 fn call(&self, kwargs: Kwargs, state: &State) -> Res {
26 (self)(kwargs, state)
27 }
28}
29
30type FunctionFunc = dyn Fn(Kwargs, &State) -> TeraResult<Value> + Sync + Send + 'static;
31
32#[derive(Clone)]
33pub(crate) struct StoredFunction {
34 func: Arc<FunctionFunc>,
35 is_safe: bool,
36}
37
38impl StoredFunction {
39 pub fn new<Func, Res>(f: Func) -> Self
40 where
41 Func: Function<Res>,
42 Res: FunctionResult,
43 {
44 let is_safe = f.is_safe();
45 let closure = move |kwargs, state: &State| -> TeraResult<Value> {
46 f.call(kwargs, state).into_result()
47 };
48
49 StoredFunction {
50 func: Arc::new(closure),
51 is_safe,
52 }
53 }
54
55 pub fn call(&self, kwargs: Kwargs, state: &State) -> TeraResult<Value> {
56 (self.func)(kwargs, state)
57 }
58
59 pub fn is_safe(&self) -> bool {
60 self.is_safe
61 }
62}
63
64const MAX_RANGE_LEN: usize = 100_000;
66
67pub(crate) fn range(kwargs: Kwargs, _: &State) -> TeraResult<Vec<i128>> {
68 let start = kwargs.get::<i128>("start")?.unwrap_or_default();
69 let end = kwargs.must_get::<i128>("end")?;
70 let step_by = kwargs.get::<i128>("step_by")?.unwrap_or(1);
71 if start > end && step_by > 0 {
72 return Err(Error::message(
73 "Function `range` was called with a `start` argument greater than the `end` one",
74 ));
75 }
76 if step_by == 0 {
77 return Err(Error::message(
78 "Function `range` was called with a `step_by` argument of 0",
79 ));
80 }
81
82 let overflow =
83 || Error::message("Function `range` was called with arguments that overflow i128");
84 let len = if step_by > 0 {
85 let span = end.checked_sub(start).ok_or_else(overflow)?;
86 span.checked_add(step_by - 1).ok_or_else(overflow)? / step_by
87 } else if start <= end {
88 0
89 } else {
90 let step = step_by.checked_neg().ok_or_else(overflow)?;
91 let span = start.checked_sub(end).ok_or_else(overflow)?;
92 span.checked_add(step - 1).ok_or_else(overflow)? / step
93 };
94 if len > MAX_RANGE_LEN as i128 {
95 return Err(Error::message(format!(
96 "Function `range` would produce {len} elements, which exceeds the limit of {MAX_RANGE_LEN}"
97 )));
98 }
99
100 let mut values = Vec::with_capacity(len as usize);
101 for i in 0..len {
102 values.push(start + i * step_by);
103 }
104 Ok(values)
105}
106
107pub(crate) fn throw(kwargs: Kwargs, _: &State) -> TeraResult<bool> {
108 let message = kwargs.must_get::<&str>("message")?;
109 Err(Error::message(message))
110}