pax_lang/deserializer/
mod.rs

1use crate::{Parser, PaxParser, Rule};
2use helpers::PaxNumeric;
3use pax_runtime_api::PaxValue;
4use pest::iterators::Pair;
5use serde::de::{self, Visitor};
6use serde::{forward_to_deserialize_any, Deserialize};
7
8pub mod error;
9mod helpers;
10mod tests;
11
12use self::helpers::{ColorChannelInteger, PaxEnum, PaxObject, PaxSeq};
13
14pub use error::{Error, Result};
15
16use pax_runtime_api::constants::{
17    COLOR, DEGREES, INTEGER, NUMERIC, PERCENT, PIXELS, RADIANS, ROTATION, SIZE,
18};
19
20const STRING: &str = "String";
21const BOOL: &str = "Bool";
22const OPTION: &str = "Option";
23const VEC: &str = "Vec";
24const ENUM: &str = "Enum";
25const OBJECT: &str = "Object";
26
27pub fn from_pax(str: &str) -> Result<PaxValue> {
28    let ast = if let Ok(mut ast) = PaxParser::parse(Rule::literal_value, &str) {
29        ast.next().unwrap()
30    } else {
31        return Err(Error::Message(format!("Could not parse: {}", str)));
32    };
33    let deserializer: PaxDeserializer = PaxDeserializer::from(ast);
34    let t = PaxValue::deserialize(deserializer)?;
35    Ok(t)
36}
37
38pub fn from_pax_ast(ast: Pair<Rule>) -> Result<PaxValue> {
39    let deserializer: PaxDeserializer = PaxDeserializer::from(ast);
40    let t = PaxValue::deserialize(deserializer)?;
41    Ok(t)
42}
43
44pub struct PaxDeserializer<'de> {
45    pub ast: Pair<'de, Rule>,
46}
47
48impl<'de> PaxDeserializer<'de> {
49    pub fn from(ast: Pair<'de, Rule>) -> Self {
50        PaxDeserializer { ast }
51    }
52
53    fn deserialize_pax_value<V>(mut self, visitor: V) -> Result<V::Value>
54    where
55        V: Visitor<'de>,
56    {
57        // Flatten settings_value to internal typed rules
58        if let Rule::settings_value = self.ast.as_rule() {
59            self.ast = self.ast.into_inner().next().unwrap();
60        }
61
62        // Flatten literal_value to internal typed rules
63        if let Rule::literal_value = self.ast.as_rule() {
64            self.ast = self.ast.into_inner().next().unwrap();
65        }
66
67        match self.ast.as_rule() {
68            Rule::literal_color => {
69                visitor.visit_enum(PaxEnum::new_pax_value(COLOR, Some(self.ast)))
70            }
71            Rule::literal_number => {
72                visitor.visit_enum(PaxEnum::new_pax_value(NUMERIC, Some(self.ast)))
73            }
74            Rule::literal_number_with_unit => {
75                let unit = self
76                    .ast
77                    .clone()
78                    .into_inner()
79                    .nth(1)
80                    .unwrap()
81                    .as_str()
82                    .trim();
83                match unit {
84                    "%" => visitor.visit_enum(PaxEnum::new_pax_value(PERCENT, Some(self.ast))),
85                    "px" => visitor.visit_enum(PaxEnum::new_pax_value(SIZE, Some(self.ast))),
86                    "rad" => visitor.visit_enum(PaxEnum::new_pax_value(ROTATION, Some(self.ast))),
87                    "deg" => visitor.visit_enum(PaxEnum::new_pax_value(ROTATION, Some(self.ast))),
88                    _ => {
89                        unreachable!("Unsupported unit: {}", unit)
90                    }
91                }
92            }
93            Rule::string => visitor.visit_enum(PaxEnum::new_pax_value(STRING, Some(self.ast))),
94            Rule::literal_list | Rule::literal_tuple => {
95                visitor.visit_enum(PaxEnum::new_pax_value(VEC, Some(self.ast)))
96            }
97            Rule::literal_enum_value => {
98                visitor.visit_enum(PaxEnum::new_pax_value(ENUM, Some(self.ast)))
99            }
100            Rule::literal_option => {
101                visitor.visit_enum(PaxEnum::new_pax_value(OPTION, Some(self.ast)))
102            }
103            Rule::literal_boolean => visitor.visit_enum(PaxEnum::new(BOOL, Some(self.ast))),
104            Rule::literal_object => {
105                visitor.visit_enum(PaxEnum::new_pax_value(OBJECT, Some(self.ast)))
106            }
107            _ => Err(Error::UnsupportedType(format!(
108                "Rule : {:?}, raw_string: {}",
109                self.ast.as_rule(),
110                self.ast.as_str().to_string()
111            ))),
112        }
113    }
114
115    fn deserialize_builtin<V>(self, visitor: V) -> Result<V::Value>
116    where
117        V: Visitor<'de>,
118    {
119        let ret = match self.ast.as_rule() {
120            Rule::literal_color => {
121                // literal_color = {literal_color_space_func | literal_color_const}
122                let what_kind_of_color = self.ast.into_inner().next().unwrap();
123                match what_kind_of_color.as_rule() {
124                    Rule::literal_color_space_func => {
125                        let func = what_kind_of_color
126                            .as_str()
127                            .trim()
128                            .split("(")
129                            .next()
130                            .unwrap();
131
132                        let color_args = Some(what_kind_of_color);
133
134                        visitor.visit_enum(PaxEnum::new(func, color_args))
135                    }
136                    Rule::literal_color_const => {
137                        let explicit_color =
138                            visitor.visit_enum(PaxEnum::new(what_kind_of_color.as_str(), None));
139                        explicit_color
140                    }
141                    _ => {
142                        unreachable!()
143                    }
144                }
145            }
146            Rule::literal_color_channel => {
147                let channel = self.ast.into_inner().next().unwrap();
148                match channel.as_rule() {
149                    Rule::literal_number_integer => {
150                        visitor.visit_enum(ColorChannelInteger(channel.as_str().parse().unwrap()))
151                    }
152                    Rule::literal_number_with_unit => {
153                        let unit = channel.clone().into_inner().nth(1).unwrap().as_str().trim();
154                        let number = channel.clone().into_inner().next().unwrap();
155                        match unit {
156                            "%" => visitor.visit_enum(PaxEnum::new(PERCENT, Some(number))),
157                            "rad" => visitor.visit_enum(PaxEnum::new(ROTATION, Some(channel))),
158                            "deg" => visitor.visit_enum(PaxEnum::new(ROTATION, Some(channel))),
159                            _ => Err(Error::Message(format!(
160                                "Unsupported unit: {} for ColorChannel",
161                                unit
162                            ))),
163                        }
164                    }
165                    _ => Err(Error::Message(format!(
166                        "Unsupported type: {} for ColorChannel",
167                        channel.as_str()
168                    ))),
169                }
170            }
171            Rule::literal_number => {
172                let number = self.ast.into_inner().next().unwrap();
173                visitor.visit_enum(PaxNumeric::new(number, true))
174            }
175            Rule::literal_number_integer | Rule::literal_number_float => {
176                visitor.visit_enum(PaxNumeric::new(self.ast, true))
177            }
178            Rule::literal_number_with_unit => {
179                let inner = self.ast.into_inner();
180                let number = inner.clone().next();
181                let unit = inner.clone().nth(1).unwrap().as_str().trim();
182                match unit {
183                    "%" => visitor.visit_newtype_struct(PaxDeserializer::from(number.unwrap())),
184                    "px" => visitor.visit_enum(PaxEnum::new(PIXELS, number)),
185                    "rad" => visitor.visit_enum(PaxEnum::new(RADIANS, number)),
186                    "deg" => visitor.visit_enum(PaxEnum::new(DEGREES, number)),
187                    _ => Err(Error::Message(format!("Unsupported unit: {}", unit))),
188                }
189            }
190            Rule::string => {
191                let string_within_quotes =
192                    self.ast.into_inner().next().unwrap().as_str().to_string();
193                visitor.visit_string(string_within_quotes)
194            }
195            Rule::literal_boolean => {
196                let bool_str = self.ast.as_str();
197                visitor.visit_bool(bool_str.parse::<bool>().unwrap())
198            }
199            Rule::identifier | Rule::pascal_identifier => visitor.visit_str(self.ast.as_str()),
200            Rule::settings_key => visitor.visit_str(self.ast.into_inner().next().unwrap().as_str()),
201            _ => Err(Error::UnsupportedType(self.ast.as_str().to_string())),
202        }?;
203
204        Ok(ret)
205    }
206}
207
208impl<'de> de::Deserializer<'de> for PaxDeserializer<'de> {
209    type Error = Error;
210
211    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
212    where
213        V: Visitor<'de>,
214    {
215        self.deserialize_builtin(visitor)
216    }
217
218    forward_to_deserialize_any! {
219        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
220        bytes byte_buf unit unit_struct newtype_struct identifier
221        tuple_struct struct ignored_any
222    }
223
224    fn deserialize_enum<V>(
225        self,
226        name: &'static str,
227        _variants: &'static [&'static str],
228        visitor: V,
229    ) -> std::result::Result<V::Value, Self::Error>
230    where
231        V: Visitor<'de>,
232    {
233        if name == "PaxValue" {
234            return self.deserialize_pax_value(visitor);
235        }
236        self.deserialize_any(visitor)
237    }
238
239    fn deserialize_seq<V>(self, visitor: V) -> std::result::Result<V::Value, Self::Error>
240    where
241        V: Visitor<'de>,
242    {
243        let rule = self.ast.as_rule();
244        if rule == Rule::literal_object {
245            visitor.visit_seq(PaxObject::new(self.ast.into_inner()))
246        } else {
247            visitor.visit_seq(PaxSeq::new(self.ast.into_inner()))
248        }
249    }
250
251    fn deserialize_option<V>(self, visitor: V) -> std::result::Result<V::Value, Self::Error>
252    where
253        V: Visitor<'de>,
254    {
255        let unwrapped_option = self.ast.into_inner().next().unwrap();
256        match unwrapped_option.as_rule() {
257            Rule::literal_none => visitor.visit_none(),
258            Rule::literal_some => visitor.visit_some(PaxDeserializer::from(
259                unwrapped_option.into_inner().next().unwrap(),
260            )),
261            _ => Err(Error::Message(format!(
262                "Unexpected format for Option: {}",
263                unwrapped_option.as_str()
264            ))),
265        }
266    }
267
268    fn deserialize_map<V>(self, visitor: V) -> std::result::Result<V::Value, Self::Error>
269    where
270        V: Visitor<'de>,
271    {
272        visitor.visit_map(PaxObject::new(self.ast.into_inner()))
273    }
274
275    fn deserialize_tuple<V>(
276        self,
277        len: usize,
278        visitor: V,
279    ) -> std::result::Result<V::Value, Self::Error>
280    where
281        V: Visitor<'de>,
282    {
283        visitor.visit_seq(PaxSeq::new(self.ast.into_inner()))
284    }
285}