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 == "Color" {
135 write!(f, "{}", variant)?;
136 } else {
137 write!(f, "{}::{}", name, variant)?;
138 }
139 if !values.is_empty() {
140 write!(f, "(")?;
141 for (i, val) in values.iter().enumerate() {
142 if i != 0 {
143 write!(f, ", ")?;
144 }
145 write!(f, "{}", val)?;
146 }
147 write!(f, ")")?;
148 }
149 Ok(())
150 }
151 }
152 }
153}
154
155impl Default for PaxValue {
156 fn default() -> Self {
157 PaxValue::Numeric(Numeric::F64(0.0))
158 }
159}
160
161pub enum PaxAny {
164 Builtin(PaxValue),
166 Any(Box<dyn Any>),
168}
169
170impl std::fmt::Debug for PaxAny {
171 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172 write!(f, "PaxAny {{ .. }}")
173 }
174}
175
176impl Interpolatable for PaxValue {}
177
178pub trait ToPaxValue {
183 fn to_pax_value(self) -> PaxValue;
185}
186
187pub trait ToFromPaxAny
194where
195 Self: Sized + 'static,
196{
197 fn to_pax_any(self) -> PaxAny;
199 fn from_pax_any(pax_any: PaxAny) -> Result<Self, String>;
201 fn ref_from_pax_any(pax_any: &PaxAny) -> Result<&Self, String>;
203 fn mut_from_pax_any(pax_any: &mut PaxAny) -> Result<&mut Self, String>;
205}
206
207impl ToFromPaxAny for PaxValue {
208 fn to_pax_any(self) -> PaxAny {
209 PaxAny::Builtin(self)
210 }
211
212 fn from_pax_any(pax_any: PaxAny) -> Result<Self, String> {
213 match pax_any {
214 PaxAny::Builtin(val) => Ok(val),
215 PaxAny::Any(_) => Err("tried to unwrap any as builtin".to_string()),
216 }
217 }
218
219 fn ref_from_pax_any(pax_any: &PaxAny) -> Result<&Self, String> {
220 match pax_any {
221 PaxAny::Builtin(val) => Ok(val),
222 PaxAny::Any(_) => Err("tried to unwrap any as builtin".to_string()),
223 }
224 }
225
226 fn mut_from_pax_any(pax_any: &mut PaxAny) -> Result<&mut Self, String> {
227 match pax_any {
228 PaxAny::Builtin(val) => Ok(val),
229 PaxAny::Any(_) => Err("tried to unwrap any as builtin".to_string()),
230 }
231 }
232}
233
234pub trait ImplToFromPaxAny: 'static {}
238
239impl<T: ImplToFromPaxAny> ToFromPaxAny for T {
242 fn to_pax_any(self) -> PaxAny {
243 PaxAny::Any(Box::new(self) as Box<dyn Any>)
244 }
245
246 fn from_pax_any(pax_any: PaxAny) -> Result<Self, String> {
247 match pax_any {
248 PaxAny::Any(v) => Ok(*v
249 .downcast::<Self>()
250 .map_err(|_e| "downcast failed".to_string())?),
251 _ => Err("wasn't any".to_string()),
252 }
253 }
254
255 fn ref_from_pax_any(pax_any: &PaxAny) -> Result<&Self, String> {
256 match pax_any {
257 PaxAny::Any(v) => v
258 .downcast_ref::<Self>()
259 .ok_or_else(|| "downcast failed".to_string()),
260 _ => Err("wasn't any".to_string()),
261 }
262 }
263
264 fn mut_from_pax_any(pax_any: &mut PaxAny) -> Result<&mut Self, String> {
265 match pax_any {
266 PaxAny::Any(v) => v
267 .downcast_mut::<Self>()
268 .ok_or_else(|| "downcast failed".to_string()),
269 _ => Err("wasn't any".to_string()),
270 }
271 }
272}
273
274impl ToFromPaxAny for PaxAny {
276 fn to_pax_any(self) -> PaxAny {
277 self
278 }
279
280 fn from_pax_any(pax_any: PaxAny) -> Result<Self, String> {
281 Ok(pax_any)
282 }
283
284 fn ref_from_pax_any(pax_any: &PaxAny) -> Result<&Self, String> {
285 Ok(pax_any)
286 }
287
288 fn mut_from_pax_any(pax_any: &mut PaxAny) -> Result<&mut Self, String> {
289 Ok(pax_any)
290 }
291}