ifc_lite_server/services/data_model/
documents.rs1use super::types::{DocumentAssociation, EntityJob};
8use ifc_lite_core::EntityDecoder;
9use rayon::prelude::*;
10use std::sync::Arc;
11
12fn resolve_document(
15 decoder: &mut EntityDecoder,
16 id: u32,
17) -> (
18 Option<String>,
19 Option<String>,
20 Option<String>,
21 Option<String>,
22) {
23 let Ok(entity) = decoder.decode_by_id(id) else {
24 return (None, None, None, None);
25 };
26 let ty = entity.ifc_type.as_str().to_ascii_uppercase();
27
28 if ty == "IFCDOCUMENTINFORMATION" {
29 return (
31 entity.get_string(0).map(|s| s.to_string()),
32 entity.get_string(1).map(|s| s.to_string()),
33 entity.get_string(3).map(|s| s.to_string()),
34 entity.get_string(2).map(|s| s.to_string()),
35 );
36 }
37
38 let mut location = entity.get_string(0).map(|s| s.to_string());
41 let mut identification = entity.get_string(1).map(|s| s.to_string());
42 let mut name = entity.get_string(2).map(|s| s.to_string());
43 let mut description = entity.get_string(3).map(|s| s.to_string());
44
45 if let Some(info_id) = entity.get_ref(4) {
47 if let Ok(info) = decoder.decode_by_id(info_id) {
48 if info
49 .ifc_type
50 .as_str()
51 .eq_ignore_ascii_case("IFCDOCUMENTINFORMATION")
52 {
53 identification =
54 identification.or_else(|| info.get_string(0).map(|s| s.to_string()));
55 name = name.or_else(|| info.get_string(1).map(|s| s.to_string()));
56 description = description.or_else(|| info.get_string(2).map(|s| s.to_string()));
57 location = location.or_else(|| info.get_string(3).map(|s| s.to_string()));
58 }
59 }
60 }
61
62 (identification, name, location, description)
63}
64
65pub(super) fn extract_documents(
67 jobs: &[EntityJob],
68 content: &Arc<Vec<u8>>,
69 entity_index: &Arc<ifc_lite_core::EntityIndex>,
70) -> Vec<DocumentAssociation> {
71 let rel_jobs: Vec<_> = jobs
72 .iter()
73 .filter(|job| {
74 job.type_name
75 .eq_ignore_ascii_case("IFCRELASSOCIATESDOCUMENT")
76 })
77 .collect();
78
79 tracing::debug!(count = rel_jobs.len(), "Extracting documents");
80
81 rel_jobs
82 .par_iter()
83 .flat_map(|job| {
84 let mut decoder =
85 EntityDecoder::with_arc_index(content.as_slice(), entity_index.clone());
86 let Ok(rel) = decoder.decode_at(job.start, job.end) else {
87 return Vec::new();
88 };
89 let related = super::related_object_ids(&rel);
90 let Some(doc_id) = rel.get_ref(5) else {
92 return Vec::new();
93 };
94 let (identification, name, location, description) =
95 resolve_document(&mut decoder, doc_id);
96
97 related
98 .into_iter()
99 .map(|element_id| DocumentAssociation {
100 element_id,
101 identification: identification.clone(),
102 name: name.clone(),
103 location: location.clone(),
104 description: description.clone(),
105 })
106 .collect()
107 })
108 .collect()
109}