1use crate::Deserialize;
24use tanzim_value::{Error, LocatedValue};
25
26pub type BoxedParseFn = Box<dyn Fn(&str, &str, &[u8]) -> Result<LocatedValue, Error>>;
27pub type BoxedValidatorFn = Box<dyn Fn(&[u8]) -> Option<bool>>;
28
29pub struct Closure {
30 name: String,
31 parser: BoxedParseFn,
32 validator: BoxedValidatorFn,
33 supported_format_list: Vec<String>,
34}
35
36impl Closure {
37 pub fn new<N: AsRef<str>, F: AsRef<str>>(
38 name: N,
39 supported_format: F,
40 parser: BoxedParseFn,
41 ) -> Self {
42 Self {
43 name: name.as_ref().to_string(),
44 parser,
45 validator: Box::new(|_| None),
46 supported_format_list: vec![supported_format.as_ref().to_string()],
47 }
48 }
49
50 pub fn with_validator(mut self, validator: BoxedValidatorFn) -> Self {
51 self.validator = validator;
52 self
53 }
54
55 pub fn with_format_list<N: AsRef<str>>(mut self, format_list: &[N]) -> Self {
56 let mut formats = Vec::new();
57 for format in format_list {
58 formats.push(format.as_ref().to_string());
59 }
60 self.supported_format_list = formats;
61 self
62 }
63}
64
65impl Deserialize for Closure {
66 fn name(&self) -> &str {
67 self.name.as_str()
68 }
69
70 fn supported_format_list(&self) -> Vec<String> {
71 self.supported_format_list.clone()
72 }
73
74 fn parse(&self, source: &str, resource: &str, bytes: &[u8]) -> Result<LocatedValue, Error> {
75 (self.parser)(source, resource, bytes)
76 }
77
78 fn is_format_supported(&self, bytes: &[u8]) -> Option<bool> {
79 (self.validator)(bytes)
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86 use tanzim_value::{Location, Value};
87
88 #[test]
89 fn closure_parser_delegates_to_function() {
90 let parser = Closure::new(
91 "upper",
92 "txt",
93 Box::new(|source, resource, bytes| {
94 Ok(LocatedValue {
95 value: Value::String(String::from_utf8_lossy(bytes).to_uppercase()),
96 location: Location::at(source, resource, None, None, None),
97 })
98 }),
99 )
100 .with_validator(Box::new(|bytes| Some(!bytes.is_empty())));
101 let parsed = parser.parse("file", "test.txt", b"hello").unwrap();
102 assert_eq!(parsed.value.as_string().unwrap(), "HELLO");
103 assert_eq!(parser.is_format_supported(b"x"), Some(true));
104 assert_eq!(parser.is_format_supported(b""), Some(false));
105 }
106}