Skip to main content

pax_runtime_api/pax_value/
to_from_impls.rs

1use std::ops::Range;
2use std::rc::Rc;
3
4use std::cell::RefCell;
5
6use super::ImplToFromPaxAny;
7use super::Numeric;
8use super::PaxValue;
9use super::ToPaxValue;
10use crate::impl_to_pax_value;
11use crate::math::Space;
12use crate::math::Transform2;
13use crate::math::Vector2;
14use crate::properties::PropertyValue;
15use crate::Color;
16use crate::ColorChannel;
17use crate::Depth;
18use crate::Duration;
19use crate::GradientStop;
20use crate::LayoutRole;
21use crate::LightShape;
22use crate::LinearGradient;
23use crate::Material;
24use crate::MaterialParams;
25use crate::Opacity;
26use crate::PathElement;
27use crate::PathSmoothing;
28use crate::Percent;
29use crate::Property;
30use crate::RadialGradient;
31use crate::Rotation;
32use crate::SceneAmbientLight;
33use crate::SceneLight;
34use crate::SceneLighting;
35use crate::Size;
36use crate::Stroke;
37use crate::StrokeCap;
38use crate::StrokeJoin;
39use crate::Transform2D;
40use crate::UnitValue;
41use crate::Vector3;
42use crate::{Fill, Paint};
43
44// Primitive types
45impl_to_pax_value!(bool, PaxValue::Bool);
46
47impl_to_pax_value!(u8, PaxValue::Numeric, Numeric::U8);
48impl_to_pax_value!(u16, PaxValue::Numeric, Numeric::U16);
49impl_to_pax_value!(u32, PaxValue::Numeric, Numeric::U32);
50impl_to_pax_value!(u64, PaxValue::Numeric, Numeric::U64);
51
52impl_to_pax_value!(i8, PaxValue::Numeric, Numeric::I8);
53impl_to_pax_value!(i16, PaxValue::Numeric, Numeric::I16);
54impl_to_pax_value!(i32, PaxValue::Numeric, Numeric::I32);
55impl_to_pax_value!(i64, PaxValue::Numeric, Numeric::I64);
56
57impl_to_pax_value!(f32, PaxValue::Numeric, Numeric::F32);
58impl_to_pax_value!(f64, PaxValue::Numeric, Numeric::F64);
59
60impl_to_pax_value!(isize, PaxValue::Numeric, Numeric::ISize);
61impl_to_pax_value!(usize, PaxValue::Numeric, Numeric::USize);
62
63// don't allow to be serialized/deserialized successfully, just store it as a dyn Any
64impl ImplToFromPaxAny for () {}
65
66// for now. TBD how to handle this when we join Transform2D with Transform2 at some point
67impl<F: Space, T: Space> ImplToFromPaxAny for Transform2<F, T> {}
68
69impl_to_pax_value!(String, PaxValue::String);
70
71// Pax internal types
72impl_to_pax_value!(Numeric, PaxValue::Numeric);
73impl_to_pax_value!(Size, PaxValue::Size);
74impl_to_pax_value!(Rotation, PaxValue::Rotation);
75impl_to_pax_value!(Duration, PaxValue::Duration);
76impl_to_pax_value!(Percent, PaxValue::Percent);
77
78impl ToPaxValue for Depth {
79    fn to_pax_value(self) -> PaxValue {
80        PaxValue::Size(Size::Pixels(self.0))
81    }
82}
83
84impl ToPaxValue for LayoutRole {
85    fn to_pax_value(self) -> PaxValue {
86        let variant = match self {
87            LayoutRole::Default => "Default",
88            LayoutRole::Breakout => "Breakout",
89        };
90        PaxValue::Enum(Box::new((
91            "LayoutRole".to_string(),
92            variant.to_string(),
93            vec![],
94        )))
95    }
96}
97
98impl ToPaxValue for PathElement {
99    fn to_pax_value(self) -> PaxValue {
100        PaxValue::PathElement(Box::new(self))
101    }
102}
103
104impl ToPaxValue for Color {
105    fn to_pax_value(self) -> PaxValue {
106        PaxValue::Color(Box::new(self))
107    }
108}
109
110// Pax Vec type
111impl<T: ToPaxValue> ToPaxValue for Vec<T> {
112    fn nested_properties(&self) -> Vec<crate::properties::UntypedProperty> {
113        self.iter()
114            .flat_map(ToPaxValue::nested_properties)
115            .collect()
116    }
117    fn to_pax_value(self) -> PaxValue {
118        PaxValue::Vec(
119            self.into_iter()
120                .map(|v| v.to_pax_value())
121                .collect::<Vec<_>>(),
122        )
123    }
124}
125
126impl<T: ToPaxValue> ToPaxValue for Option<T> {
127    fn to_pax_value(self) -> PaxValue {
128        match self {
129            Some(v) => PaxValue::Option(Box::new(Some(v.to_pax_value()))),
130            None => PaxValue::Option(Box::new(None)),
131        }
132    }
133}
134
135impl<T: ToPaxValue> ToPaxValue for Range<T> {
136    fn to_pax_value(self) -> PaxValue {
137        PaxValue::Range(
138            Box::new(self.start.to_pax_value()),
139            Box::new(self.end.to_pax_value()),
140        )
141    }
142}
143
144impl<T: ToPaxValue + Clone> ToPaxValue for Rc<RefCell<T>> {
145    fn to_pax_value(self) -> PaxValue {
146        crate::borrow!(self).clone().to_pax_value()
147    }
148}
149
150impl ToPaxValue for PaxValue {
151    fn to_pax_value(self) -> PaxValue {
152        self
153    }
154}
155
156impl<T: ToPaxValue + crate::properties::SharedPropertyValue> ToPaxValue for Property<T> {
157    fn nested_properties(&self) -> Vec<crate::properties::UntypedProperty> {
158        let mut dependencies = vec![self.local().untyped()];
159        dependencies.extend(self.local().get().nested_properties());
160        dependencies
161    }
162    fn to_pax_value(self) -> PaxValue {
163        crate::PropertyBinding::value_for_conversion(&self).to_pax_value()
164    }
165}
166
167impl<T: ToPaxValue + PropertyValue> ToPaxValue for crate::LocalProperty<T> {
168    fn nested_properties(&self) -> Vec<crate::properties::UntypedProperty> {
169        let mut dependencies = vec![self.untyped()];
170        dependencies.extend(self.get().nested_properties());
171        dependencies
172    }
173    fn to_pax_value(self) -> PaxValue {
174        self.get().to_pax_value()
175    }
176}
177
178impl ToPaxValue for Paint {
179    fn to_pax_value(self) -> PaxValue {
180        match self {
181            Paint::Blend(terms) => PaxValue::Enum(Box::new((
182                "Paint".to_string(),
183                "Blend".to_string(),
184                vec![PaxValue::Vec(
185                    terms
186                        .into_iter()
187                        .map(|(fill, weight)| {
188                            PaxValue::Vec(vec![fill.to_pax_value(), weight.to_pax_value()])
189                        })
190                        .collect(),
191                )],
192            ))),
193            Paint::Solid(color) => PaxValue::Enum(Box::new((
194                "Paint".to_string(),
195                "Solid".to_string(),
196                vec![color.to_pax_value()],
197            ))),
198            Paint::MeshGradient(mesh) => PaxValue::Enum(Box::new((
199                "Paint".into(),
200                "MeshGradient".into(),
201                vec![mesh.to_pax_value()],
202            ))),
203            Paint::LinearGradient(gradient) => PaxValue::Enum(Box::new((
204                "Paint".to_string(),
205                "LinearGradient".to_string(),
206                vec![gradient.to_pax_value()],
207            ))),
208            Paint::RadialGradient(gradient) => PaxValue::Enum(Box::new((
209                "Paint".to_string(),
210                "RadialGradient".to_string(),
211                vec![gradient.to_pax_value()],
212            ))),
213        }
214    }
215}
216
217impl ToPaxValue for ColorChannel {
218    fn to_pax_value(self) -> PaxValue {
219        match self {
220            ColorChannel::Rotation(rot) => PaxValue::Enum(Box::new((
221                "ColorChannel".to_string(),
222                "Rotation".to_string(),
223                vec![rot.to_pax_value()],
224            ))),
225            ColorChannel::Percent(perc) => PaxValue::Enum(Box::new((
226                "ColorChannel".to_string(),
227                "Percent".to_string(),
228                vec![perc.to_pax_value()],
229            ))),
230            ColorChannel::Integer(num) => PaxValue::Enum(Box::new((
231                "ColorChannel".to_string(),
232                "Integer".to_string(),
233                vec![num.to_pax_value()],
234            ))),
235        }
236    }
237}
238
239impl ToPaxValue for Opacity {
240    fn to_pax_value(self) -> PaxValue {
241        match self {
242            Opacity::Alpha(value) => PaxValue::Enum(Box::new((
243                "Opacity".to_string(),
244                "Alpha".to_string(),
245                vec![value.to_pax_value()],
246            ))),
247            Opacity::Percent(value) => PaxValue::Enum(Box::new((
248                "Opacity".to_string(),
249                "Percent".to_string(),
250                vec![value.to_pax_value()],
251            ))),
252        }
253    }
254}
255
256impl ToPaxValue for UnitValue {
257    fn to_pax_value(self) -> PaxValue {
258        match self {
259            UnitValue::Unitless(value) => PaxValue::Enum(Box::new((
260                "UnitValue".to_string(),
261                "Unitless".to_string(),
262                vec![value.to_pax_value()],
263            ))),
264            UnitValue::Percent(value) => PaxValue::Enum(Box::new((
265                "UnitValue".to_string(),
266                "Percent".to_string(),
267                vec![value.to_pax_value()],
268            ))),
269        }
270    }
271}
272
273macro_rules! layer_pax_value {
274    ($ty:ident, $($field:ident),+) => {
275        impl ToPaxValue for $ty {
276            fn nested_properties(&self) -> Vec<crate::properties::UntypedProperty> {
277                let mut properties = Vec::new(); $(properties.extend(self.$field.nested_properties());)+ properties
278            }
279            fn to_pax_value(self) -> PaxValue {
280                PaxValue::Enum(Box::new((stringify!($ty).into(), "__layer".into(), vec![
281                    PaxValue::Object(vec![$((stringify!($field).into(), self.$field.to_pax_value())),+])
282                ])))
283            }
284        }
285    }
286}
287layer_pax_value!(Fill, paint, material, opacity);
288layer_pax_value!(Stroke, paint, material, opacity, width, cap, join);
289
290impl ToPaxValue for StrokeCap {
291    fn to_pax_value(self) -> PaxValue {
292        let variant = match self {
293            StrokeCap::Butt => "Butt",
294            StrokeCap::Round => "Round",
295            StrokeCap::Square => "Square",
296        };
297        PaxValue::Enum(Box::new((
298            "StrokeCap".to_string(),
299            variant.to_string(),
300            vec![],
301        )))
302    }
303}
304
305impl ToPaxValue for PathSmoothing {
306    fn to_pax_value(self) -> PaxValue {
307        let variant = match self {
308            PathSmoothing::None => "None",
309            PathSmoothing::Light => "Light",
310            PathSmoothing::Strong => "Strong",
311        };
312        PaxValue::Enum(Box::new((
313            "PathSmoothing".to_string(),
314            variant.to_string(),
315            vec![],
316        )))
317    }
318}
319
320impl ToPaxValue for StrokeJoin {
321    fn to_pax_value(self) -> PaxValue {
322        let variant = match self {
323            StrokeJoin::Miter => "Miter",
324            StrokeJoin::Round => "Round",
325            StrokeJoin::Bevel => "Bevel",
326        };
327        PaxValue::Enum(Box::new((
328            "StrokeJoin".to_string(),
329            variant.to_string(),
330            vec![],
331        )))
332    }
333}
334
335impl ToPaxValue for LightShape {
336    fn to_pax_value(self) -> PaxValue {
337        let variant = match self {
338            LightShape::Point => "Point",
339            LightShape::Directional => "Directional",
340        };
341        PaxValue::Enum(Box::new((
342            "LightShape".to_string(),
343            variant.to_string(),
344            vec![],
345        )))
346    }
347}
348
349impl ToPaxValue for Vector3 {
350    fn to_pax_value(self) -> PaxValue {
351        PaxValue::Object(
352            vec![
353                ("x".to_string(), self.x.to_pax_value()),
354                ("y".to_string(), self.y.to_pax_value()),
355                ("z".to_string(), self.z.to_pax_value()),
356            ]
357            .into_iter()
358            .collect(),
359        )
360    }
361}
362
363impl ToPaxValue for MaterialParams {
364    fn to_pax_value(self) -> PaxValue {
365        PaxValue::Object(
366            vec![
367                ("ambient".to_string(), self.ambient.to_pax_value()),
368                ("diffuse".to_string(), self.diffuse.to_pax_value()),
369                ("specular".to_string(), self.specular.to_pax_value()),
370                ("roughness".to_string(), self.roughness.to_pax_value()),
371                ("metallic".to_string(), self.metallic.to_pax_value()),
372                ("emissive".to_string(), self.emissive.to_pax_value()),
373                (
374                    "emissive_intensity".to_string(),
375                    self.emissive_intensity.to_pax_value(),
376                ),
377            ]
378            .into_iter()
379            .collect(),
380        )
381    }
382}
383
384impl ToPaxValue for Material {
385    fn nested_properties(&self) -> Vec<crate::properties::UntypedProperty> {
386        match self {
387            Self::Unlit => vec![],
388            Self::Lit(p) => vec![
389                p.ambient.untyped(),
390                p.diffuse.untyped(),
391                p.specular.untyped(),
392                p.roughness.untyped(),
393                p.metallic.untyped(),
394                p.emissive.untyped(),
395                p.emissive_intensity.untyped(),
396            ],
397        }
398    }
399    fn to_pax_value(self) -> PaxValue {
400        match self {
401            Material::Lit(params) => PaxValue::Enum(Box::new((
402                "Material".to_string(),
403                "Lit".to_string(),
404                vec![params.to_pax_value()],
405            ))),
406            Material::Unlit => PaxValue::Enum(Box::new((
407                "Material".to_string(),
408                "Unlit".to_string(),
409                vec![],
410            ))),
411        }
412    }
413}
414
415impl ToPaxValue for SceneAmbientLight {
416    fn to_pax_value(self) -> PaxValue {
417        PaxValue::Object(
418            vec![
419                ("color".to_string(), self.color.to_pax_value()),
420                ("intensity".to_string(), self.intensity.to_pax_value()),
421            ]
422            .into_iter()
423            .collect(),
424        )
425    }
426}
427
428impl ToPaxValue for SceneLight {
429    fn to_pax_value(self) -> PaxValue {
430        PaxValue::Object(
431            vec![
432                ("shape".to_string(), self.shape.to_pax_value()),
433                ("position".to_string(), self.position.to_pax_value()),
434                ("direction".to_string(), self.direction.to_pax_value()),
435                ("color".to_string(), self.color.to_pax_value()),
436                ("intensity".to_string(), self.intensity.to_pax_value()),
437                ("radius".to_string(), self.radius.to_pax_value()),
438                ("enabled".to_string(), self.enabled.to_pax_value()),
439            ]
440            .into_iter()
441            .collect(),
442        )
443    }
444}
445
446impl ToPaxValue for SceneLighting {
447    fn to_pax_value(self) -> PaxValue {
448        PaxValue::Object(
449            vec![
450                ("active".to_string(), self.active.to_pax_value()),
451                (
452                    "ambient_is_authored".to_string(),
453                    self.ambient_is_authored.to_pax_value(),
454                ),
455                ("ambient".to_string(), self.ambient.to_pax_value()),
456                ("lights".to_string(), self.lights.to_pax_value()),
457            ]
458            .into_iter()
459            .collect(),
460        )
461    }
462}
463
464impl ToPaxValue for GradientStop {
465    fn to_pax_value(self) -> PaxValue {
466        PaxValue::Object(
467            vec![
468                ("position".to_string(), self.position.to_pax_value()),
469                ("color".to_string(), self.color.to_pax_value()),
470            ]
471            .into_iter()
472            .collect(),
473        )
474    }
475}
476
477impl ToPaxValue for crate::MeshPoint {
478    fn to_pax_value(self) -> PaxValue {
479        PaxValue::Object(vec![
480            (
481                "position".into(),
482                PaxValue::Vec(vec![
483                    self.position.0.to_pax_value(),
484                    self.position.1.to_pax_value(),
485                ]),
486            ),
487            ("color".into(), self.color.to_pax_value()),
488        ])
489    }
490}
491
492impl ToPaxValue for crate::MeshGradient {
493    fn to_pax_value(self) -> PaxValue {
494        PaxValue::Object(vec![("rows".into(), self.rows.to_pax_value())])
495    }
496}
497
498impl ToPaxValue for LinearGradient {
499    fn to_pax_value(self) -> PaxValue {
500        PaxValue::Object(
501            vec![
502                (
503                    "start".to_string(),
504                    PaxValue::Vec(vec![
505                        self.start.0.to_pax_value(),
506                        self.start.1.to_pax_value(),
507                    ]),
508                ),
509                (
510                    "end".to_string(),
511                    PaxValue::Vec(vec![self.end.0.to_pax_value(), self.end.1.to_pax_value()]),
512                ),
513                ("stops".to_string(), self.stops.to_pax_value()),
514            ]
515            .into_iter()
516            .collect(),
517        )
518    }
519}
520
521impl ToPaxValue for RadialGradient {
522    fn to_pax_value(self) -> PaxValue {
523        PaxValue::Object(
524            vec![
525                (
526                    "start".to_string(),
527                    PaxValue::Vec(vec![
528                        self.start.0.to_pax_value(),
529                        self.start.1.to_pax_value(),
530                    ]),
531                ),
532                (
533                    "end".to_string(),
534                    PaxValue::Vec(vec![self.end.0.to_pax_value(), self.end.1.to_pax_value()]),
535                ),
536                ("radius".to_string(), self.radius.to_pax_value()),
537                ("stops".to_string(), self.stops.to_pax_value()),
538            ]
539            .into_iter()
540            .collect(),
541        )
542    }
543}
544
545impl ToPaxValue for Transform2D {
546    fn to_pax_value(self) -> PaxValue {
547        PaxValue::Object(
548            vec![
549                (
550                    "previous".to_string(),
551                    self.previous
552                        .map(|p| p.to_pax_value())
553                        .unwrap_or(PaxValue::Option(Box::new(None))),
554                ),
555                (
556                    "rotate".to_string(),
557                    self.rotate
558                        .map(|r| r.to_pax_value())
559                        .unwrap_or(PaxValue::Option(Box::new(None))),
560                ),
561                (
562                    "translate".to_string(),
563                    self.translate
564                        .map(|t| PaxValue::Option(Box::new(Some(t.to_vec().to_pax_value()))))
565                        .unwrap_or(PaxValue::Option(Box::new(None))),
566                ),
567                (
568                    "anchor".to_string(),
569                    self.anchor
570                        .map(|a| PaxValue::Option(Box::new(Some(a.to_vec().to_pax_value()))))
571                        .unwrap_or(PaxValue::Option(Box::new(None))),
572                ),
573                (
574                    "scale".to_string(),
575                    self.scale
576                        .map(|s| PaxValue::Option(Box::new(Some(s.to_vec().to_pax_value()))))
577                        .unwrap_or(PaxValue::Option(Box::new(None))),
578                ),
579                (
580                    "skew".to_string(),
581                    self.skew
582                        .map(|s| PaxValue::Option(Box::new(Some(s.to_vec().to_pax_value()))))
583                        .unwrap_or(PaxValue::Option(Box::new(None))),
584                ),
585            ]
586            .into_iter()
587            .collect(),
588        )
589    }
590}
591
592impl ToPaxValue for Transform2 {
593    fn to_pax_value(self) -> PaxValue {
594        PaxValue::Object(
595            vec![(
596                "m".to_string(),
597                PaxValue::Vec(self.m.iter().map(|v| v.to_pax_value()).collect::<Vec<_>>()),
598            )]
599            .into_iter()
600            .collect(),
601        )
602    }
603}
604
605impl ToPaxValue for Vector2 {
606    fn to_pax_value(self) -> PaxValue {
607        PaxValue::Object(
608            vec![
609                ("x".to_string(), self.x.to_pax_value()),
610                ("y".to_string(), self.y.to_pax_value()),
611            ]
612            .into_iter()
613            .collect(),
614        )
615    }
616}