1use std::cmp::Ordering;
3use std::fmt::Write;
4
5use gtmpl_value::{Func, FuncError, Value};
6use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
7
8use crate::printf::sprintf;
9use crate::utils::is_true;
10
11const QUERY_ENCODE: &AsciiSet = &CONTROLS
12 .add(b' ')
13 .add(b'"')
14 .add(b'<')
15 .add(b'>')
16 .add(b'#')
17 .add(b'`')
18 .add(b'`')
19 .add(b'?')
20 .add(b'{')
21 .add(b'}');
22
23pub static BUILTINS: &[(&str, Func)] = &[
24 ("eq", eq as Func),
25 ("ne", ne as Func),
26 ("lt", lt as Func),
27 ("le", le as Func),
28 ("gt", gt as Func),
29 ("ge", ge as Func),
30 ("len", len as Func),
31 ("and", and as Func),
32 ("or", or as Func),
33 ("not", not as Func),
34 ("urlquery", urlquery as Func),
35 ("print", print as Func),
36 ("println", println as Func),
37 ("printf", printf as Func),
38 ("index", index as Func),
39 ("call", call as Func),
40];
41
42macro_rules! val {
43 ($x:expr) => {
44 Value::from($x)
45 };
46}
47
48#[macro_export]
50macro_rules! gtmpl_fn {
51 (
52 $(#[$outer:meta])*
53 fn $name:ident() -> Result<$otyp:ty, FuncError>
54 { $($body:tt)* }
55 ) => {
56 $(#[$outer])*
57 pub fn $name(args: &[$crate::Value]) -> Result<$crate::Value, FuncError> {
58 fn inner() -> Result<$otyp, FuncError> {
59 $($body)*
60 }
61 Ok($crate::Value::from(inner()?))
62 }
63 };
64 (
65 $(#[$outer:meta])*
66 fn $name:ident($arg0:ident : $typ0:ty) -> Result<$otyp:ty, FuncError>
67 { $($body:tt)* }
68 ) => {
69 $(#[$outer])*
70 pub fn $name(
71 args: &[$crate::Value]
72 ) -> Result<$crate::Value, FuncError> {
73 if args.is_empty() {
74 return Err(FuncError::AtLeastXArgs(stringify!($name).into(), 1));
75 }
76 let x = &args[0];
77 let $arg0: $typ0 = $crate::from_value(x)
78 .ok_or(FuncError::UnableToConvertFromValue)?;
79 fn inner($arg0 : $typ0) -> Result<$otyp, FuncError> {
80 $($body)*
81 }
82 let ret: $crate::Value = inner($arg0)?.into();
83 Ok(ret)
84 }
85 };
86 (
87 $(#[$outer:meta])*
88 fn $name:ident($arg0:ident : $typ0:ty$(, $arg:ident : $typ:ty)*) -> Result<$otyp:ty, FuncError>
89 { $($body:tt)* }
90 ) => {
91 $(#[$outer])*
92 pub fn $name(
93 args: &[$crate::Value]
94 ) -> Result<$crate::Value, FuncError> {
95 #[allow(unused_mut)]
96 let mut args = args;
97 if args.is_empty() {
98 return Err(FuncError::AtLeastXArgs(stringify!($name).into(), 1));
99 }
100 let x = &args[0];
101 let $arg0: $typ0 = $crate::from_value(x)
102 .ok_or(FuncError::UnableToConvertFromValue)?;
103 $(args = &args[1..];
104 let x = &args[0];
105 let $arg: $typ = $crate::from_value(x)
106 .ok_or(FuncError::UnableToConvertFromValue)?;)*
107 fn inner($arg0 : $typ0, $($arg : $typ,)*) -> Result<$otyp, FuncError> {
108 $($body)*
109 }
110 let ret: $crate::Value = inner($arg0, $($arg),*)?.into();
111 Ok(ret)
112 }
113 }
114}
115
116macro_rules! gn {
117 (
118 $(#[$outer:meta])*
119 $name:ident($arg1:ident : ref Value, $arg2:ident : ref Value) ->
120 Result<Value, FuncError>
121 { $($body:tt)* }
122 ) => {
123 $(#[$outer])*
124 pub fn $name(args: &[Value]) -> Result<Value, FuncError> {
125 if args.len() != 2 {
126 return Err(FuncError::AtLeastXArgs(stringify!($name).into(), 2));
127 }
128 let $arg1 = &args[0];
129 let $arg2 = &args[1];
130 fn inner($arg1: &Value, $arg2: &Value) -> Result<Value, FuncError> {
131 $($body)*
132 }
133 inner($arg1, $arg2)
134 }
135 }
136}
137
138pub fn or(args: &[Value]) -> Result<Value, FuncError> {
150 for arg in args {
151 if is_true(arg) {
152 return Ok(arg.clone());
153 }
154 }
155 args.iter()
156 .cloned()
157 .last()
158 .ok_or_else(|| FuncError::AtLeastXArgs("or".into(), 1))
159}
160
161pub fn and(args: &[Value]) -> Result<Value, FuncError> {
173 for arg in args {
174 if !is_true(arg) {
175 return Ok(arg.clone());
176 }
177 }
178 args.iter()
179 .cloned()
180 .last()
181 .ok_or_else(|| FuncError::AtLeastXArgs("and".into(), 1))
182}
183
184pub fn not(args: &[Value]) -> Result<Value, FuncError> {
193 if args.len() != 1 {
194 Err(FuncError::ExactlyXArgs("not".into(), 1))
195 } else {
196 Ok(val!(!is_true(&args[0])))
197 }
198}
199
200pub fn len(args: &[Value]) -> Result<Value, FuncError> {
209 if args.len() != 1 {
210 return Err(FuncError::ExactlyXArgs("len".into(), 1));
211 }
212 let arg = &args[0];
213 let len = match *arg {
214 Value::String(ref s) => s.len(),
215 Value::Array(ref a) => a.len(),
216 Value::Object(ref o) => o.len(),
217 _ => {
218 return Err(FuncError::Generic(format!("unable to call len on {}", arg)));
219 }
220 };
221
222 Ok(val!(len))
223}
224
225pub fn call(args: &[Value]) -> Result<Value, FuncError> {
241 if args.is_empty() {
242 Err(FuncError::AtLeastXArgs("call".into(), 1))
243 } else if let Value::Function(ref f) = args[0] {
244 (f.f)(&args[1..])
245 } else {
246 Err(FuncError::Generic(
247 "call requires the first argument to be a function".into(),
248 ))
249 }
250}
251
252pub fn print(args: &[Value]) -> Result<Value, FuncError> {
264 let mut no_space = true;
265 let mut s = String::new();
266 for val in args {
267 if let Value::String(ref v) = *val {
268 no_space = true;
269 s.push_str(v);
270 } else {
271 if no_space {
272 s += &val.to_string();
273 } else {
274 s += &format!(" {}", val.to_string())
275 }
276 no_space = false;
277 }
278 }
279 Ok(val!(s))
280}
281
282pub fn println(args: &[Value]) -> Result<Value, FuncError> {
294 let mut iter = args.iter();
295 let s = match iter.next() {
296 None => String::from("\n"),
297 Some(first_elt) => {
298 let (lower, _) = iter.size_hint();
299 let mut result = String::with_capacity(lower + 1);
300 if let Value::String(ref v) = *first_elt {
301 result.push_str(v);
302 } else {
303 write!(&mut result, "{}", first_elt).unwrap();
304 }
305 for elt in iter {
306 result.push(' ');
307 if let Value::String(ref v) = *elt {
308 result.push_str(v);
309 } else {
310 write!(&mut result, "{}", elt).unwrap();
311 }
312 }
313 result.push('\n');
314 result
315 }
316 };
317 Ok(val!(s))
318}
319
320pub fn printf(args: &[Value]) -> Result<Value, FuncError> {
333 if args.is_empty() {
334 return Err(FuncError::AtLeastXArgs("printf".into(), 1));
335 }
336 if let Value::String(ref s) = args[0] {
337 let s = sprintf(s, &args[1..]).map_err(|e| FuncError::Other(e.into()))?;
338 Ok(val!(s))
339 } else {
340 Err(FuncError::Generic("printf requires a format string".into()))
341 }
342}
343
344pub fn index(args: &[Value]) -> Result<Value, FuncError> {
356 if args.len() < 2 {
357 return Err(FuncError::AtLeastXArgs("index".into(), 2));
358 }
359 let mut col = &args[0];
360 for val in &args[1..] {
361 col = get_item(col, val)?;
362 }
363
364 Ok(col.clone())
365}
366
367fn get_item<'a>(col: &'a Value, key: &Value) -> Result<&'a Value, FuncError> {
368 let ret = match (col, key) {
369 (&Value::Array(ref a), &Value::Number(ref n)) => {
370 if let Some(i) = n.as_u64() {
371 a.get(i as usize)
372 } else {
373 None
374 }
375 }
376 (&Value::Object(ref o), &Value::Number(ref n))
377 | (&Value::Map(ref o), &Value::Number(ref n)) => o.get(&n.to_string()),
378 (&Value::Object(ref o), &Value::String(ref s))
379 | (&Value::Map(ref o), &Value::String(ref s)) => o.get(s),
380 _ => None,
381 };
382 match *col {
383 Value::Map(_) => Ok(ret.unwrap_or(&Value::NoValue)),
384 _ => ret.ok_or_else(|| FuncError::Generic(format!("unable to get {} in {}", key, col))),
385 }
386}
387
388pub fn urlquery(args: &[Value]) -> Result<Value, FuncError> {
398 if args.len() != 1 {
399 return Err(FuncError::ExactlyXArgs("urlquery".into(), 1));
400 }
401 let val = &args[0];
402 match *val {
403 Value::String(ref s) => Ok(val!(utf8_percent_encode(s, QUERY_ENCODE).to_string())),
404 _ => Err(FuncError::Generic(
405 "Arguments need to be of type String".into(),
406 )),
407 }
408}
409
410pub fn eq(args: &[Value]) -> Result<Value, FuncError> {
419 if args.len() < 2 {
420 return Err(FuncError::AtLeastXArgs("eq".into(), 2));
421 }
422 let first = &args[0];
423 Ok(Value::from(args.iter().skip(1).all(|x| *x == *first)))
424}
425
426gn!(
427#[doc="
428Returns the boolean truth of arg1 != arg2
429
430# Example
431```
432use gtmpl::template;
433let not_equal = template(\"{{ ne 2 . }}\", 1);
434assert_eq!(¬_equal.unwrap(), \"true\");
435```
436"]
437ne(a: ref Value, b: ref Value) -> Result<Value, FuncError> {
438 Ok(Value::from(a != b))
439});
440
441gn!(
442#[doc="
443Returns the boolean truth of arg1 < arg2
444
445# Example
446```
447use gtmpl::template;
448let less_than = template(\"{{ lt 0 . }}\", 1);
449assert_eq!(&less_than.unwrap(), \"true\");
450```
451"]
452lt(a: ref Value, b: ref Value) -> Result<Value, FuncError> {
453 let ret = match cmp(a, b) {
454 None => return Err(FuncError::Generic(format!("unable to compare {} and {}", a, b))),
455 Some(Ordering::Less) => true,
456 _ => false,
457 };
458 Ok(Value::from(ret))
459});
460
461gn!(
462#[doc="
463Returns the boolean truth of arg1 <= arg2
464
465# Example
466```
467use gtmpl::template;
468let less_or_equal = template(\"{{ le 1.4 . }}\", 1.4);
469assert_eq!(less_or_equal.unwrap(), \"true\");
470
471let less_or_equal = template(\"{{ le 0.2 . }}\", 1.4);
472assert_eq!(&less_or_equal.unwrap(), \"true\");
473```
474"]
475le(a: ref Value, b: ref Value) -> Result<Value, FuncError> {
476 let ret = match cmp(a, b) {
477 None => return Err(FuncError::Generic(format!("unable to compare {} and {}", a, b))),
478 Some(Ordering::Less) | Some(Ordering::Equal) => true,
479 _ => false,
480 };
481 Ok(Value::from(ret))
482});
483
484gn!(
485#[doc="
486Returns the boolean truth of arg1 > arg2
487
488# Example
489```
490use gtmpl::template;
491let greater_than = template(\"{{ gt 1.4 . }}\", 1.2);
492assert_eq!(&greater_than.unwrap(), \"true\");
493```
494"]
495gt(a: ref Value, b: ref Value) -> Result<Value, FuncError> {
496 let ret = match cmp(a, b) {
497 None => return Err(FuncError::Generic(format!("unable to compare {} and {}", a, b))),
498 Some(Ordering::Greater) => true,
499 _ => false,
500 };
501 Ok(Value::from(ret))
502});
503
504gn!(
505#[doc="
506Returns the boolean truth of arg1 >= arg2
507
508# Example
509```
510use gtmpl::template;
511let greater_or_equal = template(\"{{ ge 1.4 1.3 }}\", 1.2);
512assert_eq!(greater_or_equal.unwrap(), \"true\");
513
514let greater_or_equal = template(\"{{ ge 1.4 . }}\", 0.2);
515assert_eq!(&greater_or_equal.unwrap(), \"true\");
516```
517"]
518ge(a: ref Value, b: ref Value) -> Result<Value, FuncError> {
519 let ret = match cmp(a, b) {
520 None => return Err(FuncError::Generic(format!("unable to compare {} and {}", a, b))),
521 Some(Ordering::Greater) | Some(Ordering::Equal) => true,
522 _ => false,
523 };
524 Ok(Value::from(ret))
525});
526
527fn cmp(left: &Value, right: &Value) -> Option<Ordering> {
528 match (left, right) {
529 (&Value::Number(ref l), &Value::Number(ref r)) => {
530 if let (Some(lf), Some(rf)) = (l.as_f64(), r.as_f64()) {
531 return lf.partial_cmp(&rf);
532 }
533 if let (Some(li), Some(ri)) = (l.as_i64(), r.as_i64()) {
534 return li.partial_cmp(&ri);
535 }
536 if let (Some(lu), Some(ru)) = (l.as_u64(), r.as_u64()) {
537 return lu.partial_cmp(&ru);
538 }
539 None
540 }
541 (&Value::Bool(ref l), &Value::Bool(ref r)) => l.partial_cmp(r),
542 (&Value::String(ref l), &Value::String(ref r)) => l.partial_cmp(r),
543 (&Value::Array(ref l), &Value::Array(ref r)) => l.len().partial_cmp(&r.len()),
544 _ => None,
545 }
546}
547
548#[cfg(test)]
549mod tests_mocked {
550 use super::*;
551 use std::collections::HashMap;
552
553 #[test]
554 fn test_macro() {
555 gtmpl_fn!(
556 fn f1(i: i64) -> Result<i64, FuncError> {
557 Ok(i + 1)
558 }
559 );
560 let vals: Vec<Value> = vec![val!(1i64)];
561 let ret = f1(&vals);
562 assert_eq!(ret.unwrap(), Value::from(2i64));
563
564 gtmpl_fn!(
565 fn f3(i: i64, j: i64, k: i64) -> Result<i64, FuncError> {
566 Ok(i + j + k)
567 }
568 );
569 let vals: Vec<Value> = vec![val!(1i64), val!(2i64), val!(3i64)];
570 let ret = f3(&vals);
571 assert_eq!(ret.unwrap(), Value::from(6i64));
572 }
573
574 #[test]
575 fn test_eq() {
576 let vals: Vec<Value> = vec![val!("foo".to_owned()), val!("foo".to_owned())];
577 let ret = eq(&vals);
578 assert_eq!(ret.unwrap(), Value::Bool(true));
579 let vals: Vec<Value> = vec![val!(1u32), val!(1u32), val!(1i8)];
580 let ret = eq(&vals);
581 assert_eq!(ret.unwrap(), Value::Bool(true));
582 let vals: Vec<Value> = vec![val!(false), val!(false), val!(false)];
583 let ret = eq(&vals);
584 assert_eq!(ret.unwrap(), Value::Bool(true));
585 }
586
587 #[test]
588 fn test_and() {
589 let vals: Vec<Value> = vec![val!(0i32), val!(1u8)];
590 let ret = and(&vals);
591 assert_eq!(ret.unwrap(), Value::from(0i32));
592
593 let vals: Vec<Value> = vec![val!(1i32), val!(2u8)];
594 let ret = and(&vals);
595 assert_eq!(ret.unwrap(), Value::from(2u8));
596 }
597
598 #[test]
599 fn test_or() {
600 let vals: Vec<Value> = vec![val!(0i32), val!(1u8)];
601 let ret = or(&vals);
602 assert_eq!(ret.unwrap(), Value::from(1u8));
603
604 let vals: Vec<Value> = vec![val!(0i32), val!(0u8)];
605 let ret = or(&vals);
606 assert_eq!(ret.unwrap(), Value::from(0u8));
607 }
608
609 #[test]
610 fn test_ne() {
611 let vals: Vec<Value> = vec![val!(0i32), val!(1u8)];
612 let ret = ne(&vals);
613 assert_eq!(ret.unwrap(), Value::from(true));
614
615 let vals: Vec<Value> = vec![val!(0i32), val!(0u8)];
616 let ret = ne(&vals);
617 assert_eq!(ret.unwrap(), Value::from(false));
618
619 let vals: Vec<Value> = vec![val!("foo"), val!("bar")];
620 let ret = ne(&vals);
621 assert_eq!(ret.unwrap(), Value::from(true));
622
623 let vals: Vec<Value> = vec![val!("foo"), val!("foo")];
624 let ret = ne(&vals);
625 assert_eq!(ret.unwrap(), Value::from(false));
626 }
627
628 #[test]
629 fn test_lt() {
630 let vals: Vec<Value> = vec![val!(-1i32), val!(1u8)];
631 let ret = lt(&vals);
632 assert_eq!(ret.unwrap(), Value::from(true));
633
634 let vals: Vec<Value> = vec![val!(0i32), val!(0u8)];
635 let ret = lt(&vals);
636 assert_eq!(ret.unwrap(), Value::from(false));
637
638 let vals: Vec<Value> = vec![val!(1i32), val!(0u8)];
639 let ret = lt(&vals);
640 assert_eq!(ret.unwrap(), Value::from(false));
641 }
642
643 #[test]
644 fn test_le() {
645 let vals: Vec<Value> = vec![val!(-1i32), val!(1u8)];
646 let ret = le(&vals);
647 assert_eq!(ret.unwrap(), Value::from(true));
648
649 let vals: Vec<Value> = vec![val!(0i32), val!(0u8)];
650 let ret = le(&vals);
651 assert_eq!(ret.unwrap(), Value::from(true));
652
653 let vals: Vec<Value> = vec![val!(1i32), val!(0u8)];
654 let ret = le(&vals);
655 assert_eq!(ret.unwrap(), Value::from(false));
656 }
657
658 #[test]
659 fn test_gt() {
660 let vals: Vec<Value> = vec![val!(-1i32), val!(1u8)];
661 let ret = gt(&vals);
662 assert_eq!(ret.unwrap(), Value::from(false));
663
664 let vals: Vec<Value> = vec![val!(0i32), val!(0u8)];
665 let ret = gt(&vals);
666 assert_eq!(ret.unwrap(), Value::from(false));
667
668 let vals: Vec<Value> = vec![val!(1i32), val!(0u8)];
669 let ret = gt(&vals);
670 assert_eq!(ret.unwrap(), Value::from(true));
671 }
672
673 #[test]
674 fn test_ge() {
675 let vals: Vec<Value> = vec![val!(-1i32), val!(1u8)];
676 let ret = ge(&vals);
677 assert_eq!(ret.unwrap(), Value::from(false));
678
679 let vals: Vec<Value> = vec![val!(0i32), val!(0u8)];
680 let ret = ge(&vals);
681 assert_eq!(ret.unwrap(), Value::from(true));
682
683 let vals: Vec<Value> = vec![val!(1i32), val!(0u8)];
684 let ret = ge(&vals);
685 assert_eq!(ret.unwrap(), Value::from(true));
686 }
687
688 #[test]
689 fn test_print() {
690 let vals: Vec<Value> = vec![val!("foo"), val!(1u8)];
691 let ret = print(&vals);
692 assert_eq!(ret.unwrap(), Value::from("foo1"));
693
694 let vals: Vec<Value> = vec![val!("foo"), val!(1u8), val!(2)];
695 let ret = print(&vals);
696 assert_eq!(ret.unwrap(), Value::from("foo1 2"));
697
698 let vals: Vec<Value> = vec![val!(true), val!(1), val!("foo"), val!(2)];
699 let ret = print(&vals);
700 assert_eq!(ret.unwrap(), Value::from("true 1foo2"));
701 }
702
703 #[test]
704 fn test_println() {
705 let vals: Vec<Value> = vec![val!("foo"), val!(1u8)];
706 let ret = println(&vals);
707 assert_eq!(ret.unwrap(), Value::from("foo 1\n"));
708
709 let vals: Vec<Value> = vec![];
710 let ret = println(&vals);
711 assert_eq!(ret.unwrap(), Value::from("\n"));
712 }
713
714 #[test]
715 fn test_index() {
716 let vals: Vec<Value> = vec![val!(vec![vec![1, 2], vec![3, 4]]), val!(1), val!(0)];
717 let ret = index(&vals);
718 assert_eq!(ret.unwrap(), Value::from(3));
719
720 let mut o = HashMap::new();
721 o.insert(String::from("foo"), vec![String::from("bar")]);
722 let col = Value::from(o);
723 let vals: Vec<Value> = vec![col, val!("foo"), val!(0)];
724 let ret = index(&vals);
725 assert_eq!(ret.unwrap(), Value::from("bar"));
726
727 let mut o = HashMap::new();
728 o.insert(String::from("foo"), String::from("bar"));
729 let col = Value::from(o);
730 let vals: Vec<Value> = vec![col, val!("foo2")];
731 let ret = index(&vals);
732 assert_eq!(ret.unwrap(), Value::NoValue);
733 }
734
735 #[test]
736 fn test_builtins() {
737 let vals: Vec<Value> = vec![val!("foo".to_owned()), val!("foo".to_owned())];
738 let builtin_eq = BUILTINS
739 .iter()
740 .find(|&&(n, _)| n == "eq")
741 .map(|&(_, f)| f)
742 .unwrap();
743 let ret = builtin_eq(&vals);
744 assert_eq!(ret.unwrap(), Value::Bool(true));
745 }
746
747 #[test]
748 fn test_gtmpl_fn() {
749 gtmpl_fn!(
750 fn add(a: u64, b: u64) -> Result<u64, FuncError> {
751 Ok(a + b)
752 }
753 );
754 let vals: Vec<Value> = vec![val!(1u32), val!(2u32)];
755 let ret = add(&vals);
756 assert_eq!(ret.unwrap(), Value::from(3u32));
757
758 gtmpl_fn!(
759 fn has_prefix(s: String, prefix: String) -> Result<bool, FuncError> {
760 Ok(s.starts_with(&prefix))
761 }
762 );
763 let vals: Vec<Value> = vec![val!("foobar"), val!("foo")];
764 let ret = has_prefix(&vals);
765 assert_eq!(ret.unwrap(), Value::from(true));
766 }
767}