Skip to main content

pite_core/
node.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2use std::fmt;
3
4use crate::Props;
5
6/// Handle to a node inside a [`NodeTree`](crate::NodeTree).
7///
8/// Ids are human-readable strings: they survive edits, read well
9/// in diffs, and can be crossed to Python without an integer translation table.
10#[derive(Clone, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
11pub struct NodeId(String);
12
13impl NodeId {
14    pub fn new(id: impl Into<String>) -> Self {
15        Self(id.into())
16    }
17
18    pub fn as_str(&self) -> &str {
19        &self.0
20    }
21
22    pub fn is_empty(&self) -> bool {
23        self.0.is_empty()
24    }
25}
26
27impl fmt::Display for NodeId {
28    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29        f.write_str(&self.0)
30    }
31}
32
33impl fmt::Debug for NodeId {
34    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35        write!(f, "NodeId({:?})", self.0)
36    }
37}
38
39impl From<&str> for NodeId {
40    fn from(value: &str) -> Self {
41        Self::new(value)
42    }
43}
44
45impl From<String> for NodeId {
46    fn from(value: String) -> Self {
47        Self::new(value)
48    }
49}
50
51impl AsRef<str> for NodeId {
52    fn as_ref(&self) -> &str {
53        &self.0
54    }
55}
56
57/// Script attachment: project-relative path plus the exported class name.
58///
59/// One file exports one class, which keeps the `path + class` attach
60/// mapping trivial.
61#[derive(Clone, Debug, Default, PartialEq, Eq)]
62pub struct ScriptRef {
63    pub path: String,
64    pub class_name: String,
65}
66
67/// A node record. Data only: behaviour lives in [`crate::NodeTypeRegistry`] and
68/// [`crate::LifecycleSink`], so the tree stays free of subsystem types.
69///
70/// The tree owns the structural invariants (`parent`/`children` agreement); treat
71/// these fields as owned by [`crate::NodeTree`].
72#[derive(Clone, Debug, Default, PartialEq)]
73pub struct Node {
74    pub id: NodeId,
75    pub type_name: String,
76    pub name: String,
77    pub parent: Option<NodeId>,
78    pub children: Vec<NodeId>,
79    pub props: Props,
80    pub script: Option<ScriptRef>,
81}
82
83impl Node {
84    /// Minimal node record; the tree fills in `name`, `parent` and `children`.
85    pub fn new(id: NodeId, type_name: impl Into<String>) -> Self {
86        Self {
87            id,
88            type_name: type_name.into(),
89            name: String::new(),
90            ..Self::default()
91        }
92    }
93}
94
95/// Input used to build a [`Node`], e.g. from a scene file entry.
96#[derive(Clone, Debug, Default, PartialEq)]
97pub struct NodeDesc {
98    pub id: NodeId,
99    pub type_name: String,
100    pub name: String,
101    pub parent: Option<NodeId>,
102    pub props: Props,
103    pub script: Option<ScriptRef>,
104}
105
106impl NodeDesc {
107    pub fn new(id: impl Into<NodeId>, type_name: impl Into<String>) -> Self {
108        Self {
109            id: id.into(),
110            type_name: type_name.into(),
111            ..Self::default()
112        }
113    }
114}