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 if let Rule::settings_value = self.ast.as_rule() {
59 self.ast = self.ast.into_inner().next().unwrap();
60 }
61
62 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 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}