1#![allow(clippy::must_use_candidate)]
13
14use std::collections::HashSet;
15
16use crate::generated::model as m;
17use crate::scene::geometry::Solid;
18use crate::scene::pmi;
19use crate::scene::{Ctx, Scene};
20
21impl Scene<'_> {
22 pub fn all_products(&self) -> impl Iterator<Item = Product<'_>> + '_ {
24 let cx = self.ctx();
25 (0..cx.model.product_arena.items.len()).map(move |i| Product {
26 cx,
27 id: m::ProductId(i),
28 })
29 }
30
31 pub fn all_product_definitions(&self) -> impl Iterator<Item = ProductDef<'_>> + '_ {
33 let cx = self.ctx();
34 let plain = (0..cx.model.product_definition_arena.items.len()).map(move |i| ProductDef {
35 cx,
36 which: PdImpl::Plain(m::ProductDefinitionId(i)),
37 });
38 let with_docs = (0..cx
39 .model
40 .product_definition_with_associated_documents_arena
41 .items
42 .len())
43 .map(move |i| ProductDef {
44 cx,
45 which: PdImpl::WithDocs(m::ProductDefinitionWithAssociatedDocumentsId(i)),
46 });
47 plain.chain(with_docs)
48 }
49
50 pub fn root_definitions(&self) -> impl Iterator<Item = ProductDef<'_>> + '_ {
54 let cx = self.ctx();
55 let rg = cx.ref_graph();
56 self.all_product_definitions().filter(move |def| {
57 !rg.referrers(def.key()).iter().any(|r| {
58 let m::EntityKey::NextAssemblyUsageOccurrence(nid) = r else {
59 return false;
60 };
61 let nauo = cx.model.next_assembly_usage_occurrence_arena.get(nid.0);
62 matches!(
63 &nauo.related_product_definition,
64 m::ProductDefinitionOrReferenceRef::ProductDefinition(d) if m::EntityKey::ProductDefinition(*d) == def.key()
65 )
66 })
67 })
68 }
69}
70
71#[derive(Clone, Copy)]
77pub struct Product<'m> {
78 cx: Ctx<'m>,
79 id: m::ProductId,
80}
81
82impl<'m> Product<'m> {
83 fn raw(&self) -> &'m m::Product {
84 self.cx.model.product_arena.get(self.id.0)
85 }
86
87 pub fn key(&self) -> m::EntityKey {
90 m::EntityKey::Product(self.id)
91 }
92
93 pub fn id(&self) -> &'m str {
94 &self.raw().id
95 }
96
97 pub fn name(&self) -> &'m str {
98 &self.raw().name
99 }
100
101 pub fn description(&self) -> Option<&'m str> {
102 self.raw().description.as_deref()
103 }
104
105 pub fn definitions(&self) -> impl Iterator<Item = ProductDef<'m>> + 'm {
113 let cx = self.cx;
114 let rg = cx.ref_graph();
115 let mut out: Vec<ProductDef<'m>> = Vec::new();
116 for &fr in rg.referrers(m::EntityKey::Product(self.id)) {
117 if !matches!(
118 fr,
119 m::EntityKey::ProductDefinitionFormation(_)
120 | m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(_)
121 ) {
122 continue;
123 }
124 for &pr in rg.referrers(fr) {
125 if let Some(d) = ProductDef::from_key(cx, pr) {
126 out.push(d);
127 }
128 }
129 }
130 out.into_iter()
131 }
132
133 fn metadata_targets(&self) -> Vec<m::EntityKey> {
140 let rg = self.cx.ref_graph();
141 let mut targets = vec![self.key()];
142 for &fr in rg.referrers(self.key()) {
143 if !matches!(
144 fr,
145 m::EntityKey::ProductDefinitionFormation(_)
146 | m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(_)
147 ) {
148 continue;
149 }
150 targets.push(fr);
151 for &pr in rg.referrers(fr) {
152 if matches!(pr, m::EntityKey::ProductDefinition(_)) {
153 targets.push(pr);
154 }
155 }
156 }
157 targets
158 }
159
160 pub fn contributors(&self) -> Vec<Contributor<'m>> {
163 contributors_of(self.cx, &self.metadata_targets())
164 }
165
166 pub fn approvals(&self) -> Vec<Approval<'m>> {
169 approvals_of(self.cx, &self.metadata_targets())
170 }
171
172 pub fn documents(&self) -> Vec<Document<'m>> {
174 documents_of(self.cx, &self.metadata_targets())
175 }
176
177 pub fn security_classifications(&self) -> Vec<SecurityClassification<'m>> {
179 security_classifications_of(self.cx, &self.metadata_targets())
180 }
181
182 pub fn versions(&self) -> Vec<Version<'m>> {
186 let cx = self.cx;
187 let rg = cx.ref_graph();
188 let mut out: Vec<Version<'m>> = Vec::new();
189 for r in rg.referrers(self.key()) {
190 let which = match r {
191 m::EntityKey::ProductDefinitionFormation(id) => FormImpl::Plain(*id),
192 m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(id) => {
193 FormImpl::WithSource(*id)
194 }
195 _ => continue,
196 };
197 out.push(Version { cx, which });
198 }
199 out
200 }
201}
202
203#[derive(Clone, Copy)]
208pub struct Version<'m> {
209 cx: Ctx<'m>,
210 which: FormImpl,
211}
212
213#[derive(Clone, Copy)]
214enum FormImpl {
215 Plain(m::ProductDefinitionFormationId),
216 WithSource(m::ProductDefinitionFormationWithSpecifiedSourceId),
217}
218
219impl<'m> Version<'m> {
220 fn fields(&self) -> (&'m str, Option<&'m str>) {
223 let model = self.cx.model;
224 match self.which {
225 FormImpl::Plain(i) => {
226 let f = model.product_definition_formation_arena.get(i.0);
227 (&f.id, f.description.as_deref())
228 }
229 FormImpl::WithSource(i) => {
230 let f = model
231 .product_definition_formation_with_specified_source_arena
232 .get(i.0);
233 (&f.id, f.description.as_deref())
234 }
235 }
236 }
237
238 pub fn key(&self) -> m::EntityKey {
240 match self.which {
241 FormImpl::Plain(i) => m::EntityKey::ProductDefinitionFormation(i),
242 FormImpl::WithSource(i) => {
243 m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(i)
244 }
245 }
246 }
247
248 pub fn id(&self) -> &'m str {
250 self.fields().0
251 }
252
253 pub fn description(&self) -> Option<&'m str> {
255 self.fields().1
256 }
257
258 pub fn definitions(&self) -> impl Iterator<Item = ProductDef<'m>> + 'm {
261 let cx = self.cx;
262 let rg = cx.ref_graph();
263 let mut out: Vec<ProductDef<'m>> = Vec::new();
264 for &r in rg.referrers(self.key()) {
265 if let Some(d) = ProductDef::from_key(cx, r) {
266 out.push(d);
267 }
268 }
269 out.into_iter()
270 }
271}
272
273#[derive(Clone, Copy)]
280pub struct ProductDef<'m> {
281 cx: Ctx<'m>,
282 which: PdImpl,
283}
284
285#[derive(Clone, Copy)]
289enum PdImpl {
290 Plain(m::ProductDefinitionId),
291 WithDocs(m::ProductDefinitionWithAssociatedDocumentsId),
292}
293
294struct PdCore<'m> {
296 id: &'m str,
297 description: Option<&'m str>,
298 formation: &'m m::ProductDefinitionFormationRef,
299}
300
301impl<'m> ProductDef<'m> {
302 fn from_key(cx: Ctx<'m>, key: m::EntityKey) -> Option<Self> {
305 match key {
306 m::EntityKey::ProductDefinition(i) => Some(Self {
307 cx,
308 which: PdImpl::Plain(i),
309 }),
310 m::EntityKey::ProductDefinitionWithAssociatedDocuments(i) => Some(Self {
311 cx,
312 which: PdImpl::WithDocs(i),
313 }),
314 _ => None,
315 }
316 }
317
318 fn core(&self) -> PdCore<'m> {
320 match self.which {
321 PdImpl::Plain(i) => {
322 let r = self.cx.model.product_definition_arena.get(i.0);
323 PdCore {
324 id: &r.id,
325 description: r.description.as_deref(),
326 formation: &r.formation,
327 }
328 }
329 PdImpl::WithDocs(i) => {
330 let r = self
331 .cx
332 .model
333 .product_definition_with_associated_documents_arena
334 .get(i.0);
335 PdCore {
336 id: &r.id,
337 description: r.description.as_deref(),
338 formation: &r.formation,
339 }
340 }
341 }
342 }
343
344 pub fn key(&self) -> m::EntityKey {
347 match self.which {
348 PdImpl::Plain(i) => m::EntityKey::ProductDefinition(i),
349 PdImpl::WithDocs(i) => m::EntityKey::ProductDefinitionWithAssociatedDocuments(i),
350 }
351 }
352
353 pub fn id(&self) -> &'m str {
354 self.core().id
355 }
356
357 pub fn description(&self) -> Option<&'m str> {
358 self.core().description
359 }
360
361 pub fn product(&self) -> Option<Product<'m>> {
363 let model = self.cx.model;
364 let of_product: &m::ProductRef = match self.core().formation {
365 m::ProductDefinitionFormationRef::ProductDefinitionFormation(i) => {
366 &model.product_definition_formation_arena.get(i.0).of_product
367 }
368 m::ProductDefinitionFormationRef::ProductDefinitionFormationWithSpecifiedSource(i) => {
369 &model
370 .product_definition_formation_with_specified_source_arena
371 .get(i.0)
372 .of_product
373 }
374 m::ProductDefinitionFormationRef::Complex(_) => return None,
375 };
376 match of_product {
377 m::ProductRef::Product(pid) => Some(Product {
378 cx: self.cx,
379 id: *pid,
380 }),
381 m::ProductRef::Complex(_) => None,
382 }
383 }
384
385 pub fn occurrences(&self) -> impl Iterator<Item = Occurrence<'m>> + 'm {
389 let cx = self.cx;
390 let rg = cx.ref_graph();
391 let me = self.key();
392 let mut out: Vec<Occurrence<'m>> = Vec::new();
393 for r in rg.referrers(me) {
394 if let m::EntityKey::NextAssemblyUsageOccurrence(nid) = r {
395 let nauo = cx.model.next_assembly_usage_occurrence_arena.get(nid.0);
396 if pdor_is(&nauo.relating_product_definition, me) {
397 out.push(Occurrence { cx, id: *nid });
398 }
399 }
400 }
401 out.into_iter()
402 }
403
404 pub fn children(&self) -> impl Iterator<Item = ProductDef<'m>> + 'm {
407 self.occurrences().filter_map(|o| o.definition())
408 }
409
410 pub fn parents(&self) -> impl Iterator<Item = ProductDef<'m>> + 'm {
413 let cx = self.cx;
414 let rg = cx.ref_graph();
415 let me = self.key();
416 let mut out: Vec<ProductDef<'m>> = Vec::new();
417 for r in rg.referrers(me) {
418 if let m::EntityKey::NextAssemblyUsageOccurrence(nid) = r {
419 let nauo = cx.model.next_assembly_usage_occurrence_arena.get(nid.0);
420 if pdor_is(&nauo.related_product_definition, me) {
421 if let Some(d) = pdor_to_def(cx, &nauo.relating_product_definition) {
422 out.push(d);
423 }
424 }
425 }
426 }
427 out.into_iter()
428 }
429
430 pub fn solids(&self) -> impl Iterator<Item = Solid<'m>> + 'm {
438 let cx = self.cx;
439 let rg = cx.ref_graph();
440 let me = self.key();
441 let mut out: Vec<Solid<'m>> = Vec::new();
442 let mut visited: HashSet<m::EntityKey> = HashSet::new();
445 for r in rg.referrers(me) {
446 let m::EntityKey::ProductDefinitionShape(pds_id) = r else {
447 continue;
448 };
449 let pds = cx.model.product_definition_shape_arena.get(pds_id.0);
450 if !cdef_is(&pds.definition, me) {
451 continue;
452 }
453 for s in rg.referrers(m::EntityKey::ProductDefinitionShape(*pds_id)) {
454 let m::EntityKey::ShapeDefinitionRepresentation(sdr_id) = s else {
455 continue;
456 };
457 let sdr = cx.model.shape_definition_representation_arena.get(sdr_id.0);
458 if matches!(&sdr.definition, m::RepresentedDefinitionRef::ProductDefinitionShape(p) if *p == *pds_id)
459 {
460 collect_solids_from_repr(cx, &sdr.used_representation, &mut out, &mut visited);
461 }
462 }
463 }
464 let mut seen: HashSet<m::EntityKey> = HashSet::new();
466 out.retain(|s| seen.insert(s.key()));
467 out.into_iter()
468 }
469
470 pub fn features(&self) -> impl Iterator<Item = pmi::Feature<'m>> + 'm {
474 pmi::features_of(self.cx, self.key()).into_iter()
475 }
476
477 pub fn dimensions(&self) -> impl Iterator<Item = pmi::Dimension<'m>> + 'm {
479 pmi::dimensions_of(self.cx, self.key()).into_iter()
480 }
481
482 pub fn tolerances(&self) -> impl Iterator<Item = pmi::Tolerance<'m>> + 'm {
485 pmi::tolerances_of(self.cx, self.key()).into_iter()
486 }
487
488 pub fn datums(&self) -> impl Iterator<Item = pmi::Datum<'m>> + 'm {
490 pmi::datums_of(self.cx, self.key()).into_iter()
491 }
492
493 pub fn version(&self) -> Option<&'m str> {
495 let model = self.cx.model;
496 match self.core().formation {
497 m::ProductDefinitionFormationRef::ProductDefinitionFormation(i) => {
498 Some(&model.product_definition_formation_arena.get(i.0).id)
499 }
500 m::ProductDefinitionFormationRef::ProductDefinitionFormationWithSpecifiedSource(i) => {
501 Some(
502 &model
503 .product_definition_formation_with_specified_source_arena
504 .get(i.0)
505 .id,
506 )
507 }
508 m::ProductDefinitionFormationRef::Complex(_) => None,
509 }
510 }
511
512 fn metadata_targets(&self) -> Vec<m::EntityKey> {
520 let mut targets = Vec::new();
521 if let Some(p) = self.product() {
522 targets.push(p.key());
523 }
524 match self.core().formation {
525 m::ProductDefinitionFormationRef::ProductDefinitionFormation(i) => {
526 targets.push(m::EntityKey::ProductDefinitionFormation(*i));
527 }
528 m::ProductDefinitionFormationRef::ProductDefinitionFormationWithSpecifiedSource(i) => {
529 targets.push(m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(
530 *i,
531 ));
532 }
533 m::ProductDefinitionFormationRef::Complex(_) => {}
534 }
535 targets.push(self.key());
536 targets
537 }
538
539 pub fn contributors(&self) -> Vec<Contributor<'m>> {
542 contributors_of(self.cx, &self.metadata_targets())
543 }
544
545 pub fn approvals(&self) -> Vec<Approval<'m>> {
548 approvals_of(self.cx, &self.metadata_targets())
549 }
550
551 pub fn documents(&self) -> Vec<Document<'m>> {
557 let mut out = documents_of(self.cx, &self.metadata_targets());
558 if let PdImpl::WithDocs(i) = self.which {
559 let raw = self
560 .cx
561 .model
562 .product_definition_with_associated_documents_arena
563 .get(i.0);
564 let scope = scope_of(self.key());
565 for dref in &raw.documentation_ids {
566 let which = match dref {
567 m::DocumentRef::Document(i) => DocImpl::Document(*i),
568 m::DocumentRef::DocumentFile(i) => DocImpl::DocumentFile(*i),
569 m::DocumentRef::Complex(_) => continue,
570 };
571 let doc = Document {
572 cx: self.cx,
573 which,
574 scope,
575 };
576 if !out.iter().any(|d| d.key() == doc.key()) {
577 out.push(doc);
578 }
579 }
580 }
581 out
582 }
583
584 pub fn security_classifications(&self) -> Vec<SecurityClassification<'m>> {
587 security_classifications_of(self.cx, &self.metadata_targets())
588 }
589}
590
591#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
610pub enum Scope {
611 Product,
613 Version,
615 Definition,
617}
618
619fn scope_of(k: m::EntityKey) -> Scope {
622 match k {
623 m::EntityKey::Product(_) => Scope::Product,
624 m::EntityKey::ProductDefinitionFormation(_)
625 | m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(_) => Scope::Version,
626 _ => Scope::Definition,
627 }
628}
629
630#[derive(Clone, Copy)]
635pub enum Target<'m> {
636 Product(Product<'m>),
637 Version(Version<'m>),
638 Definition(ProductDef<'m>),
639}
640
641impl Target<'_> {
642 pub fn scope(&self) -> Scope {
644 match self {
645 Target::Product(_) => Scope::Product,
646 Target::Version(_) => Scope::Version,
647 Target::Definition(_) => Scope::Definition,
648 }
649 }
650}
651
652fn target_of(cx: Ctx<'_>, k: m::EntityKey) -> Option<Target<'_>> {
655 Some(match k {
656 m::EntityKey::Product(id) => Target::Product(Product { cx, id }),
657 m::EntityKey::ProductDefinitionFormation(id) => Target::Version(Version {
658 cx,
659 which: FormImpl::Plain(id),
660 }),
661 m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(id) => {
662 Target::Version(Version {
663 cx,
664 which: FormImpl::WithSource(id),
665 })
666 }
667 other => return ProductDef::from_key(cx, other).map(Target::Definition),
668 })
669}
670
671fn targets_from_keys<'m>(cx: Ctx<'m>, keys: impl Iterator<Item = m::EntityKey>) -> Vec<Target<'m>> {
673 let mut out: Vec<Target<'m>> = Vec::new();
674 let mut seen: Vec<m::EntityKey> = Vec::new();
675 for k in keys {
676 if seen.contains(&k) {
677 continue;
678 }
679 seen.push(k);
680 if let Some(t) = target_of(cx, k) {
681 out.push(t);
682 }
683 }
684 out
685}
686
687fn contributors_of<'m>(cx: Ctx<'m>, targets: &[m::EntityKey]) -> Vec<Contributor<'m>> {
688 let rg = cx.ref_graph();
689 let mut out: Vec<Contributor<'m>> = Vec::new();
690 let mut seen: Vec<m::EntityKey> = Vec::new();
691 for &t in targets {
692 let scope = scope_of(t);
693 for r in rg.referrers(t) {
694 let which = match r {
695 m::EntityKey::CcDesignPersonAndOrganizationAssignment(id) => {
696 ContributorImpl::CcDesign(*id)
697 }
698 m::EntityKey::AppliedPersonAndOrganizationAssignment(id) => {
699 ContributorImpl::Applied(*id)
700 }
701 _ => continue,
702 };
703 if seen.contains(r) {
704 continue;
705 }
706 seen.push(*r);
707 out.push(Contributor { cx, which, scope });
708 }
709 }
710 out
711}
712
713fn approvals_of<'m>(cx: Ctx<'m>, targets: &[m::EntityKey]) -> Vec<Approval<'m>> {
714 let rg = cx.ref_graph();
715 let mut out: Vec<Approval<'m>> = Vec::new();
716 let mut seen: Vec<m::ApprovalId> = Vec::new();
717 for &t in targets {
718 let scope = scope_of(t);
719 for r in rg.referrers(t) {
720 let m::ApprovalRef::Approval(aid) = match r {
721 m::EntityKey::CcDesignApproval(id) => {
722 &cx.model
723 .cc_design_approval_arena
724 .get(id.0)
725 .assigned_approval
726 }
727 m::EntityKey::AppliedApprovalAssignment(id) => {
728 &cx.model
729 .applied_approval_assignment_arena
730 .get(id.0)
731 .assigned_approval
732 }
733 _ => continue,
734 };
735 if seen.contains(aid) {
736 continue;
737 }
738 seen.push(*aid);
739 out.push(Approval {
740 cx,
741 id: *aid,
742 scope,
743 });
744 }
745 }
746 out
747}
748
749fn documents_of<'m>(cx: Ctx<'m>, targets: &[m::EntityKey]) -> Vec<Document<'m>> {
752 let rg = cx.ref_graph();
753 let mut out: Vec<Document<'m>> = Vec::new();
754 let mut seen: Vec<m::EntityKey> = Vec::new();
755 for &t in targets {
756 let scope = scope_of(t);
757 for r in rg.referrers(t) {
758 let m::EntityKey::AppliedDocumentReference(id) = r else {
759 continue;
760 };
761 let which = match &cx
762 .model
763 .applied_document_reference_arena
764 .get(id.0)
765 .assigned_document
766 {
767 m::DocumentRef::Document(i) => DocImpl::Document(*i),
768 m::DocumentRef::DocumentFile(i) => DocImpl::DocumentFile(*i),
769 m::DocumentRef::Complex(_) => {
770 cx.warn(
771 "APPLIED_DOCUMENT_REFERENCE.assigned_document is a complex instance; \
772 document left unread"
773 .to_owned(),
774 );
775 continue;
776 }
777 };
778 let doc = Document { cx, which, scope };
779 let k = doc.key();
780 if seen.contains(&k) {
781 continue;
782 }
783 seen.push(k);
784 out.push(doc);
785 }
786 }
787 out
788}
789
790fn security_classifications_of<'m>(
791 cx: Ctx<'m>,
792 targets: &[m::EntityKey],
793) -> Vec<SecurityClassification<'m>> {
794 let rg = cx.ref_graph();
795 let mut out: Vec<SecurityClassification<'m>> = Vec::new();
796 let mut seen: Vec<m::SecurityClassificationId> = Vec::new();
797 for &t in targets {
798 let scope = scope_of(t);
799 for r in rg.referrers(t) {
800 let m::SecurityClassificationRef::SecurityClassification(sid) = match r {
801 m::EntityKey::CcDesignSecurityClassification(id) => {
802 &cx.model
803 .cc_design_security_classification_arena
804 .get(id.0)
805 .assigned_security_classification
806 }
807 m::EntityKey::AppliedSecurityClassificationAssignment(id) => {
808 &cx.model
809 .applied_security_classification_assignment_arena
810 .get(id.0)
811 .assigned_security_classification
812 }
813 _ => continue,
814 };
815 if seen.contains(sid) {
816 continue;
817 }
818 seen.push(*sid);
819 out.push(SecurityClassification {
820 cx,
821 id: *sid,
822 scope,
823 });
824 }
825 }
826 out
827}
828
829#[derive(Clone, Copy)]
834enum ContributorImpl {
835 CcDesign(m::CcDesignPersonAndOrganizationAssignmentId),
836 Applied(m::AppliedPersonAndOrganizationAssignmentId),
837}
838
839#[derive(Clone, Copy)]
842pub struct Contributor<'m> {
843 cx: Ctx<'m>,
844 which: ContributorImpl,
845 scope: Scope,
846}
847
848impl<'m> Contributor<'m> {
849 pub fn assigned_scope(&self) -> Scope {
851 self.scope
852 }
853
854 pub fn assigned_targets(&self) -> Vec<Target<'m>> {
857 let cx = self.cx;
858 let keys: Vec<m::EntityKey> = match self.which {
859 ContributorImpl::CcDesign(i) => cx
860 .model
861 .cc_design_person_and_organization_assignment_arena
862 .get(i.0)
863 .items
864 .iter()
865 .map(m::CcPersonOrganizationItemRef::entity_key)
866 .collect(),
867 ContributorImpl::Applied(i) => cx
868 .model
869 .applied_person_and_organization_assignment_arena
870 .get(i.0)
871 .items
872 .iter()
873 .map(m::PersonAndOrganizationItemRef::entity_key)
874 .collect(),
875 };
876 targets_from_keys(cx, keys.into_iter())
877 }
878
879 fn ids(&self) -> (m::PersonAndOrganizationId, m::PersonAndOrganizationRoleId) {
882 let model = self.cx.model;
883 let (pao, role) = match self.which {
884 ContributorImpl::CcDesign(i) => {
885 let a = model
886 .cc_design_person_and_organization_assignment_arena
887 .get(i.0);
888 (&a.assigned_person_and_organization, &a.role)
889 }
890 ContributorImpl::Applied(i) => {
891 let a = model
892 .applied_person_and_organization_assignment_arena
893 .get(i.0);
894 (&a.assigned_person_and_organization, &a.role)
895 }
896 };
897 let m::PersonAndOrganizationRef::PersonAndOrganization(pid) = pao;
898 let m::PersonAndOrganizationRoleRef::PersonAndOrganizationRole(rid) = role;
899 (*pid, *rid)
900 }
901
902 pub fn role(&self) -> &'m str {
904 let (_, rid) = self.ids();
905 &self
906 .cx
907 .model
908 .person_and_organization_role_arena
909 .get(rid.0)
910 .name
911 }
912
913 pub fn person(&self) -> Person<'m> {
915 let (pao, _) = self.ids();
916 let m::PersonRef::Person(pid) = &self
917 .cx
918 .model
919 .person_and_organization_arena
920 .get(pao.0)
921 .the_person;
922 Person {
923 cx: self.cx,
924 id: *pid,
925 }
926 }
927
928 pub fn organization(&self) -> &'m str {
930 let (pao, _) = self.ids();
931 let m::OrganizationRef::Organization(oid) = &self
932 .cx
933 .model
934 .person_and_organization_arena
935 .get(pao.0)
936 .the_organization;
937 &self.cx.model.organization_arena.get(oid.0).name
938 }
939}
940
941#[derive(Clone, Copy)]
943pub struct Person<'m> {
944 cx: Ctx<'m>,
945 id: m::PersonId,
946}
947
948impl<'m> Person<'m> {
949 fn raw(&self) -> &'m m::Person {
950 self.cx.model.person_arena.get(self.id.0)
951 }
952
953 pub fn key(&self) -> m::EntityKey {
955 m::EntityKey::Person(self.id)
956 }
957
958 pub fn id(&self) -> &'m str {
960 &self.raw().id
961 }
962
963 pub fn first_name(&self) -> Option<&'m str> {
965 self.raw().first_name.as_deref()
966 }
967
968 pub fn last_name(&self) -> Option<&'m str> {
970 self.raw().last_name.as_deref()
971 }
972}
973
974#[derive(Clone, Copy, Debug)]
981pub struct Placement {
982 pub origin: [f64; 3],
983 pub axis: [f64; 3],
984 pub ref_direction: [f64; 3],
985}
986
987#[derive(Clone, Copy, Debug)]
991pub struct Transform {
992 pub from: Placement,
993 pub to: Placement,
994}
995
996fn vdot(a: [f64; 3], b: [f64; 3]) -> f64 {
1000 a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
1001}
1002fn vsub(a: [f64; 3], b: [f64; 3]) -> [f64; 3] {
1003 [a[0] - b[0], a[1] - b[1], a[2] - b[2]]
1004}
1005fn vscale(a: [f64; 3], s: f64) -> [f64; 3] {
1006 [a[0] * s, a[1] * s, a[2] * s]
1007}
1008fn vcross(a: [f64; 3], b: [f64; 3]) -> [f64; 3] {
1009 [
1010 a[1] * b[2] - a[2] * b[1],
1011 a[2] * b[0] - a[0] * b[2],
1012 a[0] * b[1] - a[1] * b[0],
1013 ]
1014}
1015fn vnorm(a: [f64; 3]) -> Option<[f64; 3]> {
1016 let n = vdot(a, a).sqrt();
1017 (n >= 1e-12).then(|| vscale(a, 1.0 / n))
1018}
1019
1020impl Placement {
1021 fn frame(&self) -> Option<([f64; 3], [f64; 3], [f64; 3])> {
1026 let z = vnorm(self.axis)?;
1027 let x = vnorm(vsub(
1028 self.ref_direction,
1029 vscale(z, vdot(self.ref_direction, z)),
1030 ))?;
1031 Some((x, vcross(z, x), z))
1032 }
1033}
1034
1035impl Transform {
1036 #[allow(clippy::needless_range_loop)]
1047 pub fn matrix(&self) -> Option<[[f64; 4]; 4]> {
1048 let rf = self.from.frame()?; let rt = self.to.frame()?; let (rf, rt) = ([rf.0, rf.1, rf.2], [rt.0, rt.1, rt.2]);
1051 let mut m = [[0.0_f64; 4]; 4];
1052 for i in 0..3 {
1054 for j in 0..3 {
1055 m[i][j] = (0..3).map(|k| rt[k][i] * rf[k][j]).sum();
1056 }
1057 }
1058 for i in 0..3 {
1060 m[i][3] =
1061 self.to.origin[i] - (0..3).map(|j| m[i][j] * self.from.origin[j]).sum::<f64>();
1062 }
1063 m[3][3] = 1.0;
1064 Some(m)
1065 }
1066}
1067
1068#[derive(Clone, Copy)]
1071pub struct Occurrence<'m> {
1072 cx: Ctx<'m>,
1073 id: m::NextAssemblyUsageOccurrenceId,
1074}
1075
1076impl<'m> Occurrence<'m> {
1077 fn raw(&self) -> &'m m::NextAssemblyUsageOccurrence {
1078 self.cx
1079 .model
1080 .next_assembly_usage_occurrence_arena
1081 .get(self.id.0)
1082 }
1083
1084 pub fn key(&self) -> m::EntityKey {
1086 m::EntityKey::NextAssemblyUsageOccurrence(self.id)
1087 }
1088
1089 pub fn definition(&self) -> Option<ProductDef<'m>> {
1091 pdor_to_def(self.cx, &self.raw().related_product_definition)
1092 }
1093
1094 pub fn transform(&self) -> Option<Transform> {
1101 let cx = self.cx;
1102 let rg = cx.ref_graph();
1103 let me = self.id;
1104 for r in rg.referrers(m::EntityKey::NextAssemblyUsageOccurrence(me)) {
1105 let m::EntityKey::ProductDefinitionShape(pds_id) = r else {
1106 continue;
1107 };
1108 let pds = cx.model.product_definition_shape_arena.get(pds_id.0);
1109 if !matches!(&pds.definition, m::CharacterizedDefinitionRef::NextAssemblyUsageOccurrence(n) if *n == me)
1110 {
1111 continue;
1112 }
1113 for c in rg.referrers(m::EntityKey::ProductDefinitionShape(*pds_id)) {
1114 let m::EntityKey::ContextDependentShapeRepresentation(cdsr_id) = c else {
1115 continue;
1116 };
1117 let cdsr = cx
1118 .model
1119 .context_dependent_shape_representation_arena
1120 .get(cdsr_id.0);
1121 if !matches!(&cdsr.represented_product_relation, m::ProductDefinitionShapeRef::ProductDefinitionShape(p) if *p == *pds_id)
1122 {
1123 continue;
1124 }
1125 if let Some(idt) = idt_of_cdsr(cx, &cdsr.representation_relation) {
1126 let from = resolve_placement(cx, &idt.transform_item_1)?;
1127 let to = resolve_placement(cx, &idt.transform_item_2)?;
1128 return Some(Transform { from, to });
1129 }
1130 }
1131 }
1132 None
1133 }
1134}
1135
1136impl Scene<'_> {
1142 pub fn all_mapped_instances(&self) -> impl Iterator<Item = MappedInstance<'_>> + '_ {
1147 let cx = self.ctx();
1148 (0..cx.model.mapped_item_arena.items.len()).map(move |i| MappedInstance {
1149 cx,
1150 id: m::MappedItemId(i),
1151 })
1152 }
1153}
1154
1155#[derive(Clone, Copy)]
1158pub struct MappedInstance<'m> {
1159 cx: Ctx<'m>,
1160 id: m::MappedItemId,
1161}
1162
1163impl<'m> MappedInstance<'m> {
1164 fn raw(&self) -> &'m m::MappedItem {
1165 self.cx.model.mapped_item_arena.get(self.id.0)
1166 }
1167
1168 pub fn name(&self) -> &'m str {
1169 &self.raw().name
1170 }
1171
1172 pub fn key(&self) -> m::EntityKey {
1174 m::EntityKey::MappedItem(self.id)
1175 }
1176
1177 fn map(&self) -> Option<&'m m::RepresentationMap> {
1178 let m::RepresentationMapRef::RepresentationMap(id) = &self.raw().mapping_source else {
1179 self.cx
1180 .warn("MAPPED_ITEM.mapping_source is not a REPRESENTATION_MAP".to_owned());
1181 return None;
1182 };
1183 Some(self.cx.model.representation_map_arena.get(id.0))
1184 }
1185
1186 pub fn transform(&self) -> Option<Transform> {
1192 let cx = self.cx;
1193 let map = self.map()?;
1194 let from = resolve_placement(cx, &map.mapping_origin)?;
1195 let to = resolve_placement(cx, &self.raw().mapping_target)?;
1196 Some(Transform { from, to })
1197 }
1198
1199 pub fn solids(&self) -> Vec<Solid<'m>> {
1202 let cx = self.cx;
1203 let Some(map) = self.map() else {
1204 return Vec::new();
1205 };
1206 rep_items(cx, &map.mapped_representation)
1207 .into_iter()
1208 .flatten()
1209 .filter_map(|it| match it {
1210 m::RepresentationItemRef::ManifoldSolidBrep(id) => Some(Solid::from_id(cx, *id)),
1211 m::RepresentationItemRef::BrepWithVoids(id) => Some(Solid::from_void_id(cx, *id)),
1212 _ => None,
1213 })
1214 .collect()
1215 }
1216
1217 pub fn mapped_children(&self) -> Vec<MappedInstance<'m>> {
1220 let cx = self.cx;
1221 let Some(map) = self.map() else {
1222 return Vec::new();
1223 };
1224 rep_items(cx, &map.mapped_representation)
1225 .into_iter()
1226 .flatten()
1227 .filter_map(|it| match it {
1228 m::RepresentationItemRef::MappedItem(id) => Some(MappedInstance { cx, id: *id }),
1229 _ => None,
1230 })
1231 .collect()
1232 }
1233}
1234
1235fn rep_items<'m>(cx: Ctx<'m>, r: &m::RepresentationRef) -> Option<&'m [m::RepresentationItemRef]> {
1238 match r {
1239 m::RepresentationRef::ShapeRepresentation(id) => {
1240 Some(&cx.model.shape_representation_arena.get(id.0).items)
1241 }
1242 m::RepresentationRef::AdvancedBrepShapeRepresentation(id) => Some(
1243 &cx.model
1244 .advanced_brep_shape_representation_arena
1245 .get(id.0)
1246 .items,
1247 ),
1248 m::RepresentationRef::GeometricallyBoundedWireframeShapeRepresentation(id) => Some(
1249 &cx.model
1250 .geometrically_bounded_wireframe_shape_representation_arena
1251 .get(id.0)
1252 .items,
1253 ),
1254 _ => None,
1255 }
1256}
1257
1258fn idt_of_cdsr<'m>(
1267 cx: Ctx<'m>,
1268 rr: &m::ShapeRepresentationRelationshipRef,
1269) -> Option<&'m m::ItemDefinedTransformation> {
1270 let m::ShapeRepresentationRelationshipRef::Complex(cuid) = rr else {
1271 return None;
1272 };
1273 let op = cx
1274 .model
1275 .complex_unit_arena
1276 .get(cuid.0)
1277 .parts
1278 .iter()
1279 .find_map(|p| match p {
1280 m::UnitPart::RepresentationRelationshipWithTransformation {
1281 transformation_operator,
1282 } => Some(transformation_operator),
1283 _ => None,
1284 })?;
1285 let m::TransformationRef::ItemDefinedTransformation(id) = op else {
1286 return None;
1287 };
1288 Some(cx.model.item_defined_transformation_arena.get(id.0))
1289}
1290
1291fn resolve_placement(cx: Ctx<'_>, item: &m::RepresentationItemRef) -> Option<Placement> {
1296 let m::RepresentationItemRef::Axis2Placement3d(id) = item else {
1297 cx.warn("transform item is not an AXIS2_PLACEMENT_3D".to_owned());
1298 return None;
1299 };
1300 let a = cx.model.axis2_placement3d_arena.get(id.0);
1301 Some(Placement {
1302 origin: point3(cx, &a.location),
1303 axis: a.axis.as_ref().map_or([0.0, 0.0, 1.0], |d| dir3(cx, d)),
1304 ref_direction: a
1305 .ref_direction
1306 .as_ref()
1307 .map_or([1.0, 0.0, 0.0], |d| dir3(cx, d)),
1308 })
1309}
1310
1311fn point3(cx: Ctx<'_>, r: &m::CartesianPointRef) -> [f64; 3] {
1313 if let m::CartesianPointRef::CartesianPoint(id) = r {
1314 let c = &cx.model.cartesian_point_arena.get(id.0).coordinates;
1315 [
1316 c.first().copied().unwrap_or(0.0),
1317 c.get(1).copied().unwrap_or(0.0),
1318 c.get(2).copied().unwrap_or(0.0),
1319 ]
1320 } else {
1321 [0.0; 3]
1322 }
1323}
1324
1325fn dir3(cx: Ctx<'_>, r: &m::DirectionRef) -> [f64; 3] {
1327 if let m::DirectionRef::Direction(id) = r {
1328 let c = &cx.model.direction_arena.get(id.0).direction_ratios;
1329 [
1330 c.first().copied().unwrap_or(0.0),
1331 c.get(1).copied().unwrap_or(0.0),
1332 c.get(2).copied().unwrap_or(0.0),
1333 ]
1334 } else {
1335 [0.0; 3]
1336 }
1337}
1338
1339fn pdor_is(r: &m::ProductDefinitionOrReferenceRef, key: m::EntityKey) -> bool {
1342 match r {
1343 m::ProductDefinitionOrReferenceRef::ProductDefinition(i) => {
1344 m::EntityKey::ProductDefinition(*i) == key
1345 }
1346 m::ProductDefinitionOrReferenceRef::ProductDefinitionWithAssociatedDocuments(i) => {
1347 m::EntityKey::ProductDefinitionWithAssociatedDocuments(*i) == key
1348 }
1349 _ => false,
1350 }
1351}
1352
1353fn pdor_to_def<'m>(cx: Ctx<'m>, r: &m::ProductDefinitionOrReferenceRef) -> Option<ProductDef<'m>> {
1357 match r {
1358 m::ProductDefinitionOrReferenceRef::ProductDefinition(i) => {
1359 ProductDef::from_key(cx, m::EntityKey::ProductDefinition(*i))
1360 }
1361 m::ProductDefinitionOrReferenceRef::ProductDefinitionWithAssociatedDocuments(i) => {
1362 ProductDef::from_key(
1363 cx,
1364 m::EntityKey::ProductDefinitionWithAssociatedDocuments(*i),
1365 )
1366 }
1367 _ => None,
1368 }
1369}
1370
1371fn cdef_is(cd: &m::CharacterizedDefinitionRef, key: m::EntityKey) -> bool {
1374 match cd {
1375 m::CharacterizedDefinitionRef::ProductDefinition(i) => {
1376 m::EntityKey::ProductDefinition(*i) == key
1377 }
1378 m::CharacterizedDefinitionRef::ProductDefinitionWithAssociatedDocuments(i) => {
1379 m::EntityKey::ProductDefinitionWithAssociatedDocuments(*i) == key
1380 }
1381 _ => false,
1382 }
1383}
1384
1385fn collect_solids_from_repr<'m>(
1393 cx: Ctx<'m>,
1394 r: &m::RepresentationRef,
1395 out: &mut Vec<Solid<'m>>,
1396 visited: &mut HashSet<m::EntityKey>,
1397) {
1398 let (key, items): (m::EntityKey, &[m::RepresentationItemRef]) = match r {
1399 m::RepresentationRef::ShapeRepresentation(i) => (
1400 m::EntityKey::ShapeRepresentation(*i),
1401 &cx.model.shape_representation_arena.get(i.0).items,
1402 ),
1403 m::RepresentationRef::AdvancedBrepShapeRepresentation(i) => (
1404 m::EntityKey::AdvancedBrepShapeRepresentation(*i),
1405 &cx.model
1406 .advanced_brep_shape_representation_arena
1407 .get(i.0)
1408 .items,
1409 ),
1410 _ => return,
1411 };
1412 if !visited.insert(key) {
1413 return;
1414 }
1415 for it in items {
1416 match it {
1417 m::RepresentationItemRef::ManifoldSolidBrep(sid) => out.push(Solid::from_id(cx, *sid)),
1418 m::RepresentationItemRef::BrepWithVoids(sid) => {
1419 out.push(Solid::from_void_id(cx, *sid));
1420 }
1421 _ => {}
1422 }
1423 }
1424 let rg = cx.ref_graph();
1426 for referrer in rg.referrers(key) {
1427 let m::EntityKey::ShapeRepresentationRelationship(srr_id) = referrer else {
1428 continue;
1429 };
1430 let srr = cx
1431 .model
1432 .shape_representation_relationship_arena
1433 .get(srr_id.0);
1434 let (k1, k2) = (srr.rep_1.entity_key(), srr.rep_2.entity_key());
1435 let other = if k1 == key {
1436 k2
1437 } else if k2 == key {
1438 k1
1439 } else {
1440 continue;
1441 };
1442 if let Ok(other_ref) = m::RepresentationRef::from_any(other) {
1443 collect_solids_from_repr(cx, &other_ref, out, visited);
1444 }
1445 }
1446}
1447
1448#[derive(Clone, Copy)]
1455pub struct Approval<'m> {
1456 cx: Ctx<'m>,
1457 id: m::ApprovalId,
1458 scope: Scope,
1459}
1460
1461impl<'m> Approval<'m> {
1462 fn raw(&self) -> &'m m::Approval {
1463 self.cx.model.approval_arena.get(self.id.0)
1464 }
1465
1466 pub fn key(&self) -> m::EntityKey {
1468 m::EntityKey::Approval(self.id)
1469 }
1470
1471 pub fn assigned_scope(&self) -> Scope {
1474 self.scope
1475 }
1476
1477 pub fn assigned_targets(&self) -> Vec<Target<'m>> {
1480 let cx = self.cx;
1481 let mut keys: Vec<m::EntityKey> = Vec::new();
1482 for r in cx.ref_graph().referrers(self.key()) {
1483 match r {
1484 m::EntityKey::CcDesignApproval(i) => keys.extend(
1485 cx.model
1486 .cc_design_approval_arena
1487 .get(i.0)
1488 .items
1489 .iter()
1490 .map(m::ApprovedItemRef::entity_key),
1491 ),
1492 m::EntityKey::AppliedApprovalAssignment(i) => keys.extend(
1493 cx.model
1494 .applied_approval_assignment_arena
1495 .get(i.0)
1496 .items
1497 .iter()
1498 .map(m::ApprovalItemRef::entity_key),
1499 ),
1500 _ => {}
1501 }
1502 }
1503 targets_from_keys(cx, keys.into_iter())
1504 }
1505
1506 pub fn status(&self) -> &'m str {
1508 let m::ApprovalStatusRef::ApprovalStatus(sid) = &self.raw().status;
1509 &self.cx.model.approval_status_arena.get(sid.0).name
1510 }
1511
1512 pub fn level(&self) -> &'m str {
1514 &self.raw().level
1515 }
1516
1517 pub fn approvers(&self) -> Vec<Approver<'m>> {
1520 let cx = self.cx;
1521 let mut out: Vec<Approver<'m>> = Vec::new();
1522 for r in cx.ref_graph().referrers(self.key()) {
1523 if let m::EntityKey::ApprovalPersonOrganization(id) = r {
1524 out.push(Approver { cx, id: *id });
1525 }
1526 }
1527 out
1528 }
1529
1530 pub fn date(&self) -> Option<ApprovalDate> {
1538 let cx = self.cx;
1539 for r in cx.ref_graph().referrers(self.key()) {
1540 if let m::EntityKey::ApprovalDateTime(id) = r {
1541 let dt = &cx.model.approval_date_time_arena.get(id.0).date_time;
1542 return resolve_datetime(cx, dt);
1543 }
1544 }
1545 None
1546 }
1547}
1548
1549#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
1554pub struct ApprovalDate {
1555 pub year: Option<i64>,
1556 pub month: Option<i64>,
1557 pub day: Option<i64>,
1558 pub hour: Option<i64>,
1559 pub minute: Option<i64>,
1560}
1561
1562fn resolve_datetime(cx: Ctx<'_>, r: &m::DateTimeSelectRef) -> Option<ApprovalDate> {
1567 let mut d = ApprovalDate::default();
1568 match r {
1569 m::DateTimeSelectRef::CalendarDate(i) => set_calendar(cx, &mut d, *i),
1570 m::DateTimeSelectRef::Date(i) => {
1571 d.year = Some(cx.model.date_arena.get(i.0).year_component);
1572 }
1573 m::DateTimeSelectRef::DateAndTime(i) => {
1574 let dt = cx.model.date_and_time_arena.get(i.0);
1575 set_date(cx, &mut d, &dt.date_component);
1576 let m::LocalTimeRef::LocalTime(lt) = &dt.time_component;
1577 set_time(cx, &mut d, *lt);
1578 }
1579 m::DateTimeSelectRef::LocalTime(i) => set_time(cx, &mut d, *i),
1580 m::DateTimeSelectRef::Complex(_) => {
1581 cx.warn(
1582 "APPROVAL_DATE_TIME.date_time is a complex instance; date left unread".to_owned(),
1583 );
1584 return None;
1585 }
1586 }
1587 Some(d)
1588}
1589
1590fn set_date(cx: Ctx<'_>, d: &mut ApprovalDate, r: &m::DateRef) {
1592 match r {
1593 m::DateRef::CalendarDate(i) => set_calendar(cx, d, *i),
1594 m::DateRef::Date(i) => d.year = Some(cx.model.date_arena.get(i.0).year_component),
1595 m::DateRef::Complex(_) => {}
1596 }
1597}
1598
1599fn set_calendar(cx: Ctx<'_>, d: &mut ApprovalDate, i: m::CalendarDateId) {
1600 let c = cx.model.calendar_date_arena.get(i.0);
1601 d.year = Some(c.year_component);
1602 d.month = Some(c.month_component);
1603 d.day = Some(c.day_component);
1604}
1605
1606fn set_time(cx: Ctx<'_>, d: &mut ApprovalDate, i: m::LocalTimeId) {
1607 let t = cx.model.local_time_arena.get(i.0);
1608 d.hour = Some(t.hour_component);
1609 d.minute = t.minute_component;
1610}
1611
1612#[derive(Clone, Copy)]
1614pub struct Approver<'m> {
1615 cx: Ctx<'m>,
1616 id: m::ApprovalPersonOrganizationId,
1617}
1618
1619impl<'m> Approver<'m> {
1620 fn raw(&self) -> &'m m::ApprovalPersonOrganization {
1621 self.cx
1622 .model
1623 .approval_person_organization_arena
1624 .get(self.id.0)
1625 }
1626
1627 pub fn role(&self) -> &'m str {
1629 let m::ApprovalRoleRef::ApprovalRole(rid) = &self.raw().role;
1630 &self.cx.model.approval_role_arena.get(rid.0).role
1631 }
1632
1633 pub fn person(&self) -> Option<Person<'m>> {
1636 let pid = match &self.raw().person_organization {
1637 m::PersonOrganizationSelectRef::Person(i) => *i,
1638 m::PersonOrganizationSelectRef::PersonAndOrganization(i) => {
1639 let m::PersonRef::Person(p) = &self
1640 .cx
1641 .model
1642 .person_and_organization_arena
1643 .get(i.0)
1644 .the_person;
1645 *p
1646 }
1647 m::PersonOrganizationSelectRef::Organization(_) => return None,
1648 };
1649 Some(Person {
1650 cx: self.cx,
1651 id: pid,
1652 })
1653 }
1654
1655 pub fn organization(&self) -> Option<&'m str> {
1658 let oid = match &self.raw().person_organization {
1659 m::PersonOrganizationSelectRef::Organization(i) => *i,
1660 m::PersonOrganizationSelectRef::PersonAndOrganization(i) => {
1661 let m::OrganizationRef::Organization(o) = &self
1662 .cx
1663 .model
1664 .person_and_organization_arena
1665 .get(i.0)
1666 .the_organization;
1667 *o
1668 }
1669 m::PersonOrganizationSelectRef::Person(_) => return None,
1670 };
1671 Some(&self.cx.model.organization_arena.get(oid.0).name)
1672 }
1673}
1674
1675#[derive(Clone, Copy)]
1676enum DocImpl {
1677 Document(m::DocumentId),
1678 DocumentFile(m::DocumentFileId),
1679}
1680
1681#[derive(Clone, Copy)]
1687pub struct Document<'m> {
1688 cx: Ctx<'m>,
1689 which: DocImpl,
1690 scope: Scope,
1691}
1692
1693impl<'m> Document<'m> {
1694 pub fn assigned_scope(&self) -> Scope {
1696 self.scope
1697 }
1698
1699 pub fn assigned_targets(&self) -> Vec<Target<'m>> {
1702 let cx = self.cx;
1703 let mut keys: Vec<m::EntityKey> = Vec::new();
1704 for r in cx.ref_graph().referrers(self.key()) {
1705 if let m::EntityKey::AppliedDocumentReference(i) = r {
1706 keys.extend(
1707 cx.model
1708 .applied_document_reference_arena
1709 .get(i.0)
1710 .items
1711 .iter()
1712 .map(m::DocumentReferenceItemRef::entity_key),
1713 );
1714 }
1715 }
1716 targets_from_keys(cx, keys.into_iter())
1717 }
1718
1719 fn fields(&self) -> (&'m str, &'m str, Option<&'m str>, &'m m::DocumentTypeRef) {
1722 let model = self.cx.model;
1723 match self.which {
1724 DocImpl::Document(i) => {
1725 let d = model.document_arena.get(i.0);
1726 (&d.id, &d.name, d.description.as_deref(), &d.kind)
1727 }
1728 DocImpl::DocumentFile(i) => {
1729 let d = model.document_file_arena.get(i.0);
1730 (&d.id, &d.name, d.description.as_deref(), &d.kind)
1731 }
1732 }
1733 }
1734
1735 pub fn key(&self) -> m::EntityKey {
1737 match self.which {
1738 DocImpl::Document(i) => m::EntityKey::Document(i),
1739 DocImpl::DocumentFile(i) => m::EntityKey::DocumentFile(i),
1740 }
1741 }
1742
1743 pub fn id(&self) -> &'m str {
1745 self.fields().0
1746 }
1747
1748 pub fn name(&self) -> &'m str {
1750 self.fields().1
1751 }
1752
1753 pub fn description(&self) -> Option<&'m str> {
1755 self.fields().2
1756 }
1757
1758 pub fn kind(&self) -> &'m str {
1761 let m::DocumentTypeRef::DocumentType(tid) = self.fields().3;
1762 &self
1763 .cx
1764 .model
1765 .document_type_arena
1766 .get(tid.0)
1767 .product_data_type
1768 }
1769}
1770
1771#[derive(Clone, Copy)]
1774pub struct SecurityClassification<'m> {
1775 cx: Ctx<'m>,
1776 id: m::SecurityClassificationId,
1777 scope: Scope,
1778}
1779
1780impl<'m> SecurityClassification<'m> {
1781 fn raw(&self) -> &'m m::SecurityClassification {
1782 self.cx.model.security_classification_arena.get(self.id.0)
1783 }
1784
1785 pub fn key(&self) -> m::EntityKey {
1787 m::EntityKey::SecurityClassification(self.id)
1788 }
1789
1790 pub fn assigned_scope(&self) -> Scope {
1792 self.scope
1793 }
1794
1795 pub fn assigned_targets(&self) -> Vec<Target<'m>> {
1798 let cx = self.cx;
1799 let mut keys: Vec<m::EntityKey> = Vec::new();
1800 for r in cx.ref_graph().referrers(self.key()) {
1801 match r {
1802 m::EntityKey::CcDesignSecurityClassification(i) => keys.extend(
1803 cx.model
1804 .cc_design_security_classification_arena
1805 .get(i.0)
1806 .items
1807 .iter()
1808 .map(m::CcClassifiedItemRef::entity_key),
1809 ),
1810 m::EntityKey::AppliedSecurityClassificationAssignment(i) => keys.extend(
1811 cx.model
1812 .applied_security_classification_assignment_arena
1813 .get(i.0)
1814 .items
1815 .iter()
1816 .map(m::SecurityClassificationItemRef::entity_key),
1817 ),
1818 _ => {}
1819 }
1820 }
1821 targets_from_keys(cx, keys.into_iter())
1822 }
1823
1824 pub fn name(&self) -> &'m str {
1826 &self.raw().name
1827 }
1828
1829 pub fn purpose(&self) -> &'m str {
1831 &self.raw().purpose
1832 }
1833
1834 pub fn level(&self) -> &'m str {
1837 let m::SecurityClassificationLevelRef::SecurityClassificationLevel(lid) =
1838 &self.raw().security_level;
1839 &self
1840 .cx
1841 .model
1842 .security_classification_level_arena
1843 .get(lid.0)
1844 .name
1845 }
1846}