pax_manifest/
lib.rs

1use std::borrow::Borrow;
2use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
3use std::fmt::Display;
4use std::hash::Hasher;
5use std::{cmp::Ordering, hash::Hash};
6
7pub use pax_lang::interpreter::{PaxExpression, PaxIdentifier, PaxPrimary};
8use pax_lang::DependencyCollector;
9use pax_message::serde::{Deserialize, Serialize};
10pub use pax_runtime_api;
11use pax_runtime_api::{CoercionRules, HelperFunctions, Interpolatable, PaxValue, ToPaxValue};
12pub mod parsing;
13pub mod server;
14
15#[cfg(feature = "parsing")]
16pub mod utils;
17
18pub mod cartridge_generation;
19pub mod code_serialization;
20pub mod constants;
21
22/// Definition container for an entire Pax cartridge
23#[serde_with::serde_as]
24#[derive(Serialize, Deserialize, Clone)]
25#[serde(crate = "pax_message::serde")]
26pub struct PaxManifest {
27    #[serde_as(as = "BTreeMap<serde_with::json::JsonString, _>")]
28    pub components: BTreeMap<TypeId, ComponentDefinition>,
29    pub main_component_type_id: TypeId,
30    #[serde_as(as = "HashMap<serde_with::json::JsonString, _>")]
31    pub type_table: TypeTable,
32    /// Compiler metadata: list of fully qualified asset directories, gathered during compiletime,
33    /// from which assets will be copied for bundling into executable binaries
34    pub assets_dirs: Vec<String>,
35    /// Compiler metadata: the import prefix for the engine module, `pax_kit::pax_engine` by default
36    /// but parameterizable for integrating with pax_engine directly, e.g. pax_std and pax_designer
37    pub engine_import_path: String,
38}
39
40impl PaxManifest {
41    pub fn is_designer(&self) -> bool {
42        if let Some(identifier) = self.main_component_type_id.get_pascal_identifier() {
43            return identifier == "PaxDesigner";
44        }
45        false
46    }
47
48    pub fn get_template_node(
49        &self,
50        uni: &UniqueTemplateNodeIdentifier,
51    ) -> Option<&TemplateNodeDefinition> {
52        self.components
53            .get(&uni.component)?
54            .template
55            .as_ref()?
56            .nodes
57            .get(&uni.template_node_id)
58    }
59
60    pub fn get_all_component_property_definitions(
61        &self,
62        type_id: &TypeId,
63    ) -> Vec<PropertyDefinition> {
64        if let None = self.components.get(type_id) {
65            return Vec::default();
66        }
67        let mut common_properties = get_common_properties_as_property_definitions();
68        common_properties.extend(
69            self.type_table
70                .get(type_id)
71                .map(|table| table.property_definitions.clone())
72                .unwrap_or_default(),
73        );
74        common_properties
75    }
76
77    pub fn get_node_location(&self, uni: &UniqueTemplateNodeIdentifier) -> Option<NodeLocation> {
78        self.components
79            .get(&uni.component)
80            .unwrap()
81            .template
82            .as_ref()
83            .unwrap()
84            .get_location(&uni.template_node_id)
85    }
86
87    pub fn get_all_property_names(&self, type_id: &TypeId) -> HashSet<String> {
88        let mut ret = HashSet::new();
89        self.get_all_component_property_definitions(type_id)
90            .iter()
91            .for_each(|prop| {
92                ret.insert(prop.name.clone());
93            });
94        ret
95    }
96
97    // String representing the symbolic ID for the &dyn PaxCartridge struct
98    // generated for this manifest's cartridge in #[main]
99    pub fn get_main_cartridge_struct_id(&self) -> String {
100        format!(
101            "{}{}",
102            &self.main_component_type_id.get_pascal_identifier().unwrap(),
103            crate::constants::CARTRIDGE_PARTIAL_STRUCT_ID
104        )
105    }
106
107    // String representing the symbolic ID for the &dyn DefinitionToInstanceTraverser struct
108    // generated for this manifest's cartridge in #[main]
109    pub fn get_main_definition_to_instance_traverser_struct_id(&self) -> String {
110        format!(
111            "{}{}",
112            &self.main_component_type_id.get_pascal_identifier().unwrap(),
113            crate::constants::DEFINITION_TO_INSTANCE_TRAVERSER_PARTIAL_STRUCT_ID
114        )
115    }
116
117    pub fn merge_in_place(&mut self, other: &PaxManifest) {
118        self.components.extend(other.components.clone());
119        self.type_table.extend(other.type_table.clone());
120        self.assets_dirs.extend(other.assets_dirs.clone());
121    }
122}
123
124pub fn get_common_properties_type_ids() -> Vec<TypeId> {
125    let mut ret = vec![];
126    for (_, import_path) in constants::COMMON_PROPERTIES_TYPE {
127        if SUPPORTED_NUMERIC_PRIMITIVES.contains(import_path)
128            || SUPPORTED_NONNUMERIC_PRIMITIVES.contains(import_path)
129        {
130            ret.push(TypeId::build_primitive(import_path));
131        } else {
132            ret.push(TypeId::build_singleton(import_path, None));
133        }
134    }
135    ret
136}
137
138pub fn get_common_properties_as_property_definitions() -> Vec<PropertyDefinition> {
139    let mut ret = vec![];
140    for (cp, import_path) in constants::COMMON_PROPERTIES_TYPE {
141        if SUPPORTED_NUMERIC_PRIMITIVES.contains(import_path)
142            || SUPPORTED_NONNUMERIC_PRIMITIVES.contains(import_path)
143        {
144            ret.push(PropertyDefinition {
145                name: cp.to_string(),
146                flags: Default::default(),
147                type_id: TypeId::build_primitive(import_path),
148            });
149        } else {
150            ret.push(PropertyDefinition {
151                name: cp.to_string(),
152                flags: Default::default(),
153                type_id: TypeId::build_singleton(import_path, None),
154            });
155        }
156    }
157    ret
158}
159
160pub const SUPPORTED_NUMERIC_PRIMITIVES: [&str; 13] = [
161    "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize", "f64",
162];
163
164pub const SUPPORTED_NONNUMERIC_PRIMITIVES: [&str; 2] = ["String", "bool"];
165
166/// Container for an entire component definition — includes template, settings,
167/// event bindings, property definitions, and compiler + reflection metadata
168#[derive(Serialize, Deserialize, Clone)]
169#[serde(crate = "pax_message::serde")]
170pub struct ComponentDefinition {
171    pub type_id: TypeId,
172    pub is_main_component: bool,
173    pub is_primitive: bool,
174
175    /// Flag describing whether this component definition is a "struct-only component", a
176    /// struct decorated with `#[pax]` for use as the `T` in `Property<T>`.
177    pub is_struct_only_component: bool,
178
179    pub module_path: String,
180
181    /// For primitives like Rectangle or Group, a separate import
182    /// path is required for the Instance (render context) struct
183    /// and the Definition struct.  For primitives, then, we need
184    /// to store an additional import path to use when instantiating.
185    pub primitive_instance_import_path: Option<String>,
186    pub template: Option<ComponentTemplate>,
187    pub settings: Option<Vec<SettingsBlockElement>>,
188}
189
190impl ComponentDefinition {
191    pub fn get_property_definitions<'a>(&self, tt: &'a TypeTable) -> &'a Vec<PropertyDefinition> {
192        &tt.get(&self.type_id).unwrap().property_definitions
193    }
194}
195
196#[derive(Serialize, Deserialize, Debug, Clone)]
197#[serde(crate = "pax_message::serde")]
198pub enum SettingsBlockElement {
199    SelectorBlock(Token, LiteralBlockDefinition),
200    Handler(Token, Vec<Token>),
201    Comment(String),
202}
203
204#[derive(Serialize, Default, Deserialize, Debug, Clone, Hash, PartialEq, Eq)]
205#[serde(crate = "pax_message::serde")]
206pub struct TemplateNodeId(usize);
207
208impl CoercionRules for TemplateNodeId {
209    fn try_coerce(value: PaxValue) -> Result<Self, String> {
210        match value {
211            PaxValue::Numeric(_) => Ok(TemplateNodeId(usize::try_coerce(value)?)),
212            _ => Err("Cannot coerce PaxValue into TemplateNodeId".to_string()),
213        }
214    }
215}
216
217impl HelperFunctions for TemplateNodeId {}
218
219impl ToPaxValue for TemplateNodeId {
220    fn to_pax_value(self) -> PaxValue {
221        self.0.to_pax_value()
222    }
223}
224
225impl TemplateNodeId {
226    pub fn build(id: usize) -> Self {
227        TemplateNodeId(id)
228    }
229
230    pub fn as_usize(&self) -> usize {
231        self.0
232    }
233}
234
235impl Display for TemplateNodeId {
236    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
237        write!(f, "{}", self.0)
238    }
239}
240
241#[derive(Serialize, Default, Deserialize, Debug, Clone, Hash, PartialEq, Eq)]
242#[serde(crate = "pax_message::serde")]
243pub enum PaxType {
244    If,
245    Slot,
246    Repeat,
247    Comment,
248    BlankComponent {
249        pascal_identifier: String,
250    },
251    Primitive {
252        pascal_identifier: String,
253    },
254    Singleton {
255        pascal_identifier: String,
256    },
257    Range {
258        identifier: String,
259    },
260    Option {
261        identifier: String,
262    },
263    Vector {
264        elem_identifier: String,
265    },
266    Map {
267        key_identifier: String,
268        value_identifier: String,
269    },
270    #[default]
271    Unknown,
272}
273
274impl HelperFunctions for PaxType {}
275
276impl CoercionRules for PaxType {
277    fn try_coerce(value: PaxValue) -> Result<Self, String> {
278        match value {
279            PaxValue::Enum(_name, variant, args) => match variant.as_str() {
280                "If" => Ok(PaxType::If),
281                "Slot" => Ok(PaxType::Slot),
282                "Repeat" => Ok(PaxType::Repeat),
283                "Comment" => Ok(PaxType::Comment),
284                "BlankComponent" => {
285                    let pascal_identifier = String::try_coerce(args[0].clone())?;
286                    Ok(PaxType::BlankComponent { pascal_identifier })
287                }
288                "Primitive" => {
289                    let pascal_identifier = String::try_coerce(args[0].clone())?;
290                    Ok(PaxType::Primitive { pascal_identifier })
291                }
292                "Singleton" => {
293                    let pascal_identifier = String::try_coerce(args[0].clone())?;
294                    Ok(PaxType::Singleton { pascal_identifier })
295                }
296                "Range" => {
297                    let identifier = String::try_coerce(args[0].clone())?;
298                    Ok(PaxType::Range { identifier })
299                }
300                "Option" => {
301                    let identifier = String::try_coerce(args[0].clone())?;
302                    Ok(PaxType::Option { identifier })
303                }
304                "Vector" => {
305                    let elem_identifier = String::try_coerce(args[0].clone())?;
306                    Ok(PaxType::Vector { elem_identifier })
307                }
308                "Map" => {
309                    let key_identifier = String::try_coerce(args[0].clone())?;
310                    let value_identifier = String::try_coerce(args[1].clone())?;
311                    Ok(PaxType::Map {
312                        key_identifier,
313                        value_identifier,
314                    })
315                }
316                _ => Ok(PaxType::Unknown),
317            },
318            _ => Err("Cannot coerce PaxValue into PaxType".to_string()),
319        }
320    }
321}
322
323impl ToPaxValue for PaxType {
324    fn to_pax_value(self) -> PaxValue {
325        match self {
326            PaxType::If => PaxValue::Enum("PaxType".to_string(), "If".to_string(), vec![]),
327            PaxType::Slot => PaxValue::Enum("PaxType".to_string(), "Slot".to_string(), vec![]),
328            PaxType::Repeat => PaxValue::Enum("PaxType".to_string(), "Repeat".to_string(), vec![]),
329            PaxType::Comment => {
330                PaxValue::Enum("PaxType".to_string(), "Comment".to_string(), vec![])
331            }
332            PaxType::BlankComponent { pascal_identifier } => PaxValue::Enum(
333                "PaxType".to_string(),
334                "BlankComponent".to_string(),
335                vec![pascal_identifier.to_pax_value()],
336            ),
337            PaxType::Primitive { pascal_identifier } => PaxValue::Enum(
338                "PaxType".to_string(),
339                "Primitive".to_string(),
340                vec![pascal_identifier.to_pax_value()],
341            ),
342            PaxType::Singleton { pascal_identifier } => PaxValue::Enum(
343                "PaxType".to_string(),
344                "Singleton".to_string(),
345                vec![pascal_identifier.to_pax_value()],
346            ),
347            PaxType::Range { identifier } => PaxValue::Enum(
348                "PaxType".to_string(),
349                "Range".to_string(),
350                vec![identifier.to_pax_value()],
351            ),
352            PaxType::Option { identifier } => PaxValue::Enum(
353                "PaxType".to_string(),
354                "Option".to_string(),
355                vec![identifier.to_pax_value()],
356            ),
357            PaxType::Vector { elem_identifier } => PaxValue::Enum(
358                "PaxType".to_string(),
359                "Vector".to_string(),
360                vec![elem_identifier.to_pax_value()],
361            ),
362            PaxType::Map {
363                key_identifier,
364                value_identifier,
365            } => PaxValue::Enum(
366                "PaxType".to_string(),
367                "Map".to_string(),
368                vec![
369                    key_identifier.to_pax_value(),
370                    value_identifier.to_pax_value(),
371                ],
372            ),
373            PaxType::Unknown => {
374                PaxValue::Enum("PaxType".to_string(), "Unknown".to_string(), vec![])
375            }
376        }
377    }
378}
379
380impl Display for PaxType {
381    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
382        match self {
383            PaxType::If => write!(f, "If"),
384            PaxType::Slot => write!(f, "Slot"),
385            PaxType::Repeat => write!(f, "Repeat"),
386            PaxType::Comment => write!(f, "Comment"),
387            PaxType::BlankComponent { pascal_identifier } => write!(f, "{}", pascal_identifier),
388            PaxType::Primitive { pascal_identifier } => write!(f, "{}", pascal_identifier),
389            PaxType::Singleton { pascal_identifier } => write!(f, "{}", pascal_identifier),
390            PaxType::Range { identifier } => write!(f, "std::ops::Range<{}>", identifier),
391            PaxType::Option { identifier } => write!(f, "std::option::Option<{}>", identifier),
392            PaxType::Vector { elem_identifier } => write!(f, "std::vec::Vec<{}>", elem_identifier),
393            PaxType::Map {
394                key_identifier,
395                value_identifier,
396            } => write!(
397                f,
398                "std::collections::HashMap<{}><{}>",
399                key_identifier, value_identifier
400            ),
401            PaxType::Unknown => write!(f, "Unknown"),
402        }
403    }
404}
405
406#[derive(Serialize, Default, Deserialize, Debug, Clone, Hash, PartialEq, Eq)]
407#[serde(crate = "pax_message::serde")]
408pub struct TypeId {
409    pax_type: PaxType,
410    import_path: Option<String>,
411    is_intoable_downstream_type: bool,
412
413    _type_id: String,
414    _type_id_escaped: String,
415}
416
417impl HelperFunctions for TypeId {}
418
419impl PartialOrd for TypeId {
420    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
421        self._type_id.partial_cmp(&other._type_id)
422    }
423}
424
425impl CoercionRules for TypeId {
426    fn try_coerce(value: PaxValue) -> Result<Self, String> {
427        match value {
428            PaxValue::Object(map) => {
429                let pax_type = PaxType::try_coerce(
430                    map.iter()
431                        .find_map(|(n, v)| (n == "pax_type").then_some(v))
432                        .unwrap()
433                        .clone(),
434                )?;
435                let import_path = map
436                    .iter()
437                    .find_map(|(n, v)| (n == "import_path").then_some(v))
438                    .map(|v| Option::<String>::try_coerce(v.clone()))
439                    .unwrap_or(Ok(None))?;
440                let is_intoable_downstream_type = map
441                    .iter()
442                    .find_map(|(n, v)| (n == "is_intoable_downstream_type").then_some(v))
443                    .map(|v| bool::try_coerce(v.clone()))
444                    .unwrap_or(Ok(false))?;
445                let _type_id = map
446                    .iter()
447                    .find_map(|(n, v)| (n == "_type_id").then_some(v))
448                    .map(|v| String::try_coerce(v.clone()))
449                    .unwrap_or(Ok("".to_string()))?;
450                let _type_id_escaped = map
451                    .iter()
452                    .find_map(|(n, v)| (n == "_type_id_escaped").then_some(v))
453                    .map(|v| String::try_coerce(v.clone()))
454                    .unwrap_or(Ok("".to_string()))?;
455                Ok(Self {
456                    pax_type,
457                    import_path,
458                    is_intoable_downstream_type,
459                    _type_id,
460                    _type_id_escaped,
461                })
462            }
463            _ => Err("Cannot coerce PaxValue into TypeId".to_string()),
464        }
465    }
466}
467
468impl ToPaxValue for TypeId {
469    fn to_pax_value(self) -> PaxValue {
470        let mut map = vec![];
471        map.push(("pax_type".to_string(), self.pax_type.to_pax_value()));
472        map.push(("import_path".to_string(), self.import_path.to_pax_value()));
473        map.push((
474            "is_intoable_downstream_type".to_string(),
475            self.is_intoable_downstream_type.to_pax_value(),
476        ));
477        map.push(("_type_id".to_string(), self._type_id.to_pax_value()));
478        map.push((
479            "_type_id_escaped".to_string(),
480            self._type_id_escaped.to_pax_value(),
481        ));
482        PaxValue::Object(map)
483    }
484}
485
486impl Ord for TypeId {
487    fn cmp(&self, other: &Self) -> Ordering {
488        self._type_id.cmp(&other._type_id)
489    }
490}
491
492impl Interpolatable for TypeId {}
493impl Interpolatable for TemplateNodeId {}
494
495impl Display for TypeId {
496    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
497        write!(f, "{}", self.get_unique_identifier())
498    }
499}
500
501impl TypeId {
502    pub fn build_if() -> Self {
503        TypeId {
504            pax_type: PaxType::If,
505            import_path: None,
506            is_intoable_downstream_type: false,
507            _type_id: "If".to_string(),
508            _type_id_escaped: "If".to_string(),
509        }
510    }
511
512    pub fn build_repeat() -> Self {
513        TypeId {
514            pax_type: PaxType::Repeat,
515            import_path: None,
516            is_intoable_downstream_type: false,
517            _type_id: "Repeat".to_string(),
518            _type_id_escaped: "Repeat".to_string(),
519        }
520    }
521
522    pub fn build_slot() -> Self {
523        TypeId {
524            pax_type: PaxType::Slot,
525            import_path: None,
526            is_intoable_downstream_type: false,
527            _type_id: "Slot".to_string(),
528            _type_id_escaped: "Slot".to_string(),
529        }
530    }
531
532    pub fn build_comment() -> Self {
533        TypeId {
534            pax_type: PaxType::Comment,
535            import_path: None,
536            is_intoable_downstream_type: false,
537            _type_id: "Comment".to_string(),
538            _type_id_escaped: "Comment".to_string(),
539        }
540    }
541
542    /// Build a typeid for a transient component
543    pub fn build_blank_component(pascal_identifier: &str) -> Self {
544        TypeId {
545            pax_type: PaxType::BlankComponent {
546                pascal_identifier: pascal_identifier.to_owned(),
547            },
548            import_path: None,
549            is_intoable_downstream_type: false,
550            _type_id: pascal_identifier.to_owned(),
551            _type_id_escaped: escape_identifier(pascal_identifier.to_owned()),
552        }
553    }
554
555    /// Build a TypeId for a most types, like `Stacker` or `SpecialComponent`
556    pub fn build_singleton(import_path: &str, pascal_identifier: Option<&str>) -> Self {
557        let pascal_identifier = if let Some(p) = pascal_identifier {
558            p.to_owned()
559        } else {
560            import_path.split("::").last().unwrap().to_string()
561        };
562
563        Self {
564            pax_type: PaxType::Singleton { pascal_identifier },
565            import_path: Some(import_path.to_owned()),
566            is_intoable_downstream_type: crate::constants::is_intoable_downstream_type(import_path),
567            _type_id: import_path.to_owned(),
568            _type_id_escaped: escape_identifier(import_path.to_owned()),
569        }
570    }
571
572    /// Build a TypeId for rust primitives like `u8` or `String`
573    pub fn build_primitive(identifier: &str) -> Self {
574        TypeId {
575            pax_type: PaxType::Primitive {
576                pascal_identifier: identifier.to_owned(),
577            },
578            import_path: None,
579            is_intoable_downstream_type: crate::constants::is_intoable_downstream_type(identifier),
580            _type_id: identifier.to_owned(),
581            _type_id_escaped: identifier.to_owned(),
582        }
583    }
584
585    /// Build a TypeId for vector types like `Vec<Color>`
586    pub fn build_vector(elem_identifier: &str) -> Self {
587        let _id = format!("std::vec::Vec<{}>", elem_identifier);
588        Self {
589            pax_type: PaxType::Vector {
590                elem_identifier: elem_identifier.to_owned(),
591            },
592            import_path: Some("std::vec::Vec".to_string()),
593            is_intoable_downstream_type: false,
594            _type_id: _id.clone(),
595            _type_id_escaped: escape_identifier(_id),
596        }
597    }
598
599    /// Build a TypeId for range types like `std::ops::Range<Color>`
600    pub fn build_range(identifier: &str) -> Self {
601        let _id = format!("std::ops::Range<{}>", identifier);
602        Self {
603            pax_type: PaxType::Range {
604                identifier: identifier.to_owned(),
605            },
606            import_path: Some("std::ops::Range".to_string()),
607            is_intoable_downstream_type: false,
608            _type_id: _id.clone(),
609            _type_id_escaped: escape_identifier(_id),
610        }
611    }
612
613    /// Build a TypeId for option types like `std::option::Option<Color>`
614    pub fn build_option(identifier: &str) -> Self {
615        let _id = format!("std::option::Option<{}>", identifier);
616        Self {
617            pax_type: PaxType::Option {
618                identifier: identifier.to_owned(),
619            },
620            import_path: Some("std::option::Option".to_string()),
621            is_intoable_downstream_type: false,
622            _type_id: _id.clone(),
623            _type_id_escaped: escape_identifier(_id),
624        }
625    }
626
627    /// Build a TypeId for map types like `std::collections::HashMap<String><Color>`
628    pub fn build_map(key_identifier: &str, value_identifier: &str) -> Self {
629        let _id = format!(
630            "std::collections::HashMap<{}><{}>",
631            key_identifier.to_owned(),
632            value_identifier.to_owned()
633        );
634        Self {
635            pax_type: PaxType::Map {
636                key_identifier: key_identifier.to_owned(),
637                value_identifier: value_identifier.to_owned(),
638            },
639            import_path: Some("std::collections::HashMap".to_string()),
640            is_intoable_downstream_type: false,
641            _type_id: _id.clone(),
642            _type_id_escaped: escape_identifier(_id),
643        }
644    }
645
646    pub fn import_path(&self) -> Option<String> {
647        if let PaxType::Primitive { pascal_identifier } = &self.pax_type {
648            return Some(pascal_identifier.clone());
649        }
650        self.import_path.clone()
651    }
652
653    pub fn get_pascal_identifier(&self) -> Option<String> {
654        match &self.pax_type {
655            PaxType::Primitive { pascal_identifier }
656            | PaxType::Singleton { pascal_identifier }
657            | PaxType::BlankComponent { pascal_identifier } => Some(pascal_identifier.clone()),
658            PaxType::If | PaxType::Slot | PaxType::Repeat | PaxType::Comment => {
659                Some(self.pax_type.to_string())
660            }
661            _ => None,
662        }
663    }
664
665    pub fn get_unique_identifier(&self) -> String {
666        self._type_id.clone()
667    }
668
669    pub fn get_pax_type(&self) -> &PaxType {
670        self.pax_type.borrow()
671    }
672
673    pub fn get_snake_case_id(&self) -> String {
674        self.get_unique_identifier()
675            .replace("::", "_")
676            .replace("/", "_")
677            .replace("\\", "_")
678            .replace(">", "_")
679            .replace("<", "_")
680            .replace(".", "_")
681    }
682
683    pub fn is_blank_component(&self) -> bool {
684        if let PaxType::BlankComponent { .. } = self.pax_type {
685            true
686        } else {
687            false
688        }
689    }
690}
691
692impl Interpolatable for UniqueTemplateNodeIdentifier {}
693
694#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq, Default)]
695#[serde(crate = "pax_message::serde")]
696pub struct UniqueTemplateNodeIdentifier {
697    component: TypeId,
698    template_node_id: TemplateNodeId,
699}
700
701impl UniqueTemplateNodeIdentifier {
702    pub fn build(component: TypeId, template_node_id: TemplateNodeId) -> Self {
703        UniqueTemplateNodeIdentifier {
704            component,
705            template_node_id,
706        }
707    }
708
709    pub fn get_containing_component_type_id(&self) -> TypeId {
710        self.component.clone()
711    }
712
713    pub fn get_template_node_id(&self) -> TemplateNodeId {
714        self.template_node_id.clone()
715    }
716}
717
718impl Display for UniqueTemplateNodeIdentifier {
719    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
720        write!(f, "({}, {})", self.component, self.template_node_id)
721    }
722}
723
724#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq)]
725pub enum TreeLocation {
726    #[default]
727    Root,
728    Parent(TemplateNodeId),
729}
730
731#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq)]
732pub enum TreeIndexPosition {
733    #[default]
734    Top,
735    Bottom,
736    At(usize),
737}
738
739impl TreeIndexPosition {
740    pub fn get_index(&self, len: usize) -> usize {
741        match self {
742            TreeIndexPosition::Top => 0,
743            TreeIndexPosition::Bottom => len,
744            TreeIndexPosition::At(index) => *index,
745        }
746    }
747
748    pub fn new(index: usize) -> Self {
749        TreeIndexPosition::At(index)
750    }
751}
752
753impl PartialOrd for TreeIndexPosition {
754    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
755        match self {
756            TreeIndexPosition::Top => match other {
757                TreeIndexPosition::Top => Some(Ordering::Equal),
758                TreeIndexPosition::Bottom => Some(Ordering::Less),
759                TreeIndexPosition::At(_) => Some(Ordering::Less),
760            },
761            TreeIndexPosition::Bottom => match other {
762                TreeIndexPosition::Top => Some(Ordering::Greater),
763                TreeIndexPosition::Bottom => Some(Ordering::Equal),
764                TreeIndexPosition::At(_) => Some(Ordering::Less),
765            },
766            TreeIndexPosition::At(index) => match other {
767                TreeIndexPosition::Top => Some(Ordering::Greater),
768                TreeIndexPosition::Bottom => Some(Ordering::Greater),
769                TreeIndexPosition::At(other_index) => index.partial_cmp(other_index),
770            },
771        }
772    }
773}
774
775impl Ord for TreeIndexPosition {
776    fn cmp(&self, other: &Self) -> Ordering {
777        self.partial_cmp(other).unwrap()
778    }
779}
780
781#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq)]
782pub struct NodeLocation {
783    pub type_id: TypeId,
784    pub tree_location: TreeLocation,
785    pub index: TreeIndexPosition,
786}
787
788impl NodeLocation {
789    pub fn new(type_id: TypeId, location: TreeLocation, index: TreeIndexPosition) -> Self {
790        NodeLocation {
791            type_id,
792            tree_location: location,
793            index,
794        }
795    }
796
797    pub fn get_tree_location(&self) -> &TreeLocation {
798        &self.tree_location
799    }
800
801    pub fn get_type_id(&self) -> &TypeId {
802        &self.type_id
803    }
804
805    pub fn root(type_id: TypeId) -> Self {
806        NodeLocation {
807            type_id,
808            tree_location: TreeLocation::Root,
809            index: TreeIndexPosition::Top,
810        }
811    }
812
813    pub fn parent(type_id: TypeId, parent: TemplateNodeId) -> Self {
814        NodeLocation {
815            type_id,
816            tree_location: TreeLocation::Parent(parent),
817            index: TreeIndexPosition::Top,
818        }
819    }
820
821    pub fn set_index(&mut self, index: TreeIndexPosition) {
822        self.index = index;
823    }
824}
825
826impl PartialOrd for NodeLocation {
827    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
828        match self.tree_location {
829            TreeLocation::Root => match other.tree_location {
830                TreeLocation::Root => {
831                    return self.index.partial_cmp(&other.index);
832                }
833                TreeLocation::Parent(_) => {
834                    return Some(Ordering::Less);
835                }
836            },
837            TreeLocation::Parent(_) => match other.tree_location {
838                TreeLocation::Root => {
839                    return Some(Ordering::Greater);
840                }
841                TreeLocation::Parent(_) => {
842                    return self.index.partial_cmp(&other.index);
843                }
844            },
845        }
846    }
847}
848
849impl Ord for NodeLocation {
850    fn cmp(&self, other: &Self) -> Ordering {
851        self.partial_cmp(other).unwrap()
852    }
853}
854
855#[serde_with::serde_as]
856#[derive(Serialize, Deserialize, Debug, Clone, Default)]
857#[serde(crate = "pax_message::serde")]
858pub struct ComponentTemplate {
859    containing_component: TypeId,
860    root: VecDeque<TemplateNodeId>,
861    #[serde_as(as = "HashMap<serde_with::json::JsonString, _>")]
862    children: HashMap<TemplateNodeId, VecDeque<TemplateNodeId>>,
863    #[serde_as(as = "HashMap<serde_with::json::JsonString, _>")]
864    nodes: HashMap<TemplateNodeId, TemplateNodeDefinition>,
865    next_id: usize,
866    template_source_file_path: Option<String>,
867}
868
869impl ComponentTemplate {
870    pub fn new(containing_component: TypeId, template_source_file_path: Option<String>) -> Self {
871        Self {
872            containing_component,
873            root: VecDeque::new(),
874            children: HashMap::new(),
875            nodes: HashMap::new(),
876            next_id: 0,
877            template_source_file_path,
878        }
879    }
880
881    pub fn get_containing_component_type_id(&self) -> TypeId {
882        self.containing_component.clone()
883    }
884
885    pub fn get_next_id(&self) -> usize {
886        self.next_id
887    }
888
889    pub fn set_next_id(&mut self, id: usize) {
890        self.next_id = id;
891    }
892
893    pub fn get_file_path(&self) -> Option<String> {
894        self.template_source_file_path.clone()
895    }
896
897    pub fn get_unique_identifier(&self, id: TemplateNodeId) -> UniqueTemplateNodeIdentifier {
898        let type_id = self.containing_component.clone();
899        UniqueTemplateNodeIdentifier::build(type_id, id)
900    }
901
902    pub fn contains_slots(&self) -> bool {
903        self.nodes
904            .values()
905            .any(|v| v.type_id.pax_type == PaxType::Slot)
906    }
907
908    fn consume_next_id(&mut self) -> TemplateNodeId {
909        let current_next_id = self.next_id;
910        self.next_id = self.next_id + 1;
911        TemplateNodeId::build(current_next_id)
912    }
913
914    pub fn add_at(
915        &mut self,
916        tnd: TemplateNodeDefinition,
917        location: NodeLocation,
918    ) -> UniqueTemplateNodeIdentifier {
919        match location.get_tree_location() {
920            TreeLocation::Root => match location.index {
921                TreeIndexPosition::Top => {
922                    return self.add_root_node_front(tnd);
923                }
924                TreeIndexPosition::Bottom => {
925                    return self.add_root_node_back(tnd);
926                }
927                TreeIndexPosition::At(index) => {
928                    return self.add_root_node_at(index, tnd);
929                }
930            },
931            TreeLocation::Parent(p) => match location.index {
932                TreeIndexPosition::Top => {
933                    return self.add_child_front(p.clone(), tnd);
934                }
935                TreeIndexPosition::Bottom => {
936                    return self.add_child_back(p.clone(), tnd);
937                }
938                TreeIndexPosition::At(index) => {
939                    return self.add_child_at(p.clone(), index, tnd);
940                }
941            },
942        }
943    }
944
945    pub fn add_root_node_front(
946        &mut self,
947        tnd: TemplateNodeDefinition,
948    ) -> UniqueTemplateNodeIdentifier {
949        let id = self.consume_next_id();
950        self.root.push_front(id.clone());
951        self.nodes.insert(id.clone(), tnd);
952        self.get_unique_identifier(id)
953    }
954
955    pub fn add_root_node_back(
956        &mut self,
957        tnd: TemplateNodeDefinition,
958    ) -> UniqueTemplateNodeIdentifier {
959        let id = self.consume_next_id();
960        self.root.push_back(id.clone());
961        self.nodes.insert(id.clone(), tnd);
962        self.get_unique_identifier(id)
963    }
964
965    pub fn add_root_node_at(
966        &mut self,
967        index: usize,
968        tnd: TemplateNodeDefinition,
969    ) -> UniqueTemplateNodeIdentifier {
970        let id = self.consume_next_id();
971        self.root.insert(index, id.clone());
972        self.children
973            .entry(id.clone())
974            .or_insert_with(VecDeque::new);
975        self.nodes.insert(id.clone(), tnd);
976        self.get_unique_identifier(id)
977    }
978
979    pub fn add(&mut self, tnd: TemplateNodeDefinition) -> UniqueTemplateNodeIdentifier {
980        self.add_root_node_front(tnd)
981    }
982
983    pub fn add_child_front(
984        &mut self,
985        id: TemplateNodeId,
986        tnd: TemplateNodeDefinition,
987    ) -> UniqueTemplateNodeIdentifier {
988        if let Some(_) = self.nodes.get_mut(&id) {
989            let child_id = self.consume_next_id();
990            if let Some(children) = self.children.get_mut(&id) {
991                children.push_front(child_id.clone());
992                self.nodes.insert(child_id.clone(), tnd);
993            } else {
994                let mut children = VecDeque::new();
995                children.push_front(child_id.clone());
996                self.nodes.insert(child_id.clone(), tnd);
997                self.children.insert(id, children);
998            }
999            self.get_unique_identifier(child_id)
1000        } else {
1001            panic!("Invalid parent");
1002        }
1003    }
1004
1005    pub fn add_child_back(
1006        &mut self,
1007        id: TemplateNodeId,
1008        tnd: TemplateNodeDefinition,
1009    ) -> UniqueTemplateNodeIdentifier {
1010        if let Some(_) = self.nodes.get_mut(&id) {
1011            let child_id = self.consume_next_id();
1012            if let Some(children) = self.children.get_mut(&id) {
1013                children.push_back(child_id.clone());
1014                self.nodes.insert(child_id.clone(), tnd);
1015            } else {
1016                let mut children = VecDeque::new();
1017                children.push_back(child_id.clone());
1018                self.nodes.insert(child_id.clone(), tnd);
1019                self.children.insert(id, children);
1020            }
1021            self.get_unique_identifier(child_id)
1022        } else {
1023            panic!("Invalid parent");
1024        }
1025    }
1026
1027    pub fn add_child_at(
1028        &mut self,
1029        id: TemplateNodeId,
1030        index: usize,
1031        tnd: TemplateNodeDefinition,
1032    ) -> UniqueTemplateNodeIdentifier {
1033        if let Some(_) = self.nodes.get_mut(&id) {
1034            let child_id = self.consume_next_id();
1035            if let Some(children) = self.children.get_mut(&id) {
1036                children.insert(index, child_id.clone());
1037                self.nodes.insert(child_id.clone(), tnd);
1038            } else {
1039                let mut children = VecDeque::new();
1040                children.insert(index, child_id.clone());
1041                self.nodes.insert(child_id.clone(), tnd);
1042                self.children.insert(id, children);
1043            }
1044            self.get_unique_identifier(child_id)
1045        } else {
1046            panic!("Invalid parent");
1047        }
1048    }
1049
1050    pub fn add_child(
1051        &mut self,
1052        id: TemplateNodeId,
1053        tnd: TemplateNodeDefinition,
1054    ) -> UniqueTemplateNodeIdentifier {
1055        self.add_child_front(id, tnd)
1056    }
1057
1058    pub fn remove_node(&mut self, id: TemplateNodeId) -> TemplateNodeDefinition {
1059        if let Some(tnd) = self.nodes.get(&id) {
1060            let node = tnd.clone();
1061            let subtree = self.get_subtree(&id);
1062            for node in subtree {
1063                self.nodes.remove(&node);
1064                self.children.remove(&node);
1065                for (_, children) in self.children.iter_mut() {
1066                    children.retain(|child| *child != node);
1067                }
1068            }
1069            self.nodes.remove(&id);
1070            self.children.remove(&id);
1071            for c in self.children.values_mut() {
1072                c.retain(|v| v != &id);
1073            }
1074            self.root.retain(|child| *child != id);
1075            node
1076        } else {
1077            panic!("Requested node doesn't exist in template");
1078        }
1079    }
1080
1081    fn get_subtree(&self, id: &TemplateNodeId) -> Vec<TemplateNodeId> {
1082        let mut ret = vec![];
1083        if let Some(children) = self.children.get(&id) {
1084            for child in children {
1085                ret.push(child.clone());
1086                ret.extend(self.get_subtree(child));
1087            }
1088        }
1089        ret
1090    }
1091
1092    pub fn get_root(&self) -> Vec<TemplateNodeId> {
1093        self.root.clone().into()
1094    }
1095
1096    pub fn get_children(&self, id: &TemplateNodeId) -> Option<Vec<TemplateNodeId>> {
1097        if let Some(c) = self.children.get(&id) {
1098            return Some(c.clone().into());
1099        }
1100        None
1101    }
1102
1103    pub fn get_parent(&self, id: &TemplateNodeId) -> Option<TemplateNodeId> {
1104        if self.root.contains(id) {
1105            return None;
1106        }
1107        self.children
1108            .iter()
1109            .find_map(|(n_id, child_ids)| child_ids.contains(&id).then_some(n_id).cloned())
1110    }
1111
1112    pub fn get_node(&self, id: &TemplateNodeId) -> Option<&TemplateNodeDefinition> {
1113        self.nodes.get(id)
1114    }
1115
1116    pub fn set_node(&mut self, id: TemplateNodeId, tnd: TemplateNodeDefinition) {
1117        self.nodes.insert(id, tnd);
1118    }
1119
1120    pub fn update_node_type_id(&mut self, id: &TemplateNodeId, new_type: &TypeId) {
1121        if let Some(node) = self.nodes.get_mut(id) {
1122            node.type_id = new_type.clone();
1123        }
1124    }
1125
1126    pub fn update_node_properties(
1127        &mut self,
1128        id: &TemplateNodeId,
1129        mut properties: HashMap<Token, Option<ValueDefinition>>,
1130    ) {
1131        if let Some(node) = self.nodes.get_mut(id) {
1132            if let Some(settings) = &mut node.settings {
1133                let mut indexes_to_remove: Vec<usize> = vec![];
1134                for (i, setting) in settings.iter_mut().enumerate() {
1135                    if let SettingElement::Setting(key, v) = setting {
1136                        if let Some(new_value) = properties.remove(key) {
1137                            if let Some(updated) = new_value {
1138                                *v = updated;
1139                            } else {
1140                                indexes_to_remove.push(i);
1141                            }
1142                        }
1143                    }
1144                }
1145
1146                // Remove propertiest that have been set to None
1147                for i in indexes_to_remove.iter().rev() {
1148                    settings.remove(*i);
1149                }
1150            } else {
1151                node.settings = Some(vec![]);
1152            }
1153        }
1154        // Add remaining (aka new properties) to settings
1155        for (k, v) in properties.iter() {
1156            if let Some(node) = self.nodes.get_mut(id) {
1157                if let Some(settings) = &mut node.settings {
1158                    if let Some(value) = v {
1159                        settings.push(SettingElement::Setting(k.clone(), value.clone()));
1160                    }
1161                }
1162            }
1163        }
1164    }
1165
1166    pub fn update_classes(&mut self, id: &TemplateNodeId, classes: HashMap<String, bool>) {
1167        if let Some(node) = self.nodes.get_mut(id) {
1168            if let Some(settings) = &mut node.settings {
1169                let mut indexes_to_remove: Vec<usize> = vec![];
1170                for (i, setting) in settings.iter_mut().enumerate() {
1171                    if let SettingElement::Setting(key, value) = setting {
1172                        if &key.token_value == "class" {
1173                            if let ValueDefinition::Identifier(value) = value {
1174                                if !*classes.get(&format!(".{}", value.name)).unwrap_or(&true) {
1175                                    indexes_to_remove.push(i);
1176                                }
1177                            }
1178                        }
1179                        if &key.token_value == "id" {
1180                            if let ValueDefinition::Identifier(value) = value {
1181                                if !*classes.get(&format!("#{}", value.name)).unwrap_or(&true) {
1182                                    indexes_to_remove.push(i);
1183                                }
1184                            }
1185                        }
1186                    }
1187                }
1188                // Remove classes that have been set to None
1189                for i in indexes_to_remove.iter().rev() {
1190                    settings.remove(*i);
1191                }
1192            } else {
1193                node.settings = Some(vec![]);
1194            }
1195        }
1196        // Add new classes to settings
1197        for (k, v) in classes.iter() {
1198            if let Some(node) = self.nodes.get_mut(id) {
1199                if let Some(settings) = &mut node.settings {
1200                    if *v {
1201                        let is_class = k.starts_with('.');
1202                        let key = if is_class { "class" } else { "id" }.to_string();
1203                        settings.push(SettingElement::Setting(
1204                            Token::new_without_location(key),
1205                            ValueDefinition::Identifier(PaxIdentifier {
1206                                name: k
1207                                    .trim_start_matches('.')
1208                                    .trim_start_matches('#')
1209                                    .to_string(),
1210                            }),
1211                        ));
1212                    }
1213                }
1214            }
1215        }
1216    }
1217
1218    pub fn update_control_flow_properties(
1219        &mut self,
1220        id: &TemplateNodeId,
1221        repeat_predicate_definition: Option<Option<ControlFlowRepeatPredicateDefinition>>,
1222        repeat_source_expression: Option<Option<ExpressionInfo>>,
1223        conditional_expression: Option<Option<ExpressionInfo>>,
1224        slot_index_expression: Option<Option<ExpressionInfo>>,
1225    ) {
1226        let Some(control_flow_settings) = self
1227            .nodes
1228            .get_mut(id)
1229            .and_then(|n| n.control_flow_settings.as_mut())
1230        else {
1231            return;
1232        };
1233        if let Some(value) = repeat_predicate_definition {
1234            control_flow_settings.repeat_predicate_definition = value;
1235        }
1236        if let Some(value) = repeat_source_expression {
1237            control_flow_settings.repeat_source_expression = value;
1238        }
1239        if let Some(value) = conditional_expression {
1240            control_flow_settings.condition_expression = value;
1241        }
1242        if let Some(value) = slot_index_expression {
1243            control_flow_settings.slot_index_expression = value;
1244        }
1245    }
1246
1247    pub fn find_node_with_str_id(&self, id: &str) -> Option<&TemplateNodeId> {
1248        for (i, n) in &self.nodes {
1249            if let Some(settings) = &n.settings {
1250                for setting in settings {
1251                    if let SettingElement::Setting(setting, value) = setting {
1252                        if setting.token_value == "id" {
1253                            if let ValueDefinition::LiteralValue(val) = value {
1254                                if let PaxValue::String(val_id) = val {
1255                                    if id == val_id {
1256                                        return Some(i);
1257                                    }
1258                                };
1259                            }
1260                        }
1261                    }
1262                }
1263            }
1264        }
1265        None
1266    }
1267
1268    pub fn get_nodes(&self) -> Vec<&TemplateNodeDefinition> {
1269        self.nodes.values().collect()
1270    }
1271
1272    pub fn get_nodes_mut(&mut self) -> Vec<&mut TemplateNodeDefinition> {
1273        self.nodes.values_mut().collect()
1274    }
1275
1276    pub fn get_nodes_owned(&self) -> Vec<TemplateNodeDefinition> {
1277        self.nodes.values().map(|x| x.clone()).collect()
1278    }
1279
1280    pub fn get_ids(&self) -> Vec<&TemplateNodeId> {
1281        self.nodes.keys().collect()
1282    }
1283
1284    pub fn get_location(&self, id: &TemplateNodeId) -> Option<NodeLocation> {
1285        if self.root.contains(&id) {
1286            let mut node_location = NodeLocation::root(self.containing_component.clone());
1287            node_location.set_index(TreeIndexPosition::new(
1288                self.root.iter().position(|x| *x == *id).unwrap(),
1289            ));
1290            return Some(node_location);
1291        }
1292        for (parent, children) in self.children.iter() {
1293            if children.contains(&id) {
1294                let mut node_location =
1295                    NodeLocation::parent(self.containing_component.clone(), parent.clone());
1296                node_location.set_index(TreeIndexPosition::new(
1297                    children.iter().position(|x| *x == *id).unwrap(),
1298                ));
1299                return Some(node_location);
1300            }
1301        }
1302        None
1303    }
1304
1305    pub fn detach_node(&mut self, id: &TemplateNodeId) -> NodeLocation {
1306        let current_location = self
1307            .get_location(id)
1308            .expect("Node doesn't exist in template");
1309        let parent = match current_location.get_tree_location() {
1310            TreeLocation::Root => {
1311                self.root.retain(|root_node| *root_node != *id);
1312                return current_location;
1313            }
1314            TreeLocation::Parent(parent) => parent,
1315        };
1316        let children = self.children.get_mut(&parent).unwrap();
1317        children.retain(|child| *child != *id);
1318        current_location
1319    }
1320
1321    pub fn get_siblings(&self, id: &TemplateNodeId) -> Option<VecDeque<TemplateNodeId>> {
1322        if self.root.contains(id) {
1323            Some(self.root.clone())
1324        } else {
1325            Some(self.children.values().find(|&v| v.contains(id)).cloned()?)
1326        }
1327    }
1328
1329    pub fn move_node(&mut self, id: &TemplateNodeId, new_location: NodeLocation) {
1330        self.detach_node(id);
1331        let (target_list, index) = match new_location.get_tree_location() {
1332            TreeLocation::Root => (&mut self.root, new_location.index),
1333            TreeLocation::Parent(p) => (
1334                self.children.entry(p.clone()).or_default(),
1335                new_location.index,
1336            ),
1337        };
1338        let index = match index {
1339            TreeIndexPosition::Top => 0,
1340            TreeIndexPosition::Bottom => target_list.len(),
1341            TreeIndexPosition::At(i) => i,
1342        };
1343        target_list.insert(index.clamp(0, target_list.len()), id.clone());
1344    }
1345
1346    pub fn get_all_children_relationships(
1347        &self,
1348    ) -> HashMap<TemplateNodeId, VecDeque<TemplateNodeId>> {
1349        self.children.clone()
1350    }
1351
1352    pub fn merge_with_settings(&mut self, settings_block: &Option<Vec<SettingsBlockElement>>) {
1353        for node in self.get_nodes_mut() {
1354            node.settings = PaxManifest::merge_inline_settings_with_settings_block(
1355                &mut node.settings,
1356                settings_block,
1357            );
1358        }
1359    }
1360}
1361
1362/// Represents an entry within a component template, e.g. a <Rectangle> declaration inside a template
1363/// Each node in a template is represented by exactly one `TemplateNodeDefinition`, and this is a compile-time
1364/// concern.  Note the difference between compile-time `definitions` and runtime `instances`.
1365/// A compile-time `TemplateNodeDefinition` corresponds to a single runtime `RenderNode` instance.
1366#[derive(Serialize, Deserialize, Default, Debug, Clone)]
1367#[serde(crate = "pax_message::serde")]
1368pub struct TemplateNodeDefinition {
1369    /// Reference to the unique string ID for a component, e.g. `primitive::Frame` or `component::Stacker`
1370    pub type_id: TypeId,
1371    /// Iff this TND is a control-flow node: parsed control flow attributes (slot/if/for)
1372    pub control_flow_settings: Option<ControlFlowSettingsDefinition>,
1373    /// IFF this TND is NOT a control-flow node: parsed key-value store of attribute definitions (like `some_key="some_value"`)
1374    pub settings: Option<Vec<SettingElement>>,
1375    /// IFF this TND is a comment node: raw comment string
1376    pub raw_comment_string: Option<String>,
1377}
1378
1379impl TemplateNodeDefinition {
1380    pub fn get_node_type(&self) -> NodeType {
1381        if let Some(cfsd) = &self.control_flow_settings {
1382            NodeType::ControlFlow(Box::new(cfsd.clone()))
1383        } else if let Some(settings) = &self.settings {
1384            NodeType::Template(settings.clone())
1385        } else if let Some(comment) = &self.raw_comment_string {
1386            NodeType::Comment(comment.clone())
1387        } else {
1388            panic!("Invalid TemplateNodeDefinition");
1389        }
1390    }
1391}
1392
1393#[derive(Serialize, Deserialize, Clone, Debug)]
1394pub enum NodeType {
1395    Template(Vec<SettingElement>),
1396    ControlFlow(Box<ControlFlowSettingsDefinition>),
1397    Comment(String),
1398}
1399
1400pub type TypeTable = HashMap<TypeId, TypeDefinition>;
1401pub fn get_primitive_type_table() -> TypeTable {
1402    let mut ret: TypeTable = Default::default();
1403
1404    SUPPORTED_NUMERIC_PRIMITIVES.into_iter().for_each(|snp| {
1405        ret.insert(TypeId::build_primitive(snp), TypeDefinition::primitive(snp));
1406    });
1407    SUPPORTED_NONNUMERIC_PRIMITIVES
1408        .into_iter()
1409        .for_each(|snnp| {
1410            ret.insert(
1411                TypeId::build_primitive(snnp),
1412                TypeDefinition::primitive(snnp),
1413            );
1414        });
1415
1416    ret
1417}
1418
1419#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1420#[serde(crate = "pax_message::serde")]
1421pub struct PropertyDefinition {
1422    /// String representation of the symbolic identifier of a declared Property
1423    pub name: String,
1424
1425    /// Flags, used ultimately by ExpressionSpecInvocations, to denote
1426    /// e.g. whether a property is the `i` or `elem` of a `Repeat`, which allows
1427    /// for special-handling the RIL that invokes these values
1428    pub flags: PropertyDefinitionFlags,
1429
1430    /// Statically known type_id for this Property's associated TypeDefinition
1431    pub type_id: TypeId,
1432}
1433
1434impl PropertyDefinition {
1435    pub fn get_type_definition<'a>(&'a self, tt: &'a TypeTable) -> &TypeDefinition {
1436        if let None = tt.get(&self.type_id) {
1437            panic!("TypeTable does not contain type_id: {}", &self.type_id);
1438        }
1439        tt.get(&self.type_id).unwrap()
1440    }
1441
1442    pub fn get_inner_iterable_type_definition<'a>(
1443        &'a self,
1444        tt: &'a TypeTable,
1445    ) -> Option<&TypeDefinition> {
1446        if let Some(ref iiti) = tt.get(&self.type_id).unwrap().inner_iterable_type_id {
1447            Some(tt.get(iiti).unwrap())
1448        } else {
1449            None
1450        }
1451    }
1452}
1453
1454/// These flags describe the aspects of properties that affect RIL codegen.
1455/// Properties are divided into modal axes (exactly one value should be true per axis per struct instance)
1456/// Codegen considers each element of the cartesian product of these axes
1457#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1458#[serde(crate = "pax_message::serde")]
1459pub struct PropertyDefinitionFlags {
1460    // // //
1461    // Binding axis
1462    //
1463    /// Does this property represent the index `i` in `for (elem, i)` ?
1464    pub is_binding_repeat_i: bool,
1465    /// Does this property represent `elem` in `for (elem, i)` OR `for elem in 0..5` ?
1466    pub is_binding_repeat_elem: bool,
1467
1468    // // //
1469    // Source axis
1470    //
1471    /// Is the source being iterated over a Range?
1472    pub is_repeat_source_range: bool,
1473    /// Is the source being iterated over an iterable, like Vec<T>?
1474    pub is_repeat_source_iterable: bool,
1475
1476    /// Describes whether this property is a `Property`-wrapped `T` in `Property<T>`
1477    /// This distinction affects our ability to dirty-watch a particular property, and
1478    /// has implications on codegen
1479    pub is_property_wrapped: bool,
1480
1481    /// Describes whether this property is an enum variant property
1482    pub is_enum: bool,
1483}
1484
1485/// Describes static metadata surrounding a property, for example
1486/// the string representation of the property's name and a `TypeInfo`
1487/// entry for the property's statically discovered type
1488impl PropertyDefinition {
1489    /// Shorthand factory / constructor
1490    pub fn primitive_with_name(type_name: &str, symbol_name: &str) -> Self {
1491        PropertyDefinition {
1492            name: symbol_name.to_string(),
1493            flags: PropertyDefinitionFlags::default(),
1494            type_id: TypeId::build_primitive(type_name),
1495        }
1496    }
1497}
1498
1499/// Describes metadata surrounding a property's type, gathered from a combination of static & dynamic analysis
1500#[derive(Serialize, Deserialize, Clone, Default)]
1501#[serde(crate = "pax_message::serde")]
1502pub struct TypeDefinition {
1503    /// Program-unique ID for this type
1504    pub type_id: TypeId,
1505
1506    /// Statically known type_id for this Property's iterable TypeDefinition, that is,
1507    /// T for some Property<Vec<T>>
1508    pub inner_iterable_type_id: Option<TypeId>,
1509
1510    /// A vec of PropertyType, describing known addressable (sub-)properties of this PropertyType
1511    pub property_definitions: Vec<PropertyDefinition>,
1512}
1513
1514impl TypeDefinition {
1515    pub fn primitive(type_name: &str) -> Self {
1516        Self {
1517            type_id: TypeId::build_primitive(type_name),
1518            property_definitions: vec![],
1519            inner_iterable_type_id: None,
1520        }
1521    }
1522
1523    ///Used by Repeat for source expressions, e.g. the `self.some_vec` in `for elem in self.some_vec`
1524    pub fn builtin_vec_rc_ref_cell_any_properties(inner_iterable_type_id: TypeId) -> Self {
1525        Self {
1526            type_id: TypeId::build_vector("std::rc::Rc<core::cell::RefCell<PaxAny>>"),
1527            property_definitions: vec![],
1528            inner_iterable_type_id: Some(inner_iterable_type_id),
1529        }
1530    }
1531
1532    pub fn builtin_range_isize() -> Self {
1533        Self {
1534            type_id: TypeId::build_range("isize"),
1535            property_definitions: vec![],
1536            inner_iterable_type_id: Some(TypeId::build_primitive("isize")),
1537        }
1538    }
1539}
1540
1541#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)]
1542pub struct ExpressionCompilationInfo {
1543    pub vtable_id: usize,
1544    /// symbols used in the expression
1545    pub dependencies: Vec<String>,
1546}
1547
1548/// Container for settings values, storing all possible
1549/// variants, populated at parse-time and used at compile-time
1550#[derive(Serialize, Deserialize, Default, Debug, Clone)]
1551#[serde(crate = "pax_message::serde")]
1552pub enum ValueDefinition {
1553    #[default]
1554    Undefined, //Used for `Default`
1555    LiteralValue(PaxValue),
1556    Block(LiteralBlockDefinition),
1557    /// (Expression contents, vtable id binding)
1558    Expression(ExpressionInfo),
1559    /// (Expression contents, vtable id binding)
1560    Identifier(PaxIdentifier),
1561    /// (Expression contents, vtable id binding)
1562    DoubleBinding(PaxIdentifier),
1563    EventBindingTarget(PaxIdentifier),
1564}
1565
1566impl Display for ValueDefinition {
1567    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1568        match self {
1569            ValueDefinition::Undefined => write!(f, "<undefined>"),
1570            ValueDefinition::LiteralValue(value) => write!(f, "{}", value),
1571            ValueDefinition::Block(block) => write!(f, "{}", block),
1572            ValueDefinition::Expression(e) => write!(f, "{{{}}}", e.expression),
1573            ValueDefinition::Identifier(i) => write!(f, "{}", i),
1574            ValueDefinition::DoubleBinding(ident) => {
1575                write!(f, "bind:{}", ident)
1576            }
1577            ValueDefinition::EventBindingTarget(ident) => {
1578                write!(f, "@<event-binding>={}", ident)
1579            }
1580        }
1581    }
1582}
1583
1584/// Container for holding metadata about original Location in Pax Template
1585/// Used for source-mapping
1586#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
1587#[serde(crate = "pax_message::serde")]
1588pub struct LocationInfo {
1589    pub start_line_col: (usize, usize),
1590    pub end_line_col: (usize, usize),
1591}
1592
1593/// Container for holding parsed data describing a Repeat (`for`)
1594/// predicate, for example the `(elem, i)` in `for (elem, i) in foo` or
1595/// the `elem` in `for elem in foo`
1596#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
1597#[serde(crate = "pax_message::serde")]
1598pub enum ControlFlowRepeatPredicateDefinition {
1599    ElemId(String),
1600    ElemIdIndexId(String, String),
1601}
1602
1603impl ControlFlowRepeatPredicateDefinition {
1604    pub fn get_symbols(&self) -> HashSet<String> {
1605        match self {
1606            ControlFlowRepeatPredicateDefinition::ElemId(t) => {
1607                vec![t.clone()].into_iter().collect()
1608            }
1609            ControlFlowRepeatPredicateDefinition::ElemIdIndexId(t1, t2) => {
1610                vec![t1.clone(), t2.clone()].into_iter().collect()
1611            }
1612        }
1613    }
1614}
1615
1616/// Container for storing parsed control flow information, for
1617/// example the string (PAXEL) representations of condition / slot / repeat
1618/// expressions and the related vtable ids (for "punching" during expression compilation)
1619#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1620#[serde(crate = "pax_message::serde")]
1621pub struct ControlFlowSettingsDefinition {
1622    pub condition_expression: Option<ExpressionInfo>,
1623    pub slot_index_expression: Option<ExpressionInfo>,
1624    pub repeat_predicate_definition: Option<ControlFlowRepeatPredicateDefinition>,
1625    pub repeat_source_expression: Option<ExpressionInfo>,
1626}
1627
1628#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1629#[serde(crate = "pax_message::serde")]
1630pub struct ExpressionInfo {
1631    pub expression: PaxExpression,
1632    pub dependencies: Vec<String>,
1633}
1634
1635impl Display for ExpressionInfo {
1636    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1637        write!(f, "{}", self.expression)
1638    }
1639}
1640
1641impl ExpressionInfo {
1642    pub fn new(expr: PaxExpression) -> Self {
1643        Self {
1644            dependencies: expr.collect_dependencies(),
1645            expression: expr,
1646        }
1647    }
1648}
1649
1650/// Container for a parsed Literal object
1651#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1652#[serde(crate = "pax_message::serde")]
1653pub struct LiteralBlockDefinition {
1654    pub explicit_type_pascal_identifier: Option<Token>,
1655    pub elements: Vec<SettingElement>,
1656}
1657
1658impl Display for LiteralBlockDefinition {
1659    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1660        let elements = &self.elements;
1661        write!(f, "{{")?;
1662        for e in elements {
1663            match e {
1664                SettingElement::Setting(Token { token_value, .. }, value) => {
1665                    write!(f, "{}: {} ", token_value, value)?;
1666                }
1667                SettingElement::Comment(_) => (),
1668            }
1669        }
1670        write!(f, "}}")?;
1671        Ok(())
1672    }
1673}
1674
1675impl LiteralBlockDefinition {
1676    pub fn new(elements: Vec<SettingElement>) -> Self {
1677        Self {
1678            explicit_type_pascal_identifier: None,
1679            elements,
1680        }
1681    }
1682}
1683
1684#[derive(Serialize, Deserialize, Debug, Clone)]
1685#[serde(crate = "pax_message::serde")]
1686pub enum SettingElement {
1687    Setting(Token, ValueDefinition),
1688    Comment(String),
1689}
1690
1691impl LiteralBlockDefinition {
1692    pub fn get_all_settings<'a>(&'a self) -> Vec<(&'a Token, &'a ValueDefinition)> {
1693        self.elements
1694            .iter()
1695            .filter_map(|lbe| {
1696                if let SettingElement::Setting(t, vd) = lbe {
1697                    Some((t, vd))
1698                } else {
1699                    None
1700                }
1701            })
1702            .collect()
1703    }
1704}
1705
1706/// Container for parsed values with optional location information
1707/// Location is optional in case this token was generated dynamically
1708#[derive(Serialize, Deserialize, Debug, Clone, Default, Eq)]
1709#[serde(crate = "pax_message::serde")]
1710pub struct Token {
1711    pub token_value: String,
1712    pub token_location: Option<LocationInfo>,
1713}
1714
1715impl PartialEq for Token {
1716    fn eq(&self, other: &Self) -> bool {
1717        self.token_value == other.token_value
1718    }
1719}
1720
1721impl Hash for Token {
1722    fn hash<H: Hasher>(&self, state: &mut H) {
1723        self.token_value.hash(state)
1724    }
1725}
1726
1727impl PartialOrd for Token {
1728    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1729        self.token_value.partial_cmp(&other.token_value)
1730    }
1731}
1732
1733impl Ord for Token {
1734    fn cmp(&self, other: &Self) -> Ordering {
1735        self.token_value.cmp(&other.token_value)
1736    }
1737}
1738
1739impl Token {
1740    pub fn new(token_value: String, token_location: LocationInfo) -> Self {
1741        Self {
1742            token_value,
1743            token_location: Some(token_location),
1744        }
1745    }
1746
1747    pub fn new_without_location(token_value: String) -> Self {
1748        Self {
1749            token_value,
1750            token_location: None,
1751        }
1752    }
1753}
1754
1755#[derive(Serialize, Deserialize, Debug, Clone)]
1756#[serde(crate = "pax_message::serde")]
1757pub enum Number {
1758    Float(f64),
1759    Int(isize),
1760}
1761
1762#[derive(Serialize, Deserialize, Debug, Clone)]
1763#[serde(crate = "pax_message::serde")]
1764pub enum Unit {
1765    Pixels,
1766    Percent,
1767}
1768
1769pub fn escape_identifier(input: String) -> String {
1770    input
1771        .replace("(", "LPAR")
1772        .replace("::", "COCO")
1773        .replace(")", "RPAR")
1774        .replace("<", "LABR")
1775        .replace(">", "RABR")
1776        .replace(",", "COMM")
1777        .replace(".", "PERI")
1778        .replace("[", "LSQB")
1779        .replace("]", "RSQB")
1780        .replace("/", "FSLA")
1781        .replace("\\", "BSLA")
1782        .replace("#", "HASH")
1783        .replace("-", "HYPH")
1784}
1785
1786/// Pulled from host Cargo.toml
1787pub struct HostCrateInfo {
1788    /// for example: `pax-example`
1789    pub name: String,
1790    /// for example: `pax_example`
1791    pub identifier: String,
1792    /// for example: `some_crate::pax_reexports`,
1793    pub import_prefix: String,
1794}
1795
1796//Effectively our `Prelude` types
1797pub const IMPORTS_BUILTINS: &[&str] = &[
1798    "std::any::Any",
1799    "pax_runtime::api::{use_RefCell}",
1800    "std::collections::HashMap",
1801    "std::collections::VecDeque",
1802    "std::ops::Deref",
1803    "std::rc::Rc",
1804    "pax_runtime::RepeatItem",
1805    "pax_runtime::RepeatProperties",
1806    "pax_runtime::ConditionalProperties",
1807    "pax_runtime::Slot",
1808    "pax_runtime::api::Property",
1809    "pax_runtime::api::CommonProperties",
1810    "pax_runtime::api::Color::*",
1811    "pax_runtime::ComponentInstance",
1812    "pax_runtime::InstanceNodePtr",
1813    "pax_runtime::InstanceNodePtrList",
1814    "pax_runtime::ExpressionContext",
1815    "pax_runtime::PaxEngine",
1816    "pax_runtime::InstanceNode",
1817    "pax_runtime::HandlerRegistry",
1818    "pax_runtime::InstantiationArgs",
1819    "pax_runtime::ConditionalInstance",
1820    "pax_runtime::SlotInstance",
1821    "pax_runtime::properties::RuntimePropertiesStackFrame",
1822    "pax_runtime::repeat::RepeatInstance",
1823    "piet_common::RenderContext",
1824];