1use crate::{Color, Duration, Interpolatable, PathElement, Percent, Rotation, Size};
2use std::{any::Any, fmt::Display, rc::Rc};
3
4use self::numeric::Numeric;
5pub use coercion_impls::{is_typed_binding_safe, CoercionRules};
6use serde::{Deserialize, Serialize};
7
8mod arithmetic;
9mod coercion_impls;
10pub mod functions;
11mod macros;
12pub mod numeric;
13mod to_from_impls;
14
15pub type RcPaxValue = Rc<PaxValue>;
17#[derive(Debug, Serialize, Deserialize, PartialEq)]
25#[serde(crate = "crate::serde")]
26pub enum PaxValue {
27 Bool(bool),
29 Numeric(Numeric),
31 String(String),
33 Size(Size),
35 Percent(Percent),
37 Color(Box<Color>),
39 Rotation(Rotation),
41 Duration(Duration),
43 PathElement(Box<PathElement>),
45 Option(Box<Option<PaxValue>>),
47 Vec(Vec<PaxValue>),
49 Range(Box<PaxValue>, Box<PaxValue>),
51 Object(Vec<(String, PaxValue)>),
53 Enum(Box<(String, String, Vec<PaxValue>)>),
55}
56
57impl Clone for PaxValue {
58 fn clone(&self) -> Self {
59 match self {
60 PaxValue::Bool(b) => PaxValue::Bool(*b),
61 PaxValue::Numeric(n) => PaxValue::Numeric(n.clone()),
62 PaxValue::String(s) => PaxValue::String(s.clone()),
63 PaxValue::Size(s) => PaxValue::Size(s.clone()),
64 PaxValue::Percent(p) => PaxValue::Percent(p.clone()),
65 PaxValue::Color(c) => PaxValue::Color(c.clone()),
66 PaxValue::Rotation(r) => PaxValue::Rotation(r.clone()),
67 PaxValue::Duration(d) => PaxValue::Duration(d.clone()),
68 PaxValue::PathElement(pe) => PaxValue::PathElement(pe.clone()),
69 PaxValue::Option(opt) => PaxValue::Option(opt.clone()),
70 PaxValue::Vec(v) => PaxValue::Vec(v.clone()),
71 PaxValue::Range(start, end) => PaxValue::Range(start.clone(), end.clone()),
72 PaxValue::Object(pairs) => PaxValue::Object(pairs.clone()),
73 PaxValue::Enum(contents) => {
74 let (name, variant, values) = contents.as_ref();
75 PaxValue::Enum(Box::new((name.clone(), variant.clone(), values.clone())))
76 }
77 }
78 }
79}
80
81impl Display for PaxValue {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 match self {
85 PaxValue::Bool(b) => write!(f, "{}", b),
86 PaxValue::Numeric(n) => write!(f, "{}", n),
87 PaxValue::String(s) => write!(f, "\"{}\"", s),
88 PaxValue::Size(s) => write!(f, "{}", s),
89 PaxValue::Percent(p) => write!(f, "{}", p),
90 PaxValue::Color(c) => write!(f, "{}", c),
91 PaxValue::Rotation(r) => write!(f, "{}", r),
92 PaxValue::Duration(d) => write!(f, "{}", d),
93 PaxValue::PathElement(path_elem) => {
94 write!(f, "PathElement::")?;
95 match path_elem.as_ref() {
96 PathElement::Empty => write!(f, "Empty"),
97 PathElement::Point(s1, s2) => write!(f, "Point({}, {})", s1, s2),
98 PathElement::Line => write!(f, "Line"),
99 PathElement::Quadratic(s1, s2) => write!(f, "Quadratic({}, {})", s1, s2),
100 PathElement::Cubic(v1, v2, v3, v4) => {
101 write!(f, "Cubic({}, {}, {}, {})", v1, v2, v3, v4)
102 }
103 PathElement::Close => write!(f, "Close"),
104 }?;
105 Ok(())
106 }
107 PaxValue::Option(o) => match o.as_ref() {
108 Some(v) => write!(f, "Some({})", v),
109 None => write!(f, "None"),
110 },
111 PaxValue::Vec(v) => {
112 write!(f, "[")?;
113 for (i, val) in v.iter().enumerate() {
114 if i != 0 {
115 write!(f, ", ")?;
116 }
117 write!(f, "{}", val)?;
118 }
119 write!(f, "]")
120 }
121 PaxValue::Range(start, end) => write!(f, "{}..{}", start, end),
122 PaxValue::Object(o) => {
123 write!(f, "{{")?;
124 for (i, (key, val)) in o.iter().enumerate() {
125 if i != 0 {
126 write!(f, ", ")?;
127 }
128 write!(f, "{}: {}", key, val)?;
129 }
130 write!(f, "}}")
131 }
132 PaxValue::Enum(contents) => {
133 let (name, variant, values) = contents.as_ref();
134 if (name == "Fill" || name == "Stroke") && variant == "__layer" && values.len() == 1
135 {
136 return write!(f, "{} {}", name, values[0]);
137 }
138 if name == "Color" {
139 write!(f, "{}", variant)?;
140 } else {
141 write!(f, "{}::{}", name, variant)?;
142 }
143 if !values.is_empty() {
144 write!(f, "(")?;
145 for (i, val) in values.iter().enumerate() {
146 if i != 0 {
147 write!(f, ", ")?;
148 }
149 write!(f, "{}", val)?;
150 }
151 write!(f, ")")?;
152 }
153 Ok(())
154 }
155 }
156 }
157}
158
159impl Default for PaxValue {
160 fn default() -> Self {
161 PaxValue::Numeric(Numeric::F64(0.0))
162 }
163}
164
165pub enum PaxAny {
168 Builtin(PaxValue),
170 Any(Box<dyn Any>),
172}
173
174impl std::fmt::Debug for PaxAny {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 write!(f, "PaxAny {{ .. }}")
177 }
178}
179
180impl Interpolatable for PaxValue {}
181
182pub trait ToPaxValue {
187 fn nested_properties(&self) -> Vec<crate::properties::UntypedProperty> {
190 Vec::new()
191 }
192
193 fn to_pax_value(self) -> PaxValue;
195 fn to_pax_value_in_graph(self) -> PaxValue
199 where
200 Self: Sized,
201 {
202 crate::properties::with_graph_conversion(|| self.to_pax_value())
203 }
204}
205
206pub trait ToFromPaxAny
213where
214 Self: Sized + 'static,
215{
216 fn to_pax_any(self) -> PaxAny;
218 fn from_pax_any(pax_any: PaxAny) -> Result<Self, String>;
220 fn ref_from_pax_any(pax_any: &PaxAny) -> Result<&Self, String>;
222 fn mut_from_pax_any(pax_any: &mut PaxAny) -> Result<&mut Self, String>;
224}
225
226impl ToFromPaxAny for PaxValue {
227 fn to_pax_any(self) -> PaxAny {
228 PaxAny::Builtin(self)
229 }
230
231 fn from_pax_any(pax_any: PaxAny) -> Result<Self, String> {
232 match pax_any {
233 PaxAny::Builtin(val) => Ok(val),
234 PaxAny::Any(_) => Err("tried to unwrap any as builtin".to_string()),
235 }
236 }
237
238 fn ref_from_pax_any(pax_any: &PaxAny) -> Result<&Self, String> {
239 match pax_any {
240 PaxAny::Builtin(val) => Ok(val),
241 PaxAny::Any(_) => Err("tried to unwrap any as builtin".to_string()),
242 }
243 }
244
245 fn mut_from_pax_any(pax_any: &mut PaxAny) -> Result<&mut Self, String> {
246 match pax_any {
247 PaxAny::Builtin(val) => Ok(val),
248 PaxAny::Any(_) => Err("tried to unwrap any as builtin".to_string()),
249 }
250 }
251}
252
253pub trait ImplToFromPaxAny: 'static {}
257
258impl<T: ImplToFromPaxAny> ToFromPaxAny for T {
261 fn to_pax_any(self) -> PaxAny {
262 PaxAny::Any(Box::new(self) as Box<dyn Any>)
263 }
264
265 fn from_pax_any(pax_any: PaxAny) -> Result<Self, String> {
266 match pax_any {
267 PaxAny::Any(v) => Ok(*v
268 .downcast::<Self>()
269 .map_err(|_e| "downcast failed".to_string())?),
270 _ => Err("wasn't any".to_string()),
271 }
272 }
273
274 fn ref_from_pax_any(pax_any: &PaxAny) -> Result<&Self, String> {
275 match pax_any {
276 PaxAny::Any(v) => v
277 .downcast_ref::<Self>()
278 .ok_or_else(|| "downcast failed".to_string()),
279 _ => Err("wasn't any".to_string()),
280 }
281 }
282
283 fn mut_from_pax_any(pax_any: &mut PaxAny) -> Result<&mut Self, String> {
284 match pax_any {
285 PaxAny::Any(v) => v
286 .downcast_mut::<Self>()
287 .ok_or_else(|| "downcast failed".to_string()),
288 _ => Err("wasn't any".to_string()),
289 }
290 }
291}
292
293impl ToFromPaxAny for PaxAny {
295 fn to_pax_any(self) -> PaxAny {
296 self
297 }
298
299 fn from_pax_any(pax_any: PaxAny) -> Result<Self, String> {
300 Ok(pax_any)
301 }
302
303 fn ref_from_pax_any(pax_any: &PaxAny) -> Result<&Self, String> {
304 Ok(pax_any)
305 }
306
307 fn mut_from_pax_any(pax_any: &mut PaxAny) -> Result<&mut Self, String> {
308 Ok(pax_any)
309 }
310}