pax_runtime_api/pax_value/
functions.rs1use crate::{
2 math::{Transform2, Vector2},
3 Color, ColorChannel, Paint, PaxValue, Rotation,
4};
5use once_cell::sync::Lazy;
6use std::{
7 collections::HashMap,
8 sync::{Arc, RwLock},
9};
10
11use super::{CoercionRules, ToPaxValue};
12
13type FunctionType = Arc<dyn Fn(Vec<PaxValue>) -> Result<PaxValue, String> + Send + Sync>;
14
15static FUNCTIONS: Lazy<Arc<RwLock<HashMap<String, HashMap<String, FunctionType>>>>> =
16 Lazy::new(|| Arc::new(RwLock::new(HashMap::new())));
17
18pub fn print_all_functions() {
20 let functions = FUNCTIONS.read().unwrap();
21 log::warn!("Total scopes: {}", functions.len());
22 for (scope, funcs) in functions.iter() {
23 log::warn!("Scope: {}", scope);
24 for (name, _) in funcs.iter() {
25 log::warn!(" |{}|", name);
26 }
27 }
28}
29
30pub fn register_function(scope: String, name: String, func: FunctionType) {
32 let mut functions = FUNCTIONS.write().unwrap();
33 functions
34 .entry(scope)
35 .or_insert_with(HashMap::new)
36 .insert(name, func);
37}
38
39pub fn call_function(scope: String, name: String, args: Vec<PaxValue>) -> Result<PaxValue, String> {
41 let functions = FUNCTIONS.read().unwrap();
42 let scope_funcs = functions
43 .get(&scope)
44 .ok_or_else(|| format!("Scope {} not found", scope))?;
45 let func = scope_funcs
46 .get(&name)
47 .ok_or_else(|| format!("Function {} not found in scope {}", name, scope))?;
48 func(args)
49}
50
51fn add(args: Vec<PaxValue>) -> Result<PaxValue, String> {
53 if args.len() != 2 {
54 return Err("Expected 2 arguments for function add".to_string());
55 }
56 let mut itr = args.into_iter();
57 Ok(itr.next().unwrap() + itr.next().unwrap())
58}
59
60fn sub_or_neg(args: Vec<PaxValue>) -> Result<PaxValue, String> {
62 if args.len() == 1 {
63 Ok(-args.into_iter().next().unwrap())
64 } else if args.len() == 2 {
65 let mut itr = args.into_iter();
66 Ok(itr.next().unwrap() - itr.next().unwrap())
67 } else {
68 Err("Expected 1 or 2 arguments for function sub_or_neg".to_string())
69 }
70}
71
72fn mul(args: Vec<PaxValue>) -> Result<PaxValue, String> {
74 if args.len() != 2 {
75 return Err("Expected 2 arguments for function mul".to_string());
76 }
77 let mut itr = args.into_iter();
78 Ok(itr.next().unwrap() * itr.next().unwrap())
79}
80
81fn div(args: Vec<PaxValue>) -> Result<PaxValue, String> {
83 if args.len() != 2 {
84 return Err("Expected 2 arguments for function div".to_string());
85 }
86 let mut itr = args.into_iter();
87 Ok(itr.next().unwrap() / itr.next().unwrap())
88}
89
90fn exp(args: Vec<PaxValue>) -> Result<PaxValue, String> {
92 if args.len() != 2 {
93 return Err("Expected 2 arguments for function exp".to_string());
94 }
95 let mut itr = args.into_iter();
96 Ok(itr.next().unwrap().pow(itr.next().unwrap()))
97}
98
99fn mod_(args: Vec<PaxValue>) -> Result<PaxValue, String> {
101 if args.len() != 2 {
102 return Err("Expected 2 arguments for function mod_".to_string());
103 }
104 let mut itr = args.into_iter();
105 Ok(itr.next().unwrap() % itr.next().unwrap())
106}
107
108fn rel_eq(args: Vec<PaxValue>) -> Result<PaxValue, String> {
110 if args.len() != 2 {
111 return Err("Expected 2 arguments for function rel_eq".to_string());
112 }
113 Ok(PaxValue::Bool(args[0] == args[1]))
114}
115
116fn rel_gt(args: Vec<PaxValue>) -> Result<PaxValue, String> {
118 if args.len() != 2 {
119 return Err("Expected 2 arguments for function rel_gt".to_string());
120 }
121 Ok(PaxValue::Bool(args[0] > args[1]))
122}
123
124fn rel_gte(args: Vec<PaxValue>) -> Result<PaxValue, String> {
126 if args.len() != 2 {
127 return Err("Expected 2 arguments for function rel_gte".to_string());
128 }
129 Ok(PaxValue::Bool(args[0] >= args[1]))
130}
131
132fn rel_lt(args: Vec<PaxValue>) -> Result<PaxValue, String> {
134 if args.len() != 2 {
135 return Err("Expected 2 arguments for function rel_lt".to_string());
136 }
137 Ok(PaxValue::Bool(args[0] < args[1]))
138}
139
140fn rel_lte(args: Vec<PaxValue>) -> Result<PaxValue, String> {
142 if args.len() != 2 {
143 return Err("Expected 2 arguments for function rel_lte".to_string());
144 }
145 Ok(PaxValue::Bool(args[0] <= args[1]))
146}
147
148fn rel_neq(args: Vec<PaxValue>) -> Result<PaxValue, String> {
150 if args.len() != 2 {
151 return Err("Expected 2 arguments for function rel_neq".to_string());
152 }
153 Ok(PaxValue::Bool(args[0] != args[1]))
154}
155
156fn bool_and(args: Vec<PaxValue>) -> Result<PaxValue, String> {
158 if args.len() != 2 {
159 return Err("Expected 2 arguments for function bool_and".to_string());
160 }
161 let mut itr = args.into_iter();
162 Ok(itr.next().unwrap().op_and(itr.next().unwrap()))
163}
164
165fn bool_or(args: Vec<PaxValue>) -> Result<PaxValue, String> {
167 if args.len() != 2 {
168 return Err("Expected 2 arguments for function bool_or".to_string());
169 }
170 let mut itr = args.into_iter();
171 Ok(itr.next().unwrap().op_or(itr.next().unwrap()))
172}
173
174fn bool_not(args: Vec<PaxValue>) -> Result<PaxValue, String> {
176 if args.len() != 1 {
177 return Err("Expected 1 argument for function bool_not".to_string());
178 }
179 Ok(args.into_iter().next().unwrap().op_not())
180}
181
182fn min(args: Vec<PaxValue>) -> Result<PaxValue, String> {
184 if args.len() != 2 {
185 return Err("Expected 2 arguments for function min".to_string());
186 }
187 let mut itr = args.into_iter();
188 Ok(itr.next().unwrap().min(itr.next().unwrap()))
189}
190
191fn max(args: Vec<PaxValue>) -> Result<PaxValue, String> {
193 if args.len() != 2 {
194 return Err("Expected 2 arguments for function max".to_string());
195 }
196 let mut itr = args.into_iter();
197 Ok(itr.next().unwrap().max(itr.next().unwrap()))
198}
199
200fn len(args: Vec<PaxValue>) -> Result<PaxValue, String> {
202 if args.len() != 1 {
203 return Err("len function takes a single argument".to_string());
204 }
205 match args.into_iter().next().unwrap() {
206 PaxValue::Vec(vec) => Ok(vec.len().to_pax_value()),
207 e => Err(format!("can't get length of {e:?}")),
208 }
209}
210
211fn rgb(args: Vec<PaxValue>) -> Result<PaxValue, String> {
213 if args.len() != 3 {
214 return Err("Expected 3 arguments for function rgb".to_string());
215 }
216 let mut itr = args.into_iter();
217 let r = ColorChannel::try_coerce(itr.next().unwrap())?;
218 let g = ColorChannel::try_coerce(itr.next().unwrap())?;
219 let b = ColorChannel::try_coerce(itr.next().unwrap())?;
220 Ok(Color::rgb(r, g, b).to_pax_value())
221}
222
223fn rgba(args: Vec<PaxValue>) -> Result<PaxValue, String> {
225 if args.len() != 4 {
226 return Err("Expected 4 arguments for function rgba".to_string());
227 }
228 let mut itr = args.into_iter();
229 let r = ColorChannel::try_coerce(itr.next().unwrap())?;
230 let g = ColorChannel::try_coerce(itr.next().unwrap())?;
231 let b = ColorChannel::try_coerce(itr.next().unwrap())?;
232 let a = ColorChannel::try_coerce(itr.next().unwrap())?;
233 Ok(Color::rgba(r, g, b, a).to_pax_value())
234}
235
236fn hsl(args: Vec<PaxValue>) -> Result<PaxValue, String> {
238 if args.len() != 3 {
239 return Err("Expected 3 arguments for function hsl".to_string());
240 }
241 let mut itr = args.into_iter();
242 let h = Rotation::try_coerce(itr.next().unwrap())?;
243 let s = ColorChannel::try_coerce(itr.next().unwrap())?;
244 let l = ColorChannel::try_coerce(itr.next().unwrap())?;
245 Ok(Color::hsl(h, s, l).to_pax_value())
246}
247
248fn hsla(args: Vec<PaxValue>) -> Result<PaxValue, String> {
250 if args.len() != 4 {
251 return Err("Expected 4 arguments for function hsla".to_string());
252 }
253 let mut itr = args.into_iter();
254 let h = Rotation::try_coerce(itr.next().unwrap())?;
255 let s = ColorChannel::try_coerce(itr.next().unwrap())?;
256 let l = ColorChannel::try_coerce(itr.next().unwrap())?;
257 let a = ColorChannel::try_coerce(itr.next().unwrap())?;
258 Ok(Color::hsla(h, s, l, a).to_pax_value())
259}
260
261fn hex(args: Vec<PaxValue>) -> Result<PaxValue, String> {
263 if args.len() != 1 {
264 return Err("Expected 1 argument for function hex".to_string());
265 }
266 let hex = String::try_coerce(args.into_iter().next().unwrap())?;
267 Ok(Color::from_hex(&hex).to_pax_value())
268}
269
270pub trait HelperFunctions {
272 fn register_all_functions() {}
274}
275
276pub struct Functions;
278
279impl Functions {
280 pub fn register_all_functions() {
282 register_function("Math".to_string(), "+".to_string(), Arc::new(add));
284 register_function("Math".to_string(), "-".to_string(), Arc::new(sub_or_neg));
285 register_function("Math".to_string(), "*".to_string(), Arc::new(mul));
286 register_function("Math".to_string(), "/".to_string(), Arc::new(div));
287 register_function("Math".to_string(), "^".to_string(), Arc::new(exp));
288 register_function("Math".to_string(), "%%".to_string(), Arc::new(mod_));
289 register_function("Math".to_string(), "==".to_string(), Arc::new(rel_eq));
290 register_function("Math".to_string(), ">".to_string(), Arc::new(rel_gt));
291 register_function("Math".to_string(), ">=".to_string(), Arc::new(rel_gte));
292 register_function("Math".to_string(), "<".to_string(), Arc::new(rel_lt));
293 register_function("Math".to_string(), "<=".to_string(), Arc::new(rel_lte));
294 register_function("Math".to_string(), "!=".to_string(), Arc::new(rel_neq));
295 register_function("Math".to_string(), "&&".to_string(), Arc::new(bool_and));
296 register_function("Math".to_string(), "||".to_string(), Arc::new(bool_or));
297 register_function("Math".to_string(), "!".to_string(), Arc::new(bool_not));
298 register_function("Math".to_string(), "min".to_string(), Arc::new(min));
299 register_function("Math".to_string(), "max".to_string(), Arc::new(max));
300 register_function("Math".to_string(), "len".to_string(), Arc::new(len));
301 register_function("Color".to_string(), "rgb".to_string(), Arc::new(rgb));
303 register_function("Color".to_string(), "rgba".to_string(), Arc::new(rgba));
304 register_function("Color".to_string(), "hsl".to_string(), Arc::new(hsl));
305 register_function("Color".to_string(), "hsla".to_string(), Arc::new(hsla));
306 register_function("Color".to_string(), "#".to_string(), Arc::new(hex));
307 crate::Transform2D::register_all_functions();
309 }
310
311 pub fn has_function(scope: &str, name: &str) -> bool {
313 let functions = FUNCTIONS.read().unwrap();
314 if let Some(scope_funcs) = functions.get(scope) {
315 scope_funcs.contains_key(name)
316 } else {
317 false
318 }
319 }
320}
321
322impl HelperFunctions for crate::Size {}
323
324impl HelperFunctions for crate::Color {}
325
326impl HelperFunctions for crate::Rotation {}
327
328impl HelperFunctions for crate::Duration {}
329
330impl HelperFunctions for String {}
331
332impl HelperFunctions for crate::Numeric {}
333
334impl HelperFunctions for crate::UnitValue {}
335
336impl HelperFunctions for bool {}
337
338impl HelperFunctions for Paint {}
339impl HelperFunctions for crate::MeshPoint {}
340impl HelperFunctions for crate::MeshGradient {}
341impl<A, B> HelperFunctions for (A, B) {}
342impl HelperFunctions for crate::Fill {}
343
344impl HelperFunctions for crate::PaxValue {}
345
346impl HelperFunctions for crate::ColorChannel {}
347
348impl HelperFunctions for crate::Opacity {}
349
350impl HelperFunctions for crate::Stroke {}
351
352impl HelperFunctions for crate::PathSmoothing {}
353
354impl HelperFunctions for crate::StrokeCap {}
355
356impl HelperFunctions for crate::StrokeJoin {}
357
358impl HelperFunctions for u8 {}
359impl HelperFunctions for u16 {}
360impl HelperFunctions for u32 {}
361impl HelperFunctions for u64 {}
362impl HelperFunctions for u128 {}
363impl HelperFunctions for usize {}
364
365impl HelperFunctions for i8 {}
366impl HelperFunctions for i16 {}
367impl HelperFunctions for i32 {}
368impl HelperFunctions for i64 {}
369impl HelperFunctions for i128 {}
370impl HelperFunctions for isize {}
371
372impl HelperFunctions for f32 {}
373impl HelperFunctions for f64 {}
374impl<T> HelperFunctions for Vec<T> {}
375
376impl<T: HelperFunctions> HelperFunctions for Option<T> {}
377
378impl HelperFunctions for crate::Transform2D {
379 fn register_all_functions() {
380 register_function(
381 "Transform2D".to_string(),
382 "scale".to_string(),
383 Arc::new(|args| {
384 if args.len() != 2 {
385 return Err("Expected 2 arguments for function scale".to_string());
386 }
387 let mut itr = args.into_iter();
388 let x = crate::Size::try_coerce(itr.next().unwrap())?;
389 let y = crate::Size::try_coerce(itr.next().unwrap())?;
390 Ok(crate::Transform2D::scale(x, y).to_pax_value())
391 }),
392 );
393 register_function(
394 "Transform2D".to_string(),
395 "rotate".to_string(),
396 Arc::new(|args| {
397 if args.len() != 1 {
398 return Err("Expected 1 argument for function rotate".to_string());
399 }
400 let z = crate::Rotation::try_coerce(args.into_iter().next().unwrap())?;
401 Ok(crate::Transform2D::rotate(z).to_pax_value())
402 }),
403 );
404 register_function(
405 "Transform2D".to_string(),
406 "translate".to_string(),
407 Arc::new(|args| {
408 if args.len() != 2 {
409 return Err("Expected 2 arguments for function translate".to_string());
410 }
411 let mut itr = args.into_iter();
412 let x = crate::Size::try_coerce(itr.next().unwrap())?;
413 let y = crate::Size::try_coerce(itr.next().unwrap())?;
414 Ok(crate::Transform2D::translate(x, y).to_pax_value())
415 }),
416 );
417 register_function(
418 "Transform2D".to_string(),
419 "anchor".to_string(),
420 Arc::new(|args| {
421 if args.len() != 2 {
422 return Err("Expected 2 arguments for function anchor".to_string());
423 }
424 let mut itr = args.into_iter();
425 let x = crate::Size::try_coerce(itr.next().unwrap())?;
426 let y = crate::Size::try_coerce(itr.next().unwrap())?;
427 Ok(crate::Transform2D::anchor(x, y).to_pax_value())
428 }),
429 );
430 }
431}
432
433impl HelperFunctions for Transform2 {
434 fn register_all_functions() {
435 register_function(
436 "Transform2".to_string(),
437 "identity".to_string(),
438 Arc::new(|args| {
439 if args.len() != 0 {
440 return Err("Expected 0 arguments for function identity".to_string());
441 }
442 Ok(Transform2::identity().to_pax_value())
443 }),
444 );
445 register_function(
446 "Transform2".to_string(),
447 "scale".to_string(),
448 Arc::new(|args| {
449 if args.len() != 1 {
450 return Err("Expected 1 argument for function scale".to_string());
451 }
452 let s = f64::try_coerce(args.into_iter().next().unwrap())?;
453 Ok(Transform2::scale(s).to_pax_value())
454 }),
455 );
456
457 register_function(
458 "Transform2".to_string(),
459 "translate".to_string(),
460 Arc::new(|args| {
461 if args.len() != 1 {
462 return Err("Expected 1 argument for function scale".to_string());
463 }
464 let s = Vector2::try_coerce(args.into_iter().next().unwrap())?;
465 Ok(Transform2::translate(s).to_pax_value())
466 }),
467 );
468
469 register_function(
470 "Transform2".to_string(),
471 "rotate".to_string(),
472 Arc::new(|args| {
473 if args.len() != 1 {
474 return Err("Expected 1 argument for function rotate".to_string());
475 }
476 let s = f64::try_coerce(args.into_iter().next().unwrap())?;
477 Ok(Transform2::rotate(s).to_pax_value())
478 }),
479 );
480 register_function(
481 "Transform2".to_string(),
482 "skew".to_string(),
483 Arc::new(|args| {
484 if args.len() != 1 {
485 return Err("Expected 1 argument for function skew".to_string());
486 }
487 let s = Vector2::try_coerce(args.into_iter().next().unwrap())?;
488 Ok(Transform2::skew(s).to_pax_value())
489 }),
490 );
491 }
492}