Skip to main content

fission_ir/
lib.rs

1pub mod node_id;
2pub mod op;
3pub mod semantics;
4pub mod widget_id;
5
6use serde::{Deserialize, Serialize};
7use std::any::Any;
8use std::collections::HashMap;
9use std::sync::Arc;
10
11pub use node_id::NodeId;
12pub use op::{
13    AlignItems, CompositeScalar, CompositeStyle, EmbedKind, FlexDirection, FlexWrap, GridPlacement,
14    GridTrack, JustifyContent, LayoutOp, Op, PaintOp, StructuralOp,
15};
16pub use semantics::{ActionEntry, ActionSet, Role, Semantics};
17pub use widget_id::WidgetNodeId;
18
19pub const IR_VERSION: u32 = 1;
20
21#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
22pub struct CoreNode {
23    pub id: NodeId,
24    pub op: Op,
25    pub composite: CompositeStyle,
26    pub children: Vec<NodeId>,
27    pub parent: Option<NodeId>,
28    pub hash: u64,
29}
30
31/// A type-erased render object stored alongside IR nodes.
32///
33/// Downstream crates (e.g. `fission-core`) store concrete trait objects here
34/// (typically `Arc<dyn CustomRenderObject>`).  `fission-ir` itself never
35/// inspects these values -- it only provides the storage.
36pub type AnyRenderObject = Arc<dyn Any + Send + Sync>;
37
38#[derive(Clone, Serialize, Deserialize)]
39pub struct CoreIR {
40    pub nodes: HashMap<NodeId, CoreNode>,
41    pub root: Option<NodeId>,
42    /// Per-node custom render objects.  Keyed by the wrapper `NodeId` created
43    /// during lowering of a `CustomNode`.  Skipped by serde because the
44    /// concrete trait objects are not serialisable.
45    #[serde(skip)]
46    pub custom_render_objects: HashMap<NodeId, AnyRenderObject>,
47}
48
49impl std::fmt::Debug for CoreIR {
50    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        f.debug_struct("CoreIR")
52            .field("nodes", &self.nodes)
53            .field("root", &self.root)
54            .field(
55                "custom_render_objects",
56                &format!("({} entries)", self.custom_render_objects.len()),
57            )
58            .finish()
59    }
60}
61
62impl PartialEq for CoreIR {
63    fn eq(&self, other: &Self) -> bool {
64        // custom_render_objects are intentionally excluded from equality --
65        // they are ephemeral, non-serialisable extensions.
66        self.nodes == other.nodes && self.root == other.root
67    }
68}
69
70impl Default for CoreIR {
71    fn default() -> Self {
72        Self {
73            nodes: HashMap::new(),
74            root: None,
75            custom_render_objects: HashMap::new(),
76        }
77    }
78}
79
80impl CoreIR {
81    pub fn new() -> Self {
82        Self::default()
83    }
84
85    pub fn add_node(&mut self, id: NodeId, op: Op, children: Vec<NodeId>) {
86        self.add_node_with_composite(id, op, CompositeStyle::default(), children);
87    }
88
89    pub fn add_node_with_composite(
90        &mut self,
91        id: NodeId,
92        op: Op,
93        composite: CompositeStyle,
94        children: Vec<NodeId>,
95    ) {
96        let core_node = CoreNode {
97            id,
98            op,
99            composite,
100            children: children.clone(),
101            parent: None,
102            hash: 0,
103        };
104        self.nodes.insert(id, core_node);
105
106        for child_id in children {
107            if let Some(child_node) = self.nodes.get_mut(&child_id) {
108                child_node.parent = Some(id);
109            }
110        }
111    }
112
113    pub fn set_root(&mut self, id: NodeId) {
114        self.root = Some(id);
115    }
116}