anathema_value_resolver/functions/
mod.rs1use std::collections::HashMap;
2use std::fmt::{Debug, Display};
3
4use crate::ValueKind;
5
6mod list;
7mod number;
8mod string;
9
10#[derive(Debug)]
11pub enum Error {
12 FunctionAlreadyRegistered(String),
13}
14
15impl Display for Error {
16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17 match self {
18 Error::FunctionAlreadyRegistered(name) => write!(f, "function `{name}` is already registered"),
19 }
20 }
21}
22
23impl std::error::Error for Error {}
24
25pub struct Function {
26 inner: Box<dyn for<'bp> Fn(&[ValueKind<'bp>]) -> ValueKind<'bp>>,
27}
28
29impl Function {
30 pub(crate) fn invoke<'bp>(&self, args: &[ValueKind<'bp>]) -> ValueKind<'bp> {
31 (self.inner)(args)
32 }
33}
34
35impl Debug for Function {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 write!(f, "<fun>")
38 }
39}
40
41impl<T> From<T> for Function
42where
43 T: 'static,
44 T: for<'bp> Fn(&[ValueKind<'bp>]) -> ValueKind<'bp>,
45{
46 fn from(value: T) -> Self {
47 Self { inner: Box::new(value) }
48 }
49}
50
51pub struct FunctionTable {
52 inner: HashMap<String, Function>,
53}
54
55impl FunctionTable {
56 pub fn new() -> Self {
57 let mut inner = HashMap::new();
58 inner.insert("to_upper".into(), Function::from(string::to_upper));
59 inner.insert("to_lower".into(), Function::from(string::to_lower));
60 inner.insert("truncate".into(), Function::from(string::truncate));
61 inner.insert("to_str".into(), Function::from(string::to_str));
62 inner.insert("pad".into(), Function::from(string::pad));
63 inner.insert("width".into(), Function::from(string::width));
64 inner.insert("to_int".into(), Function::from(number::to_int));
65 inner.insert("to_float".into(), Function::from(number::to_float));
66 inner.insert("round".into(), Function::from(number::round));
67 inner.insert("contains".into(), Function::from(list::contains));
68 Self { inner }
69 }
70
71 pub fn insert(&mut self, ident: impl Into<String>, f: impl Into<Function>) -> Result<(), Error> {
72 let key = ident.into();
73 if self.inner.contains_key(&key) {
74 return Err(Error::FunctionAlreadyRegistered(key));
75 }
76 self.inner.insert(key, f.into());
77 Ok(())
78 }
79
80 pub fn lookup(&self, ident: &str) -> Option<&Function> {
81 self.inner.get(ident)
82 }
83}
84
85#[cfg(test)]
86mod test {
87 use crate::ValueKind;
88
89 pub(crate) fn list<T, U>(items: T) -> ValueKind<'static>
90 where
91 U: Into<ValueKind<'static>>,
92 T: IntoIterator<Item = U>,
93 {
94 let inner = items.into_iter().map(Into::into).collect::<Box<[ValueKind<'_>]>>();
95
96 ValueKind::List(inner)
97 }
98
99 pub(crate) fn value<T>(val: T) -> ValueKind<'static>
100 where
101 T: Into<ValueKind<'static>>,
102 {
103 val.into()
104 }
105}