zen_expression/functions/
arguments.rs

1use crate::variable::DynamicVariable;
2use crate::Variable;
3use ahash::HashMap;
4use anyhow::Context;
5use rust_decimal::Decimal;
6use std::cell::RefCell;
7use std::ops::Deref;
8use std::rc::Rc;
9
10pub struct Arguments<'a>(pub &'a [Variable]);
11
12type RcCell<T> = Rc<RefCell<T>>;
13
14impl<'a> Deref for Arguments<'a> {
15    type Target = [Variable];
16
17    fn deref(&self) -> &'a Self::Target {
18        &self.0
19    }
20}
21
22impl<'a> Arguments<'a> {
23    pub fn ovar(&self, pos: usize) -> Option<&'a Variable> {
24        self.0.get(pos)
25    }
26
27    pub fn var(&self, pos: usize) -> anyhow::Result<&'a Variable> {
28        self.ovar(pos)
29            .with_context(|| format!("Argument on {pos} position out of bounds"))
30    }
31
32    pub fn obool(&self, pos: usize) -> anyhow::Result<Option<bool>> {
33        match self.ovar(pos) {
34            Some(v) => v
35                .as_bool()
36                .map(Some)
37                .with_context(|| format!("Argument on {pos} is not a bool")),
38            None => Ok(None),
39        }
40    }
41
42    pub fn bool(&self, pos: usize) -> anyhow::Result<bool> {
43        self.obool(pos)?
44            .with_context(|| format!("Argument on {pos} position is not a valid bool"))
45    }
46
47    pub fn ostr(&self, pos: usize) -> anyhow::Result<Option<&'a str>> {
48        match self.ovar(pos) {
49            Some(v) => v
50                .as_str()
51                .map(Some)
52                .with_context(|| format!("Argument on {pos} is not a string")),
53            None => Ok(None),
54        }
55    }
56
57    pub fn str(&self, pos: usize) -> anyhow::Result<&'a str> {
58        self.ostr(pos)?
59            .with_context(|| format!("Argument on {pos} position is not a valid string"))
60    }
61
62    pub fn onumber(&self, pos: usize) -> anyhow::Result<Option<Decimal>> {
63        match self.ovar(pos) {
64            Some(v) => v
65                .as_number()
66                .map(Some)
67                .with_context(|| format!("Argument on {pos} is not a number")),
68            None => Ok(None),
69        }
70    }
71
72    pub fn number(&self, pos: usize) -> anyhow::Result<Decimal> {
73        self.onumber(pos)?
74            .with_context(|| format!("Argument on {pos} position is not a valid number"))
75    }
76
77    pub fn oarray(&self, pos: usize) -> anyhow::Result<Option<RcCell<Vec<Variable>>>> {
78        match self.ovar(pos) {
79            Some(v) => v
80                .as_array()
81                .map(Some)
82                .with_context(|| format!("Argument on {pos} is not a array")),
83            None => Ok(None),
84        }
85    }
86
87    pub fn array(&self, pos: usize) -> anyhow::Result<RcCell<Vec<Variable>>> {
88        self.oarray(pos)?
89            .with_context(|| format!("Argument on {pos} position is not a valid array"))
90    }
91
92    pub fn oobject(
93        &self,
94        pos: usize,
95    ) -> anyhow::Result<Option<RcCell<HashMap<Rc<str>, Variable>>>> {
96        match self.ovar(pos) {
97            Some(v) => v
98                .as_object()
99                .map(Some)
100                .with_context(|| format!("Argument on {pos} is not a object")),
101            None => Ok(None),
102        }
103    }
104
105    pub fn object(&self, pos: usize) -> anyhow::Result<RcCell<HashMap<Rc<str>, Variable>>> {
106        self.oobject(pos)?
107            .with_context(|| format!("Argument on {pos} position is not a valid object"))
108    }
109
110    pub fn odynamic<T: DynamicVariable + 'static>(&self, pos: usize) -> anyhow::Result<Option<&T>> {
111        match self.ovar(pos) {
112            None => Ok(None),
113            Some(s) => Ok(s.dynamic::<T>()),
114        }
115    }
116
117    pub fn dynamic<T: DynamicVariable + 'static>(&self, pos: usize) -> anyhow::Result<&T> {
118        self.odynamic(pos)?
119            .with_context(|| format!("Argument on {pos} position is not a valid dynamic"))
120    }
121}