1use std::collections::HashMap;
4
5use fbxcel::tree::v7400::{NodeHandle, Tree};
6use log::{debug, trace};
7use string_interner::{DefaultBackend, StringInterner};
8
9use crate::v7400::{
10 error::{
11 load::{LoadError, StructureError},
12 object::ObjectMetaError,
13 },
14 object::{ObjectClassSym, ObjectId, ObjectMeta, ObjectNodeId},
15};
16
17#[derive(Debug, Clone)]
19pub(crate) struct ObjectsCache {
20 obj_id_to_node_id: HashMap<ObjectId, ObjectNodeId>,
22 meta: HashMap<ObjectNodeId, ObjectMeta>,
24 class_strings: StringInterner<DefaultBackend<ObjectClassSym>>,
26 document_nodes: Vec<ObjectNodeId>,
28}
29
30impl ObjectsCache {
31 pub(crate) fn node_id(&self, obj_id: ObjectId) -> Option<ObjectNodeId> {
33 self.obj_id_to_node_id.get(&obj_id).cloned()
34 }
35
36 pub(crate) fn meta_from_node_id(&self, node_id: ObjectNodeId) -> Option<&ObjectMeta> {
38 self.meta.get(&node_id)
39 }
40
41 pub(crate) fn from_tree(tree: &Tree) -> Result<Self, LoadError> {
43 debug!("Loading objects cache");
44 let objects_cache = ObjectsCacheBuilder::default().load(tree)?;
45 debug!(
46 "Loaded objects cache successfully: {} objects",
47 objects_cache.obj_id_to_node_id.len()
48 );
49 Ok(objects_cache)
50 }
51
52 pub(crate) fn resolve_class_string(&self, sym: ObjectClassSym) -> &str {
58 self.class_strings
59 .resolve(sym)
60 .unwrap_or_else(|| panic!("Unresolvable class name symbol: sym={:?}", sym))
61 }
62
63 pub(crate) fn document_nodes(&self) -> &[ObjectNodeId] {
65 &self.document_nodes
66 }
67
68 pub(crate) fn object_node_ids(&self) -> impl Iterator<Item = ObjectNodeId> + '_ {
70 self.meta.keys().cloned()
71 }
72}
73
74#[derive(Debug)]
76struct ObjectsCacheBuilder {
77 obj_id_to_node_id: HashMap<ObjectId, ObjectNodeId>,
79 meta: HashMap<ObjectNodeId, ObjectMeta>,
81 class_strings: StringInterner<DefaultBackend<ObjectClassSym>>,
83 document_nodes: Vec<ObjectNodeId>,
85}
86
87impl ObjectsCacheBuilder {
88 fn load(mut self, tree: &Tree) -> Result<ObjectsCache, LoadError> {
90 self.load_objects(tree)?;
91 self.load_documents(tree)?;
92 Ok(self.build())
93 }
94
95 fn build(self) -> ObjectsCache {
97 ObjectsCache {
98 obj_id_to_node_id: self.obj_id_to_node_id,
99 meta: self.meta,
100 class_strings: self.class_strings,
101 document_nodes: self.document_nodes,
102 }
103 }
104
105 fn load_objects(&mut self, tree: &Tree) -> Result<(), LoadError> {
107 let objects_node = tree
108 .root()
109 .children_by_name("Objects")
110 .next()
111 .ok_or(StructureError::MissingObjectsNode)?;
112 for object_node in objects_node.children() {
113 self.load_object(object_node)?;
114 }
115
116 Ok(())
117 }
118
119 fn load_documents(&mut self, tree: &Tree) -> Result<(), LoadError> {
121 let documents_node = tree
122 .root()
123 .children_by_name("Documents")
124 .next()
125 .ok_or(StructureError::MissingDocumentsNode)?;
126 for object_node in documents_node.children_by_name("Document") {
127 let obj_node_id = self.load_object(object_node)?;
128 self.document_nodes.push(obj_node_id);
129 }
130
131 Ok(())
132 }
133
134 fn load_object(&mut self, node: NodeHandle<'_>) -> Result<ObjectNodeId, ObjectMetaError> {
136 trace!("Loading object metadata, node_id={:?}", node.node_id());
137 assert!(
138 !self.meta.contains_key(&ObjectNodeId::new(node.node_id())),
139 "The node is already loaded: node_id={:?}",
140 node.node_id()
141 );
142
143 let obj_id = self.load_object_id(node)?;
144 let (name, class_sym) = self.load_name_class(node, obj_id)?;
145 let subclass_sym = self.load_subclass(node, obj_id)?;
146
147 let obj_node_id = ObjectNodeId::new(node.node_id());
148 let meta = ObjectMeta::new(obj_id, name, class_sym, subclass_sym);
149 trace!(
150 "Successfully loaded object metadata: node={:?}, metadata={:?}",
151 obj_node_id,
152 meta,
153 );
154
155 self.obj_id_to_node_id.insert(obj_id, obj_node_id);
156 self.meta.insert(obj_node_id, meta);
157
158 Ok(obj_node_id)
159 }
160
161 fn load_object_id(&self, node: NodeHandle<'_>) -> Result<ObjectId, ObjectMetaError> {
163 let attrs = node.attributes();
164 let obj_id = attrs
165 .get(0)
166 .ok_or_else(|| ObjectMetaError::MissingId(node.node_id()))?
167 .get_i64_or_type()
168 .map(ObjectId::new)
169 .map_err(|ty| ObjectMetaError::InvalidIdType(node.node_id(), ty))?;
170 trace!("Got object id: {:?}", obj_id);
171 if let Some(&alt_node_id) = self.obj_id_to_node_id.get(&obj_id) {
172 return Err(ObjectMetaError::DuplicateObjectId(
173 obj_id,
174 node.node_id(),
175 alt_node_id.into(),
176 ));
177 }
178 Ok(obj_id)
179 }
180
181 fn load_name_class(
183 &mut self,
184 node: NodeHandle<'_>,
185 obj_id: ObjectId,
186 ) -> Result<(Option<String>, ObjectClassSym), ObjectMetaError> {
187 let attrs = node.attributes();
188 let (name, class) = attrs
189 .get(1)
190 .ok_or_else(|| ObjectMetaError::MissingNameClass(node.node_id(), obj_id))?
191 .get_string_or_type()
192 .map(|name_class| {
193 name_class.find("\u{0}\u{1}").map_or_else(
194 || (None, ""),
195 |sep_pos| {
196 (
197 Some(name_class[0..sep_pos].to_owned()),
198 &name_class[sep_pos + 2..],
199 )
200 },
201 )
202 })
203 .map_err(|ty| ObjectMetaError::InvalidNameClassType(node.node_id(), obj_id, ty))?;
204 let class_sym = self.class_strings.get_or_intern(class);
205 trace!(
206 "Got name and class: object_id={:?}, name={:?}, class={:?}, class_sym={:?}",
207 obj_id,
208 name,
209 class,
210 class_sym
211 );
212
213 Ok((name, class_sym))
214 }
215
216 fn load_subclass(
218 &mut self,
219 node: NodeHandle<'_>,
220 obj_id: ObjectId,
221 ) -> Result<ObjectClassSym, ObjectMetaError> {
222 let attrs = node.attributes();
223 let subclass = attrs
224 .get(2)
225 .ok_or_else(|| ObjectMetaError::MissingSubclass(node.node_id(), obj_id))?
226 .get_string_or_type()
227 .map_err(|ty| ObjectMetaError::InvalidSubclassType(node.node_id(), obj_id, ty))?;
228 let subclass_sym = self.class_strings.get_or_intern(subclass);
229 trace!(
230 "Got subclass: object_id={:?}, subclass={:?}, subclass_sym={:?}",
231 obj_id,
232 subclass,
233 subclass_sym
234 );
235
236 Ok(subclass_sym)
237 }
238}
239
240impl Default for ObjectsCacheBuilder {
241 fn default() -> Self {
242 Self {
243 obj_id_to_node_id: Default::default(),
244 meta: Default::default(),
245 class_strings: StringInterner::new(),
246 document_nodes: Default::default(),
247 }
248 }
249}