graphrefly_graph/
mount.rs1use std::sync::Arc;
9
10use crate::graph::{Graph, GraphInner, NameError};
11
12#[derive(Debug, thiserror::Error)]
14pub enum MountError {
15 #[error("Graph::mount: name `{0}` already mounted in this graph")]
16 NameCollision(String),
17 #[error("Graph::mount: name `{0}` collides with an existing local node name")]
18 NodeNameCollision(String),
19 #[error("Graph::mount: name `{0}` may not contain the `::` path separator")]
20 InvalidName(String),
21 #[error(
22 "Graph::mount: child graph has a different Core (cross-Core mount is post-M6); \
23 clone-and-rebuild against this graph's Core, or use `mount_new` + builder"
24 )]
25 CoreMismatch,
26 #[error("Graph::mount: child graph already has a parent; unmount it first")]
27 AlreadyMounted,
28 #[error("Graph::unmount: no subgraph named `{0}`")]
29 NotMounted(String),
30 #[error("Graph::mount: graph has been destroyed")]
31 Destroyed,
32}
33
34#[derive(Debug, Clone, PartialEq, Eq)]
37pub struct GraphRemoveAudit {
38 pub node_count: usize,
40 pub mount_count: usize,
42}
43
44impl From<NameError> for MountError {
45 fn from(err: NameError) -> Self {
46 match err {
47 NameError::Collision(n) => Self::NodeNameCollision(n),
48 NameError::InvalidName(n) => Self::InvalidName(n),
49 NameError::Destroyed => Self::Destroyed,
50 }
51 }
52}
53
54pub(crate) fn mount(parent: &Graph, name: String, child: Graph) -> Result<Graph, MountError> {
55 if name.contains("::") {
56 return Err(MountError::InvalidName(name));
57 }
58 if !parent.core.same_dispatcher(&child.core) {
61 return Err(MountError::CoreMismatch);
62 }
63 {
71 let mut parent_inner = parent.inner.lock();
72 if parent_inner.destroyed {
73 return Err(MountError::Destroyed);
74 }
75 if parent_inner.children.contains_key(&name) {
76 return Err(MountError::NameCollision(name));
77 }
78 if parent_inner.names.contains_key(&name) {
79 return Err(MountError::NodeNameCollision(name));
80 }
81 {
82 let mut child_inner = child.inner.lock();
83 if child_inner.parent.is_some() {
84 return Err(MountError::AlreadyMounted);
85 }
86 child_inner.parent = Some(Arc::downgrade(&parent.inner));
87 }
88 parent_inner.children.insert(name, child.clone());
89 }
90 parent.fire_namespace_change();
93 Ok(child)
94}
95
96pub(crate) fn mount_new(parent: &Graph, name: String) -> Result<Graph, MountError> {
97 if name.contains("::") {
98 return Err(MountError::InvalidName(name));
99 }
100 let parent_weak = Arc::downgrade(&parent.inner);
101 let child = {
106 let mut parent_inner = parent.inner.lock();
107 if parent_inner.destroyed {
108 return Err(MountError::Destroyed);
109 }
110 if parent_inner.children.contains_key(&name) {
111 return Err(MountError::NameCollision(name));
112 }
113 if parent_inner.names.contains_key(&name) {
114 return Err(MountError::NodeNameCollision(name));
115 }
116 let child = Graph::with_core(name.clone(), parent.core.clone(), Some(parent_weak));
117 parent_inner.children.insert(name, child.clone());
118 child
119 };
120 parent.fire_namespace_change();
122 Ok(child)
123}
124
125pub(crate) fn unmount(parent: &Graph, name: &str) -> Result<GraphRemoveAudit, MountError> {
126 let child = {
127 let mut parent_inner = parent.inner.lock();
128 if parent_inner.destroyed {
129 return Err(MountError::Destroyed);
130 }
131 parent_inner
132 .children
133 .shift_remove(name)
134 .ok_or_else(|| MountError::NotMounted(name.to_owned()))?
135 };
136 let audit = audit_of(&child);
137 child.inner.lock().parent = None;
139 child.destroy();
140 parent.fire_namespace_change();
142 Ok(audit)
143}
144
145pub(crate) fn ancestors(graph: &Graph, include_self: bool) -> Vec<Graph> {
146 let mut chain: Vec<Graph> = Vec::new();
147 if include_self {
148 chain.push(graph.clone());
149 }
150 let mut cursor: Option<Arc<parking_lot::Mutex<GraphInner>>> = graph
155 .inner
156 .lock()
157 .parent
158 .as_ref()
159 .and_then(std::sync::Weak::upgrade);
160 while let Some(inner) = cursor {
161 let next_parent = inner
162 .lock()
163 .parent
164 .as_ref()
165 .and_then(std::sync::Weak::upgrade);
166 chain.push(Graph {
167 core: graph.core.clone(),
168 inner,
169 });
170 cursor = next_parent;
171 }
172 chain
173}
174
175fn audit_of(graph: &Graph) -> GraphRemoveAudit {
176 let inner = graph.inner.lock();
177 let own = inner.names.len();
178 let mount_count_self = inner.children.len();
179 let mut node_count = own;
180 let mut mount_count = mount_count_self;
181 let kids: Vec<Graph> = inner.children.values().cloned().collect();
182 drop(inner);
183 for kid in kids {
184 let sub = audit_of(&kid);
185 node_count += sub.node_count;
186 mount_count += sub.mount_count;
187 }
188 GraphRemoveAudit {
189 node_count,
190 mount_count,
191 }
192}