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 _ => None,
1212 })
1213 .collect()
1214 }
1215
1216 pub fn mapped_children(&self) -> Vec<MappedInstance<'m>> {
1219 let cx = self.cx;
1220 let Some(map) = self.map() else {
1221 return Vec::new();
1222 };
1223 rep_items(cx, &map.mapped_representation)
1224 .into_iter()
1225 .flatten()
1226 .filter_map(|it| match it {
1227 m::RepresentationItemRef::MappedItem(id) => Some(MappedInstance { cx, id: *id }),
1228 _ => None,
1229 })
1230 .collect()
1231 }
1232}
1233
1234fn rep_items<'m>(cx: Ctx<'m>, r: &m::RepresentationRef) -> Option<&'m [m::RepresentationItemRef]> {
1237 match r {
1238 m::RepresentationRef::ShapeRepresentation(id) => {
1239 Some(&cx.model.shape_representation_arena.get(id.0).items)
1240 }
1241 m::RepresentationRef::AdvancedBrepShapeRepresentation(id) => Some(
1242 &cx.model
1243 .advanced_brep_shape_representation_arena
1244 .get(id.0)
1245 .items,
1246 ),
1247 m::RepresentationRef::GeometricallyBoundedWireframeShapeRepresentation(id) => Some(
1248 &cx.model
1249 .geometrically_bounded_wireframe_shape_representation_arena
1250 .get(id.0)
1251 .items,
1252 ),
1253 _ => None,
1254 }
1255}
1256
1257fn idt_of_cdsr<'m>(
1266 cx: Ctx<'m>,
1267 rr: &m::ShapeRepresentationRelationshipRef,
1268) -> Option<&'m m::ItemDefinedTransformation> {
1269 let m::ShapeRepresentationRelationshipRef::Complex(cuid) = rr else {
1270 return None;
1271 };
1272 let op = cx
1273 .model
1274 .complex_unit_arena
1275 .get(cuid.0)
1276 .parts
1277 .iter()
1278 .find_map(|p| match p {
1279 m::UnitPart::RepresentationRelationshipWithTransformation {
1280 transformation_operator,
1281 } => Some(transformation_operator),
1282 _ => None,
1283 })?;
1284 let m::TransformationRef::ItemDefinedTransformation(id) = op else {
1285 return None;
1286 };
1287 Some(cx.model.item_defined_transformation_arena.get(id.0))
1288}
1289
1290fn resolve_placement(cx: Ctx<'_>, item: &m::RepresentationItemRef) -> Option<Placement> {
1295 let m::RepresentationItemRef::Axis2Placement3d(id) = item else {
1296 cx.warn("transform item is not an AXIS2_PLACEMENT_3D".to_owned());
1297 return None;
1298 };
1299 let a = cx.model.axis2_placement3d_arena.get(id.0);
1300 Some(Placement {
1301 origin: point3(cx, &a.location),
1302 axis: a.axis.as_ref().map_or([0.0, 0.0, 1.0], |d| dir3(cx, d)),
1303 ref_direction: a
1304 .ref_direction
1305 .as_ref()
1306 .map_or([1.0, 0.0, 0.0], |d| dir3(cx, d)),
1307 })
1308}
1309
1310fn point3(cx: Ctx<'_>, r: &m::CartesianPointRef) -> [f64; 3] {
1312 if let m::CartesianPointRef::CartesianPoint(id) = r {
1313 let c = &cx.model.cartesian_point_arena.get(id.0).coordinates;
1314 [
1315 c.first().copied().unwrap_or(0.0),
1316 c.get(1).copied().unwrap_or(0.0),
1317 c.get(2).copied().unwrap_or(0.0),
1318 ]
1319 } else {
1320 [0.0; 3]
1321 }
1322}
1323
1324fn dir3(cx: Ctx<'_>, r: &m::DirectionRef) -> [f64; 3] {
1326 if let m::DirectionRef::Direction(id) = r {
1327 let c = &cx.model.direction_arena.get(id.0).direction_ratios;
1328 [
1329 c.first().copied().unwrap_or(0.0),
1330 c.get(1).copied().unwrap_or(0.0),
1331 c.get(2).copied().unwrap_or(0.0),
1332 ]
1333 } else {
1334 [0.0; 3]
1335 }
1336}
1337
1338fn pdor_is(r: &m::ProductDefinitionOrReferenceRef, key: m::EntityKey) -> bool {
1341 match r {
1342 m::ProductDefinitionOrReferenceRef::ProductDefinition(i) => {
1343 m::EntityKey::ProductDefinition(*i) == key
1344 }
1345 m::ProductDefinitionOrReferenceRef::ProductDefinitionWithAssociatedDocuments(i) => {
1346 m::EntityKey::ProductDefinitionWithAssociatedDocuments(*i) == key
1347 }
1348 _ => false,
1349 }
1350}
1351
1352fn pdor_to_def<'m>(cx: Ctx<'m>, r: &m::ProductDefinitionOrReferenceRef) -> Option<ProductDef<'m>> {
1356 match r {
1357 m::ProductDefinitionOrReferenceRef::ProductDefinition(i) => {
1358 ProductDef::from_key(cx, m::EntityKey::ProductDefinition(*i))
1359 }
1360 m::ProductDefinitionOrReferenceRef::ProductDefinitionWithAssociatedDocuments(i) => {
1361 ProductDef::from_key(
1362 cx,
1363 m::EntityKey::ProductDefinitionWithAssociatedDocuments(*i),
1364 )
1365 }
1366 _ => None,
1367 }
1368}
1369
1370fn cdef_is(cd: &m::CharacterizedDefinitionRef, key: m::EntityKey) -> bool {
1373 match cd {
1374 m::CharacterizedDefinitionRef::ProductDefinition(i) => {
1375 m::EntityKey::ProductDefinition(*i) == key
1376 }
1377 m::CharacterizedDefinitionRef::ProductDefinitionWithAssociatedDocuments(i) => {
1378 m::EntityKey::ProductDefinitionWithAssociatedDocuments(*i) == key
1379 }
1380 _ => false,
1381 }
1382}
1383
1384fn collect_solids_from_repr<'m>(
1392 cx: Ctx<'m>,
1393 r: &m::RepresentationRef,
1394 out: &mut Vec<Solid<'m>>,
1395 visited: &mut HashSet<m::EntityKey>,
1396) {
1397 let (key, items): (m::EntityKey, &[m::RepresentationItemRef]) = match r {
1398 m::RepresentationRef::ShapeRepresentation(i) => (
1399 m::EntityKey::ShapeRepresentation(*i),
1400 &cx.model.shape_representation_arena.get(i.0).items,
1401 ),
1402 m::RepresentationRef::AdvancedBrepShapeRepresentation(i) => (
1403 m::EntityKey::AdvancedBrepShapeRepresentation(*i),
1404 &cx.model
1405 .advanced_brep_shape_representation_arena
1406 .get(i.0)
1407 .items,
1408 ),
1409 _ => return,
1410 };
1411 if !visited.insert(key) {
1412 return;
1413 }
1414 for it in items {
1415 if let m::RepresentationItemRef::ManifoldSolidBrep(sid) = it {
1416 out.push(Solid::from_id(cx, *sid));
1417 }
1418 }
1419 let rg = cx.ref_graph();
1421 for referrer in rg.referrers(key) {
1422 let m::EntityKey::ShapeRepresentationRelationship(srr_id) = referrer else {
1423 continue;
1424 };
1425 let srr = cx
1426 .model
1427 .shape_representation_relationship_arena
1428 .get(srr_id.0);
1429 let (k1, k2) = (srr.rep_1.entity_key(), srr.rep_2.entity_key());
1430 let other = if k1 == key {
1431 k2
1432 } else if k2 == key {
1433 k1
1434 } else {
1435 continue;
1436 };
1437 if let Ok(other_ref) = m::RepresentationRef::from_any(other) {
1438 collect_solids_from_repr(cx, &other_ref, out, visited);
1439 }
1440 }
1441}
1442
1443#[derive(Clone, Copy)]
1450pub struct Approval<'m> {
1451 cx: Ctx<'m>,
1452 id: m::ApprovalId,
1453 scope: Scope,
1454}
1455
1456impl<'m> Approval<'m> {
1457 fn raw(&self) -> &'m m::Approval {
1458 self.cx.model.approval_arena.get(self.id.0)
1459 }
1460
1461 pub fn key(&self) -> m::EntityKey {
1463 m::EntityKey::Approval(self.id)
1464 }
1465
1466 pub fn assigned_scope(&self) -> Scope {
1469 self.scope
1470 }
1471
1472 pub fn assigned_targets(&self) -> Vec<Target<'m>> {
1475 let cx = self.cx;
1476 let mut keys: Vec<m::EntityKey> = Vec::new();
1477 for r in cx.ref_graph().referrers(self.key()) {
1478 match r {
1479 m::EntityKey::CcDesignApproval(i) => keys.extend(
1480 cx.model
1481 .cc_design_approval_arena
1482 .get(i.0)
1483 .items
1484 .iter()
1485 .map(m::ApprovedItemRef::entity_key),
1486 ),
1487 m::EntityKey::AppliedApprovalAssignment(i) => keys.extend(
1488 cx.model
1489 .applied_approval_assignment_arena
1490 .get(i.0)
1491 .items
1492 .iter()
1493 .map(m::ApprovalItemRef::entity_key),
1494 ),
1495 _ => {}
1496 }
1497 }
1498 targets_from_keys(cx, keys.into_iter())
1499 }
1500
1501 pub fn status(&self) -> &'m str {
1503 let m::ApprovalStatusRef::ApprovalStatus(sid) = &self.raw().status;
1504 &self.cx.model.approval_status_arena.get(sid.0).name
1505 }
1506
1507 pub fn level(&self) -> &'m str {
1509 &self.raw().level
1510 }
1511
1512 pub fn approvers(&self) -> Vec<Approver<'m>> {
1515 let cx = self.cx;
1516 let mut out: Vec<Approver<'m>> = Vec::new();
1517 for r in cx.ref_graph().referrers(self.key()) {
1518 if let m::EntityKey::ApprovalPersonOrganization(id) = r {
1519 out.push(Approver { cx, id: *id });
1520 }
1521 }
1522 out
1523 }
1524
1525 pub fn date(&self) -> Option<ApprovalDate> {
1533 let cx = self.cx;
1534 for r in cx.ref_graph().referrers(self.key()) {
1535 if let m::EntityKey::ApprovalDateTime(id) = r {
1536 let dt = &cx.model.approval_date_time_arena.get(id.0).date_time;
1537 return resolve_datetime(cx, dt);
1538 }
1539 }
1540 None
1541 }
1542}
1543
1544#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
1549pub struct ApprovalDate {
1550 pub year: Option<i64>,
1551 pub month: Option<i64>,
1552 pub day: Option<i64>,
1553 pub hour: Option<i64>,
1554 pub minute: Option<i64>,
1555}
1556
1557fn resolve_datetime(cx: Ctx<'_>, r: &m::DateTimeSelectRef) -> Option<ApprovalDate> {
1562 let mut d = ApprovalDate::default();
1563 match r {
1564 m::DateTimeSelectRef::CalendarDate(i) => set_calendar(cx, &mut d, *i),
1565 m::DateTimeSelectRef::Date(i) => {
1566 d.year = Some(cx.model.date_arena.get(i.0).year_component);
1567 }
1568 m::DateTimeSelectRef::DateAndTime(i) => {
1569 let dt = cx.model.date_and_time_arena.get(i.0);
1570 set_date(cx, &mut d, &dt.date_component);
1571 let m::LocalTimeRef::LocalTime(lt) = &dt.time_component;
1572 set_time(cx, &mut d, *lt);
1573 }
1574 m::DateTimeSelectRef::LocalTime(i) => set_time(cx, &mut d, *i),
1575 m::DateTimeSelectRef::Complex(_) => {
1576 cx.warn(
1577 "APPROVAL_DATE_TIME.date_time is a complex instance; date left unread".to_owned(),
1578 );
1579 return None;
1580 }
1581 }
1582 Some(d)
1583}
1584
1585fn set_date(cx: Ctx<'_>, d: &mut ApprovalDate, r: &m::DateRef) {
1587 match r {
1588 m::DateRef::CalendarDate(i) => set_calendar(cx, d, *i),
1589 m::DateRef::Date(i) => d.year = Some(cx.model.date_arena.get(i.0).year_component),
1590 m::DateRef::Complex(_) => {}
1591 }
1592}
1593
1594fn set_calendar(cx: Ctx<'_>, d: &mut ApprovalDate, i: m::CalendarDateId) {
1595 let c = cx.model.calendar_date_arena.get(i.0);
1596 d.year = Some(c.year_component);
1597 d.month = Some(c.month_component);
1598 d.day = Some(c.day_component);
1599}
1600
1601fn set_time(cx: Ctx<'_>, d: &mut ApprovalDate, i: m::LocalTimeId) {
1602 let t = cx.model.local_time_arena.get(i.0);
1603 d.hour = Some(t.hour_component);
1604 d.minute = t.minute_component;
1605}
1606
1607#[derive(Clone, Copy)]
1609pub struct Approver<'m> {
1610 cx: Ctx<'m>,
1611 id: m::ApprovalPersonOrganizationId,
1612}
1613
1614impl<'m> Approver<'m> {
1615 fn raw(&self) -> &'m m::ApprovalPersonOrganization {
1616 self.cx
1617 .model
1618 .approval_person_organization_arena
1619 .get(self.id.0)
1620 }
1621
1622 pub fn role(&self) -> &'m str {
1624 let m::ApprovalRoleRef::ApprovalRole(rid) = &self.raw().role;
1625 &self.cx.model.approval_role_arena.get(rid.0).role
1626 }
1627
1628 pub fn person(&self) -> Option<Person<'m>> {
1631 let pid = match &self.raw().person_organization {
1632 m::PersonOrganizationSelectRef::Person(i) => *i,
1633 m::PersonOrganizationSelectRef::PersonAndOrganization(i) => {
1634 let m::PersonRef::Person(p) = &self
1635 .cx
1636 .model
1637 .person_and_organization_arena
1638 .get(i.0)
1639 .the_person;
1640 *p
1641 }
1642 m::PersonOrganizationSelectRef::Organization(_) => return None,
1643 };
1644 Some(Person {
1645 cx: self.cx,
1646 id: pid,
1647 })
1648 }
1649
1650 pub fn organization(&self) -> Option<&'m str> {
1653 let oid = match &self.raw().person_organization {
1654 m::PersonOrganizationSelectRef::Organization(i) => *i,
1655 m::PersonOrganizationSelectRef::PersonAndOrganization(i) => {
1656 let m::OrganizationRef::Organization(o) = &self
1657 .cx
1658 .model
1659 .person_and_organization_arena
1660 .get(i.0)
1661 .the_organization;
1662 *o
1663 }
1664 m::PersonOrganizationSelectRef::Person(_) => return None,
1665 };
1666 Some(&self.cx.model.organization_arena.get(oid.0).name)
1667 }
1668}
1669
1670#[derive(Clone, Copy)]
1671enum DocImpl {
1672 Document(m::DocumentId),
1673 DocumentFile(m::DocumentFileId),
1674}
1675
1676#[derive(Clone, Copy)]
1682pub struct Document<'m> {
1683 cx: Ctx<'m>,
1684 which: DocImpl,
1685 scope: Scope,
1686}
1687
1688impl<'m> Document<'m> {
1689 pub fn assigned_scope(&self) -> Scope {
1691 self.scope
1692 }
1693
1694 pub fn assigned_targets(&self) -> Vec<Target<'m>> {
1697 let cx = self.cx;
1698 let mut keys: Vec<m::EntityKey> = Vec::new();
1699 for r in cx.ref_graph().referrers(self.key()) {
1700 if let m::EntityKey::AppliedDocumentReference(i) = r {
1701 keys.extend(
1702 cx.model
1703 .applied_document_reference_arena
1704 .get(i.0)
1705 .items
1706 .iter()
1707 .map(m::DocumentReferenceItemRef::entity_key),
1708 );
1709 }
1710 }
1711 targets_from_keys(cx, keys.into_iter())
1712 }
1713
1714 fn fields(&self) -> (&'m str, &'m str, Option<&'m str>, &'m m::DocumentTypeRef) {
1717 let model = self.cx.model;
1718 match self.which {
1719 DocImpl::Document(i) => {
1720 let d = model.document_arena.get(i.0);
1721 (&d.id, &d.name, d.description.as_deref(), &d.kind)
1722 }
1723 DocImpl::DocumentFile(i) => {
1724 let d = model.document_file_arena.get(i.0);
1725 (&d.id, &d.name, d.description.as_deref(), &d.kind)
1726 }
1727 }
1728 }
1729
1730 pub fn key(&self) -> m::EntityKey {
1732 match self.which {
1733 DocImpl::Document(i) => m::EntityKey::Document(i),
1734 DocImpl::DocumentFile(i) => m::EntityKey::DocumentFile(i),
1735 }
1736 }
1737
1738 pub fn id(&self) -> &'m str {
1740 self.fields().0
1741 }
1742
1743 pub fn name(&self) -> &'m str {
1745 self.fields().1
1746 }
1747
1748 pub fn description(&self) -> Option<&'m str> {
1750 self.fields().2
1751 }
1752
1753 pub fn kind(&self) -> &'m str {
1756 let m::DocumentTypeRef::DocumentType(tid) = self.fields().3;
1757 &self
1758 .cx
1759 .model
1760 .document_type_arena
1761 .get(tid.0)
1762 .product_data_type
1763 }
1764}
1765
1766#[derive(Clone, Copy)]
1769pub struct SecurityClassification<'m> {
1770 cx: Ctx<'m>,
1771 id: m::SecurityClassificationId,
1772 scope: Scope,
1773}
1774
1775impl<'m> SecurityClassification<'m> {
1776 fn raw(&self) -> &'m m::SecurityClassification {
1777 self.cx.model.security_classification_arena.get(self.id.0)
1778 }
1779
1780 pub fn key(&self) -> m::EntityKey {
1782 m::EntityKey::SecurityClassification(self.id)
1783 }
1784
1785 pub fn assigned_scope(&self) -> Scope {
1787 self.scope
1788 }
1789
1790 pub fn assigned_targets(&self) -> Vec<Target<'m>> {
1793 let cx = self.cx;
1794 let mut keys: Vec<m::EntityKey> = Vec::new();
1795 for r in cx.ref_graph().referrers(self.key()) {
1796 match r {
1797 m::EntityKey::CcDesignSecurityClassification(i) => keys.extend(
1798 cx.model
1799 .cc_design_security_classification_arena
1800 .get(i.0)
1801 .items
1802 .iter()
1803 .map(m::CcClassifiedItemRef::entity_key),
1804 ),
1805 m::EntityKey::AppliedSecurityClassificationAssignment(i) => keys.extend(
1806 cx.model
1807 .applied_security_classification_assignment_arena
1808 .get(i.0)
1809 .items
1810 .iter()
1811 .map(m::SecurityClassificationItemRef::entity_key),
1812 ),
1813 _ => {}
1814 }
1815 }
1816 targets_from_keys(cx, keys.into_iter())
1817 }
1818
1819 pub fn name(&self) -> &'m str {
1821 &self.raw().name
1822 }
1823
1824 pub fn purpose(&self) -> &'m str {
1826 &self.raw().purpose
1827 }
1828
1829 pub fn level(&self) -> &'m str {
1832 let m::SecurityClassificationLevelRef::SecurityClassificationLevel(lid) =
1833 &self.raw().security_level;
1834 &self
1835 .cx
1836 .model
1837 .security_classification_level_arena
1838 .get(lid.0)
1839 .name
1840 }
1841}