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
44impl_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
63impl ImplToFromPaxAny for () {}
65
66impl<F: Space, T: Space> ImplToFromPaxAny for Transform2<F, T> {}
68
69impl_to_pax_value!(String, PaxValue::String);
70
71impl_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
110impl<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}