1use crate::{collect_used_resources, state::ResourceState, untyped::UntypedResource};
24use fxhash::FxHashSet;
25
26pub struct ResourceGraphNode {
28 pub resource: UntypedResource,
30 pub children: Vec<ResourceGraphNode>,
32}
33
34impl ResourceGraphNode {
35 pub fn new(resource: &UntypedResource) -> Self {
38 let mut children = Vec::new();
39
40 let mut dependent_resources = FxHashSet::default();
42
43 let header = resource.0.lock();
44 if let ResourceState::Ok(ref resource_data) = header.state {
45 (**resource_data).as_reflect(&mut |entity| {
46 collect_used_resources(entity, &mut dependent_resources);
47 });
48 }
49
50 children.extend(
51 dependent_resources
52 .into_iter()
53 .map(|r| ResourceGraphNode::new(&r)),
54 );
55
56 Self {
57 resource: resource.clone(),
58 children,
59 }
60 }
61
62 pub fn pretty_print(&self, level: usize, out: &mut String) {
65 *out += &format!(
66 "{}{}\n",
67 String::from('\t').repeat(level),
68 self.resource.kind()
69 );
70
71 for child in self.children.iter() {
72 child.pretty_print(level + 1, out);
73 }
74 }
75
76 pub fn for_each<F: FnMut(&UntypedResource)>(&self, func: &mut F) {
78 func(&self.resource);
79
80 for child in self.children.iter() {
81 child.for_each(func)
82 }
83 }
84}
85
86pub struct ResourceDependencyGraph {
92 pub root: ResourceGraphNode,
94}
95
96impl ResourceDependencyGraph {
97 pub fn new(resource: &UntypedResource) -> Self {
99 Self {
100 root: ResourceGraphNode::new(resource),
101 }
102 }
103
104 pub fn for_each<F: FnMut(&UntypedResource)>(&self, mut func: F) {
106 self.root.for_each(&mut func)
107 }
108
109 pub fn pretty_print(&self) -> String {
111 let mut out = String::new();
112 self.root.pretty_print(0, &mut out);
113 out
114 }
115}
116#[cfg(test)]
117mod test {
118 use std::path::PathBuf;
119
120 use fyrox_core::uuid::Uuid;
121
122 use super::*;
123
124 #[test]
125 fn resource_graph_node_new() {
126 let resource = UntypedResource::default();
127 let node = ResourceGraphNode::new(&resource);
128
129 assert_eq!(node.resource, resource);
130 assert_eq!(node.children.len(), 0);
131 }
132
133 #[test]
134 fn resource_graph_node_pretty_print() {
135 let mut s = String::new();
136 let mut node = ResourceGraphNode::new(&UntypedResource::new_pending(
137 PathBuf::from("/foo").into(),
138 Uuid::default(),
139 ));
140 let node2 = ResourceGraphNode::new(&UntypedResource::new_pending(
141 PathBuf::from("/bar").into(),
142 Uuid::default(),
143 ));
144 node.children.push(node2);
145 node.pretty_print(1, &mut s);
146
147 assert_eq!(s, "\tExternal (/foo)\n\t\tExternal (/bar)\n".to_string());
148 }
149
150 #[test]
151 fn resource_graph_node_for_each() {
152 let mut node = ResourceGraphNode::new(&UntypedResource::default());
153 node.children
154 .push(ResourceGraphNode::new(&UntypedResource::default()));
155 let mut uuids = Vec::new();
156
157 node.for_each(&mut |r| uuids.push(r.type_uuid()));
158 assert_eq!(uuids, [Uuid::default(), Uuid::default()]);
159 }
160
161 #[test]
162 fn resource_dependency_graph_new() {
163 let resource = UntypedResource::default();
164 let graph = ResourceDependencyGraph::new(&resource);
165
166 assert_eq!(graph.root.resource, resource);
167 assert_eq!(graph.root.children.len(), 0);
168 }
169
170 #[test]
171 fn resource_dependency_pretty_print() {
172 let mut graph = ResourceDependencyGraph::new(&UntypedResource::new_pending(
173 PathBuf::from("/foo").into(),
174 Uuid::default(),
175 ));
176 graph
177 .root
178 .children
179 .push(ResourceGraphNode::new(&UntypedResource::new_pending(
180 PathBuf::from("/bar").into(),
181 Uuid::default(),
182 )));
183
184 let s = graph.pretty_print();
185 assert_eq!(s, "External (/foo)\n\tExternal (/bar)\n".to_string());
186 }
187
188 #[test]
189 fn resource_dependency_for_each() {
190 let mut graph = ResourceDependencyGraph::new(&UntypedResource::new_pending(
191 PathBuf::from("/foo").into(),
192 Uuid::default(),
193 ));
194 graph
195 .root
196 .children
197 .push(ResourceGraphNode::new(&UntypedResource::new_pending(
198 PathBuf::from("/bar").into(),
199 Uuid::default(),
200 )));
201
202 let mut uuids = Vec::new();
203 graph.for_each(&mut |r: &UntypedResource| uuids.push(r.type_uuid()));
204 assert_eq!(uuids, [Uuid::default(), Uuid::default()]);
205 }
206}