Skip to main content

lumen_engine/node/
deferred.rs

1use crate::expr::Expression;
2
3use super::{
4    delegate::{DelegateEvalContext, DelegateEvaluable, DelegateValue, Delegated},
5    ids::NodeId,
6    property::{PropertyExpression, PropertyValue},
7    vector,
8};
9
10#[derive(Debug, Clone)]
11pub enum Deferred<T> {
12    Value(T),
13    Expr(Expression),
14}
15
16impl<T> Deferred<T> {
17    pub fn value(value: T) -> Self {
18        Self::Value(value)
19    }
20
21    pub fn eval(
22        &self,
23        node_id: NodeId,
24        property_path: &str,
25        ctx: &crate::expr::ExpressionContext<'_>,
26    ) -> crate::Result<T>
27    where
28        T: DeferredValue,
29    {
30        T::eval_deferred(self, node_id, property_path, ctx)
31    }
32
33    pub fn to_property_value(&self) -> PropertyValue
34    where
35        T: DeferredValue,
36    {
37        match self {
38            Self::Value(value) => T::to_property_value(value),
39            Self::Expr(_) => {
40                panic!(
41                    "Deferred::to_property_value called on expression; use to_property_expression"
42                )
43            }
44        }
45    }
46
47    pub fn to_property_expression(&self) -> PropertyExpression
48    where
49        T: DeferredValue,
50    {
51        match self {
52            Self::Value(value) => PropertyExpression::Value(T::to_property_value(value)),
53            Self::Expr(expr) => PropertyExpression::Expr(expr.clone()),
54        }
55    }
56
57    pub fn from_property_expression(value: PropertyExpression) -> crate::Result<Self>
58    where
59        T: DeferredValue,
60    {
61        match value {
62            PropertyExpression::Value(value) => T::from_property_value(value)
63                .map(Self::Value)
64                .ok_or_else(|| {
65                    PropertyValue::invalid_type(
66                        NodeId::new(0),
67                        "",
68                        T::property_kind_name(),
69                        "property",
70                    )
71                }),
72            PropertyExpression::Expr(expr) => Ok(Self::Expr(expr)),
73        }
74    }
75}
76
77impl<T> From<T> for Deferred<T> {
78    fn from(value: T) -> Self {
79        Self::Value(value)
80    }
81}
82
83impl Deferred<f64> {
84    pub fn resolve_float(
85        &self,
86        node_id: NodeId,
87        property_path: &str,
88        ctx: &crate::expr::ExpressionContext<'_>,
89    ) -> crate::Result<f64> {
90        self.eval(node_id, property_path, ctx)
91    }
92}
93
94impl Deferred<i64> {
95    pub fn resolve_int(
96        &self,
97        node_id: NodeId,
98        property_path: &str,
99        ctx: &crate::expr::ExpressionContext<'_>,
100    ) -> crate::Result<i64> {
101        self.eval(node_id, property_path, ctx)
102    }
103
104    pub fn resolve_float(
105        &self,
106        node_id: NodeId,
107        property_path: &str,
108        ctx: &crate::expr::ExpressionContext<'_>,
109    ) -> crate::Result<f64> {
110        self.eval(node_id, property_path, ctx)
111            .map(|value| value as f64)
112    }
113}
114
115impl Deferred<bool> {
116    pub fn resolve_bool(
117        &self,
118        node_id: NodeId,
119        property_path: &str,
120        ctx: &crate::expr::ExpressionContext<'_>,
121    ) -> crate::Result<bool> {
122        self.eval(node_id, property_path, ctx)
123    }
124}
125
126impl Deferred<String> {
127    pub fn resolve_string(
128        &self,
129        node_id: NodeId,
130        property_path: &str,
131        ctx: &crate::expr::ExpressionContext<'_>,
132    ) -> crate::Result<String> {
133        self.eval(node_id, property_path, ctx)
134    }
135}
136
137impl Deferred<[u8; 4]> {
138    pub fn resolve_color(
139        &self,
140        node_id: NodeId,
141        property_path: &str,
142        ctx: &crate::expr::ExpressionContext<'_>,
143    ) -> crate::Result<[u8; 4]> {
144        self.eval(node_id, property_path, ctx)
145    }
146}
147
148impl Deferred<vector::paint::Paint> {
149    pub fn resolve_paint(
150        &self,
151        node_id: NodeId,
152        property_path: &str,
153        ctx: &crate::expr::ExpressionContext<'_>,
154    ) -> crate::Result<vector::paint::Paint> {
155        self.eval(node_id, property_path, ctx)
156    }
157}
158
159impl Deferred<(f64, f64)> {
160    pub fn resolve_vec2(
161        &self,
162        node_id: NodeId,
163        property_path: &str,
164        ctx: &crate::expr::ExpressionContext<'_>,
165    ) -> crate::Result<(f64, f64)> {
166        self.eval(node_id, property_path, ctx)
167    }
168}
169
170#[cfg(feature = "json")]
171impl<'de, T> serde::Deserialize<'de> for Deferred<T>
172where
173    T: DeferredJsonValue,
174{
175    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
176    where
177        D: serde::Deserializer<'de>,
178    {
179        let value = serde_json::Value::deserialize(deserializer)?;
180        if let Some(text) = value.as_str()
181            && let Some(source) = text.strip_prefix('=')
182        {
183            return Expression::parse(source)
184                .map(Self::Expr)
185                .map_err(serde::de::Error::custom);
186        }
187        T::from_json_value(&value)
188            .map(Self::Value)
189            .map_err(serde::de::Error::custom)
190    }
191}
192
193#[cfg(feature = "json")]
194pub trait DeferredJsonValue: Sized {
195    fn from_json_value(value: &serde_json::Value) -> Result<Self, String>;
196}
197
198pub trait DeferredValue: Clone {
199    fn eval_deferred(
200        deferred: &Deferred<Self>,
201        node_id: NodeId,
202        property_path: &str,
203        ctx: &crate::expr::ExpressionContext<'_>,
204    ) -> crate::Result<Self>
205    where
206        Self: Sized;
207
208    fn to_property_value(value: &Self) -> PropertyValue;
209    fn from_property_value(value: PropertyValue) -> Option<Self>
210    where
211        Self: Sized;
212    fn property_kind_name() -> &'static str;
213}
214
215impl<T> DelegateEvaluable for Deferred<T>
216where
217    T: DeferredValue,
218{
219    type Evaluated = T;
220
221    fn eval(&self, ctx: &DelegateEvalContext<'_>) -> crate::Result<Self::Evaluated> {
222        Deferred::eval(self, ctx.node_id, ctx.property_path, ctx.expr)
223    }
224}
225
226impl<T> DelegateValue for Deferred<T>
227where
228    T: DeferredValue,
229{
230    fn to_property_value(&self) -> PropertyValue {
231        Deferred::to_property_value(self)
232    }
233
234    fn to_property_expression(&self) -> PropertyExpression {
235        Deferred::to_property_expression(self)
236    }
237
238    fn from_property_expression(value: PropertyExpression) -> crate::Result<Self> {
239        Deferred::from_property_expression(value)
240    }
241}
242
243macro_rules! impl_delegated_deferred {
244    ($($ty:ty),* $(,)?) => {
245        $(
246            impl Delegated for $ty {
247                type Delegate = Deferred<$ty>;
248
249                fn into_delegate(self) -> Self::Delegate {
250                    Deferred::value(self)
251                }
252            }
253        )*
254    };
255}
256
257impl_delegated_deferred!(
258    f64,
259    f32,
260    i64,
261    u32,
262    u8,
263    bool,
264    String,
265    [u8; 4],
266    (f64, f64),
267    [f32; 2]
268);
269
270macro_rules! impl_deferred_float_expr {
271    ($ty:ty, $conv:expr) => {
272        impl DeferredValue for $ty {
273            fn eval_deferred(
274                deferred: &Deferred<Self>,
275                node_id: NodeId,
276                property_path: &str,
277                ctx: &crate::expr::ExpressionContext<'_>,
278            ) -> crate::Result<Self> {
279                match deferred {
280                    Deferred::Value(value) => Ok(*value),
281                    Deferred::Expr(expr) => {
282                        expr.evaluate(ctx)?.as_f64().map($conv).ok_or_else(|| {
283                            PropertyValue::invalid_type(
284                                node_id,
285                                property_path,
286                                "Float",
287                                "expression",
288                            )
289                        })
290                    }
291                }
292            }
293
294            fn to_property_value(value: &Self) -> PropertyValue {
295                PropertyValue::Float(f64::from(*value))
296            }
297
298            fn from_property_value(value: PropertyValue) -> Option<Self> {
299                value.coerce_float().map($conv)
300            }
301
302            fn property_kind_name() -> &'static str {
303                "Float"
304            }
305        }
306    };
307}
308
309impl_deferred_float_expr!(f64, |value: f64| value);
310
311impl DeferredValue for f32 {
312    fn eval_deferred(
313        deferred: &Deferred<Self>,
314        node_id: NodeId,
315        property_path: &str,
316        ctx: &crate::expr::ExpressionContext<'_>,
317    ) -> crate::Result<Self> {
318        match deferred {
319            Deferred::Value(value) => Ok(*value),
320            Deferred::Expr(expr) => expr
321                .evaluate(ctx)?
322                .as_f64()
323                .map(|value| value as f32)
324                .ok_or_else(|| {
325                    PropertyValue::invalid_type(node_id, property_path, "Float", "expression")
326                }),
327        }
328    }
329
330    fn to_property_value(value: &Self) -> PropertyValue {
331        PropertyValue::Float(f64::from(*value))
332    }
333
334    fn from_property_value(value: PropertyValue) -> Option<Self> {
335        value.coerce_float().map(|value| value as f32)
336    }
337
338    fn property_kind_name() -> &'static str {
339        "Float"
340    }
341}
342
343impl DeferredValue for i64 {
344    fn eval_deferred(
345        deferred: &Deferred<Self>,
346        node_id: NodeId,
347        property_path: &str,
348        ctx: &crate::expr::ExpressionContext<'_>,
349    ) -> crate::Result<Self> {
350        match deferred {
351            Deferred::Value(value) => Ok(*value),
352            Deferred::Expr(expr) => {
353                let value = expr.evaluate(ctx)?.as_f64().ok_or_else(|| {
354                    PropertyValue::invalid_type(node_id, property_path, "Int", "expression")
355                })?;
356                Ok(value as i64)
357            }
358        }
359    }
360
361    fn to_property_value(value: &Self) -> PropertyValue {
362        PropertyValue::Int(*value)
363    }
364
365    fn from_property_value(value: PropertyValue) -> Option<Self> {
366        value.coerce_int()
367    }
368
369    fn property_kind_name() -> &'static str {
370        "Int"
371    }
372}
373
374impl DeferredValue for u32 {
375    fn eval_deferred(
376        deferred: &Deferred<Self>,
377        node_id: NodeId,
378        property_path: &str,
379        ctx: &crate::expr::ExpressionContext<'_>,
380    ) -> crate::Result<Self> {
381        let value = match deferred {
382            Deferred::Value(value) => i64::from(*value),
383            Deferred::Expr(expr) => expr.evaluate(ctx)?.as_f64().ok_or_else(|| {
384                PropertyValue::invalid_type(node_id, property_path, "UInt", "expression")
385            })? as i64,
386        };
387        u32::try_from(value)
388            .map_err(|_| PropertyValue::invalid_type(node_id, property_path, "UInt", "range"))
389    }
390
391    fn to_property_value(value: &Self) -> PropertyValue {
392        PropertyValue::Int(i64::from(*value))
393    }
394
395    fn from_property_value(value: PropertyValue) -> Option<Self> {
396        value
397            .coerce_int()
398            .and_then(|value| u32::try_from(value).ok())
399    }
400
401    fn property_kind_name() -> &'static str {
402        "UInt"
403    }
404}
405
406impl DeferredValue for u8 {
407    fn eval_deferred(
408        deferred: &Deferred<Self>,
409        node_id: NodeId,
410        property_path: &str,
411        ctx: &crate::expr::ExpressionContext<'_>,
412    ) -> crate::Result<Self> {
413        let value = match deferred {
414            Deferred::Value(value) => i64::from(*value),
415            Deferred::Expr(expr) => expr.evaluate(ctx)?.as_f64().ok_or_else(|| {
416                PropertyValue::invalid_type(node_id, property_path, "Int", "expression")
417            })? as i64,
418        };
419        u8::try_from(value)
420            .map_err(|_| PropertyValue::invalid_type(node_id, property_path, "U8", "range"))
421    }
422
423    fn to_property_value(value: &Self) -> PropertyValue {
424        PropertyValue::Int(i64::from(*value))
425    }
426
427    fn from_property_value(value: PropertyValue) -> Option<Self> {
428        value
429            .coerce_int()
430            .and_then(|value| u8::try_from(value).ok())
431    }
432
433    fn property_kind_name() -> &'static str {
434        "U8"
435    }
436}
437
438impl DeferredValue for bool {
439    fn eval_deferred(
440        deferred: &Deferred<Self>,
441        _node_id: NodeId,
442        _property_path: &str,
443        ctx: &crate::expr::ExpressionContext<'_>,
444    ) -> crate::Result<Self> {
445        match deferred {
446            Deferred::Value(value) => Ok(*value),
447            Deferred::Expr(expr) => Ok(expr.evaluate(ctx)?.as_bool()),
448        }
449    }
450
451    fn to_property_value(value: &Self) -> PropertyValue {
452        PropertyValue::Bool(*value)
453    }
454
455    fn from_property_value(value: PropertyValue) -> Option<Self> {
456        value.coerce_bool()
457    }
458
459    fn property_kind_name() -> &'static str {
460        "Bool"
461    }
462}
463
464impl DeferredValue for String {
465    fn eval_deferred(
466        deferred: &Deferred<Self>,
467        _node_id: NodeId,
468        _property_path: &str,
469        ctx: &crate::expr::ExpressionContext<'_>,
470    ) -> crate::Result<Self> {
471        match deferred {
472            Deferred::Value(value) => Ok(value.clone()),
473            Deferred::Expr(expr) => Ok(expr.evaluate(ctx)?.as_string()),
474        }
475    }
476
477    fn to_property_value(value: &Self) -> PropertyValue {
478        PropertyValue::String(value.clone())
479    }
480
481    fn from_property_value(value: PropertyValue) -> Option<Self> {
482        value.coerce_string()
483    }
484
485    fn property_kind_name() -> &'static str {
486        "String"
487    }
488}
489
490macro_rules! impl_deferred_literal {
491    ($ty:ty, $kind:literal, $variant:ident, $expr_err:literal) => {
492        impl DeferredValue for $ty {
493            fn eval_deferred(
494                deferred: &Deferred<Self>,
495                node_id: NodeId,
496                property_path: &str,
497                _ctx: &crate::expr::ExpressionContext<'_>,
498            ) -> crate::Result<Self> {
499                match deferred {
500                    Deferred::Value(value) => Ok(*value),
501                    Deferred::Expr(_) => Err(PropertyValue::invalid_type(
502                        node_id,
503                        property_path,
504                        $expr_err,
505                        "expression",
506                    )),
507                }
508            }
509
510            fn to_property_value(value: &Self) -> PropertyValue {
511                PropertyValue::$variant(*value)
512            }
513
514            fn from_property_value(value: PropertyValue) -> Option<Self> {
515                match value {
516                    PropertyValue::$variant(value) => Some(value),
517                    _ => None,
518                }
519            }
520
521            fn property_kind_name() -> &'static str {
522                $kind
523            }
524        }
525    };
526}
527
528impl_deferred_literal!([u8; 4], "Color", Color, "Color");
529
530impl DeferredValue for vector::paint::Paint {
531    fn eval_deferred(
532        deferred: &Deferred<Self>,
533        node_id: NodeId,
534        property_path: &str,
535        _ctx: &crate::expr::ExpressionContext<'_>,
536    ) -> crate::Result<Self> {
537        match deferred {
538            Deferred::Value(value) => Ok(value.clone()),
539            Deferred::Expr(_) => Err(PropertyValue::invalid_type(
540                node_id,
541                property_path,
542                "Paint",
543                "expression",
544            )),
545        }
546    }
547
548    fn to_property_value(value: &Self) -> PropertyValue {
549        PropertyValue::Paint(value.clone())
550    }
551
552    fn from_property_value(value: PropertyValue) -> Option<Self> {
553        match value {
554            PropertyValue::Paint(value) => Some(value),
555            PropertyValue::Color(value) => Some(vector::paint::Paint::solid(value)),
556            _ => None,
557        }
558    }
559
560    fn property_kind_name() -> &'static str {
561        "Paint"
562    }
563}
564
565impl_deferred_literal!((f64, f64), "Vec2", Vec2, "Vec2");
566
567impl DeferredValue for [f32; 2] {
568    fn eval_deferred(
569        deferred: &Deferred<Self>,
570        node_id: NodeId,
571        property_path: &str,
572        _ctx: &crate::expr::ExpressionContext<'_>,
573    ) -> crate::Result<Self> {
574        match deferred {
575            Deferred::Value(value) => Ok(*value),
576            Deferred::Expr(_) => Err(PropertyValue::invalid_type(
577                node_id,
578                property_path,
579                "Vec2",
580                "expression",
581            )),
582        }
583    }
584
585    fn to_property_value(value: &Self) -> PropertyValue {
586        PropertyValue::Vec2((f64::from(value[0]), f64::from(value[1])))
587    }
588
589    fn from_property_value(value: PropertyValue) -> Option<Self> {
590        match value {
591            PropertyValue::Vec2((x, y)) => Some([x as f32, y as f32]),
592            _ => None,
593        }
594    }
595
596    fn property_kind_name() -> &'static str {
597        "Vec2"
598    }
599}
600
601#[cfg(feature = "json")]
602impl DeferredJsonValue for f64 {
603    fn from_json_value(value: &serde_json::Value) -> Result<Self, String> {
604        value
605            .as_f64()
606            .or_else(|| value.as_i64().map(|value| value as f64))
607            .ok_or_else(|| "expected float".to_string())
608    }
609}
610
611#[cfg(feature = "json")]
612impl DeferredJsonValue for f32 {
613    fn from_json_value(value: &serde_json::Value) -> Result<Self, String> {
614        f64::from_json_value(value).map(|value| value as f32)
615    }
616}
617
618#[cfg(feature = "json")]
619impl DeferredJsonValue for i64 {
620    fn from_json_value(value: &serde_json::Value) -> Result<Self, String> {
621        value
622            .as_i64()
623            .or_else(|| value.as_f64().map(|value| value as i64))
624            .ok_or_else(|| "expected int".to_string())
625    }
626}
627
628#[cfg(feature = "json")]
629impl DeferredJsonValue for u8 {
630    fn from_json_value(value: &serde_json::Value) -> Result<Self, String> {
631        let value = i64::from_json_value(value)?;
632        u8::try_from(value).map_err(|_| "expected u8".to_string())
633    }
634}
635
636#[cfg(feature = "json")]
637impl DeferredJsonValue for u32 {
638    fn from_json_value(value: &serde_json::Value) -> Result<Self, String> {
639        let value = i64::from_json_value(value)?;
640        u32::try_from(value).map_err(|_| "expected u32".to_string())
641    }
642}
643
644#[cfg(feature = "json")]
645impl DeferredJsonValue for bool {
646    fn from_json_value(value: &serde_json::Value) -> Result<Self, String> {
647        value
648            .as_bool()
649            .or_else(|| value.as_i64().map(|value| value != 0))
650            .ok_or_else(|| "expected bool".to_string())
651    }
652}
653
654#[cfg(feature = "json")]
655impl DeferredJsonValue for String {
656    fn from_json_value(value: &serde_json::Value) -> Result<Self, String> {
657        value
658            .as_str()
659            .map(ToString::to_string)
660            .ok_or_else(|| "expected string".to_string())
661    }
662}
663
664#[cfg(feature = "json")]
665impl DeferredJsonValue for [u8; 4] {
666    fn from_json_value(value: &serde_json::Value) -> Result<Self, String> {
667        crate::json::parse_color(value).ok_or_else(|| "expected color".to_string())
668    }
669}
670
671#[cfg(feature = "json")]
672impl DeferredJsonValue for vector::paint::Paint {
673    fn from_json_value(value: &serde_json::Value) -> Result<Self, String> {
674        vector::paint::Paint::from_json_value(value).ok_or_else(|| "expected paint".to_string())
675    }
676}
677
678#[cfg(feature = "json")]
679impl DeferredJsonValue for (f64, f64) {
680    fn from_json_value(value: &serde_json::Value) -> Result<Self, String> {
681        let values = value
682            .as_array()
683            .ok_or_else(|| "expected vec2".to_string())?;
684        if values.len() != 2 {
685            return Err(format!(
686                "expected vec2, got array of length {}",
687                values.len()
688            ));
689        }
690        let x = values[0]
691            .as_f64()
692            .ok_or_else(|| "expected vec2 x number".to_string())?;
693        let y = values[1]
694            .as_f64()
695            .ok_or_else(|| "expected vec2 y number".to_string())?;
696        Ok((x, y))
697    }
698}
699
700#[cfg(feature = "json")]
701impl DeferredJsonValue for [f32; 2] {
702    fn from_json_value(value: &serde_json::Value) -> Result<Self, String> {
703        let (x, y) = <(f64, f64)>::from_json_value(value)?;
704        Ok([x as f32, y as f32])
705    }
706}