ploidy_core/ir/views/
container.rs1use itertools::Itertools;
35use petgraph::{Direction, graph::NodeIndex, visit::EdgeRef};
36
37use crate::ir::{
38 graph::{CookedGraph, GraphEdge},
39 types::{GraphContainer, GraphInlineType, GraphSchemaType, GraphType},
40};
41
42use super::{TypeView, ViewNode};
43
44#[derive(Debug)]
46pub enum ContainerView<'graph, 'a> {
47 Array(InnerView<'graph, 'a>),
48 Map(InnerView<'graph, 'a>),
49 Optional(InnerView<'graph, 'a>),
50}
51
52impl<'graph, 'a> ContainerView<'graph, 'a> {
53 #[inline]
55 pub fn ty(&self) -> TypeView<'graph, 'a> {
56 TypeView::new(self.cooked(), self.index())
57 }
58}
59
60impl<'graph, 'a> ViewNode<'graph, 'a> for ContainerView<'graph, 'a> {
61 #[inline]
62 fn cooked(&self) -> &'graph CookedGraph<'a> {
63 let (Self::Array(c) | Self::Map(c) | Self::Optional(c)) = self;
64 c.cooked
65 }
66
67 #[inline]
68 fn index(&self) -> NodeIndex<usize> {
69 let (Self::Array(c) | Self::Map(c) | Self::Optional(c)) = self;
70 c.container
71 }
72}
73
74#[derive(Debug)]
76pub struct InnerView<'graph, 'a> {
77 cooked: &'graph CookedGraph<'a>,
78 container: NodeIndex<usize>,
79 inner: NodeIndex<usize>,
80}
81
82impl<'graph, 'a> InnerView<'graph, 'a> {
83 #[inline]
85 pub fn ty(&self) -> TypeView<'graph, 'a> {
86 TypeView::new(self.cooked, self.inner)
87 }
88
89 #[inline]
91 pub fn description(&self) -> Option<&'a str> {
92 match self.cooked.graph[self.container] {
93 GraphType::Schema(GraphSchemaType::Container(
94 _,
95 GraphContainer::Array { description }
96 | GraphContainer::Map { description }
97 | GraphContainer::Optional { description },
98 ))
99 | GraphType::Inline(GraphInlineType::Container(
100 _,
101 GraphContainer::Array { description }
102 | GraphContainer::Map { description }
103 | GraphContainer::Optional { description },
104 )) => description,
105 _ => None,
106 }
107 }
108}
109
110impl<'graph, 'a> ContainerView<'graph, 'a> {
111 #[inline]
112 pub(in crate::ir) fn new(
113 cooked: &'graph CookedGraph<'a>,
114 index: NodeIndex<usize>,
115 container: GraphContainer<'a>,
116 ) -> Self {
117 let inner = cooked
120 .graph
121 .edges_directed(index, Direction::Outgoing)
122 .filter(|e| matches!(e.weight(), GraphEdge::Contains))
123 .map(|e| e.target())
124 .exactly_one()
125 .unwrap();
126 let inner = InnerView {
127 cooked,
128 container: index,
129 inner,
130 };
131 match container {
132 GraphContainer::Array { .. } => Self::Array(inner),
133 GraphContainer::Map { .. } => Self::Map(inner),
134 GraphContainer::Optional { .. } => Self::Optional(inner),
135 }
136 }
137}