ploidy_core/ir/views/
mod.rs1use std::{any::TypeId, collections::VecDeque, fmt::Debug};
8
9use atomic_refcell::{AtomicRef, AtomicRefMut};
10use petgraph::{
11 graph::NodeIndex,
12 visit::{Bfs, EdgeFiltered, EdgeRef, VisitMap, Visitable},
13};
14use ref_cast::{RefCastCustom, ref_cast_custom};
15
16use super::graph::{Extension, ExtensionMap, IrGraph, IrGraphNode};
17
18pub mod enum_;
19pub mod inline;
20pub mod ir;
21pub mod operation;
22pub mod schema;
23pub mod struct_;
24pub mod tagged;
25pub mod untagged;
26pub mod wrappers;
27
28use self::{inline::InlineIrTypeView, ir::IrTypeView, operation::IrOperationView};
29
30pub trait View<'a> {
32 fn inlines(&self) -> impl Iterator<Item = InlineIrTypeView<'a>>;
35
36 fn used_by(&self) -> impl Iterator<Item = IrOperationView<'a>>;
39
40 fn reachable(&self) -> impl Iterator<Item = IrTypeView<'a>>;
42
43 fn reachable_if<F>(&self, filter: F) -> impl Iterator<Item = IrTypeView<'a>>
46 where
47 F: Fn(&IrTypeView<'a>) -> Traversal;
48
49 fn extensions(&self) -> &IrViewExtensions<Self>
51 where
52 Self: Extendable<'a> + Sized;
53
54 fn extensions_mut(&mut self) -> &mut IrViewExtensions<Self>
56 where
57 Self: Extendable<'a> + Sized;
58}
59
60impl<'a, T> View<'a> for T
61where
62 T: ViewNode<'a>,
63{
64 #[inline]
65 fn inlines(&self) -> impl Iterator<Item = InlineIrTypeView<'a>> {
66 let graph = self.graph();
67 let filtered = EdgeFiltered::from_fn(&graph.g, |r| {
69 !matches!(graph.g[r.target()], IrGraphNode::Schema(_))
70 });
71 let mut bfs = Bfs::new(&graph.g, self.index());
72 std::iter::from_fn(move || bfs.next(&filtered)).filter_map(|index| match graph.g[index] {
73 IrGraphNode::Inline(ty) => Some(InlineIrTypeView::new(graph, index, ty)),
74 _ => None,
75 })
76 }
77
78 #[inline]
79 fn used_by(&self) -> impl Iterator<Item = IrOperationView<'a>> {
80 self.graph()
81 .metadata
82 .get(&self.index())
83 .into_iter()
84 .flat_map(|meta| &meta.operations)
85 .map(|op| IrOperationView::new(self.graph(), op))
86 }
87
88 #[inline]
89 fn reachable(&self) -> impl Iterator<Item = IrTypeView<'a>> {
90 let graph = self.graph();
91 let mut bfs = Bfs::new(&graph.g, self.index());
92 std::iter::from_fn(move || bfs.next(&graph.g)).map(|index| IrTypeView::new(graph, index))
93 }
94
95 #[inline]
96 fn reachable_if<F>(&self, filter: F) -> impl Iterator<Item = IrTypeView<'a>>
97 where
98 F: Fn(&IrTypeView<'a>) -> Traversal,
99 {
100 let graph = self.graph();
101 let mut stack = VecDeque::new();
102 let mut discovered = graph.g.visit_map();
103
104 stack.push_back(self.index());
105 discovered.visit(self.index());
106
107 std::iter::from_fn(move || {
108 while let Some(index) = stack.pop_front() {
109 let view = IrTypeView::new(graph, index);
110 let traversal = filter(&view);
111
112 if matches!(traversal, Traversal::Visit | Traversal::Skip) {
113 for neighbor in graph.g.neighbors(index) {
115 if discovered.visit(neighbor) {
116 stack.push_back(neighbor);
117 }
118 }
119 }
120
121 if matches!(traversal, Traversal::Visit | Traversal::Stop) {
122 return Some(view);
124 }
125
126 }
128 None
129 })
130 }
131
132 #[inline]
133 fn extensions(&self) -> &IrViewExtensions<Self> {
134 IrViewExtensions::new(self)
135 }
136
137 #[inline]
138 fn extensions_mut(&mut self) -> &mut IrViewExtensions<Self> {
139 IrViewExtensions::new_mut(self)
140 }
141}
142
143pub trait ViewNode<'a> {
144 fn graph(&self) -> &'a IrGraph<'a>;
145 fn index(&self) -> NodeIndex;
146}
147
148pub trait Extendable<'graph> {
149 fn ext<'view>(&'view self) -> AtomicRef<'view, ExtensionMap>
162 where
163 'graph: 'view;
164
165 fn ext_mut<'view>(&'view mut self) -> AtomicRefMut<'view, ExtensionMap>
166 where
167 'graph: 'view;
168}
169
170impl<'graph, T> Extendable<'graph> for T
171where
172 T: ViewNode<'graph>,
173{
174 #[inline]
175 fn ext<'view>(&'view self) -> AtomicRef<'view, ExtensionMap>
176 where
177 'graph: 'view,
178 {
179 self.graph().metadata[&self.index()].extensions.borrow()
180 }
181
182 #[inline]
183 fn ext_mut<'b>(&'b mut self) -> AtomicRefMut<'b, ExtensionMap>
184 where
185 'graph: 'b,
186 {
187 self.graph().metadata[&self.index()].extensions.borrow_mut()
188 }
189}
190
191#[derive(RefCastCustom)]
197#[repr(transparent)]
198pub struct IrViewExtensions<X>(X);
199
200impl<X> IrViewExtensions<X> {
201 #[ref_cast_custom]
202 fn new(view: &X) -> &Self;
203
204 #[ref_cast_custom]
205 fn new_mut(view: &mut X) -> &mut Self;
206}
207
208impl<'a, X: Extendable<'a>> IrViewExtensions<X> {
209 #[inline]
212 pub fn get<'b, T: Send + Sync + 'static>(&'b self) -> Option<AtomicRef<'b, T>>
213 where
214 'a: 'b,
215 {
216 AtomicRef::filter_map(self.0.ext(), |ext| {
217 Some(
218 ext.get(&TypeId::of::<T>())?
219 .as_ref()
220 .downcast_ref::<T>()
221 .unwrap(),
222 )
223 })
224 }
225
226 #[inline]
229 pub fn insert<T: Send + Sync + 'static>(&mut self, value: T) -> Option<T> {
230 self.0
231 .ext_mut()
232 .insert(TypeId::of::<T>(), Box::new(value))
233 .and_then(|old| *Extension::into_inner(old).downcast().unwrap())
234 }
235}
236
237impl<X> Debug for IrViewExtensions<X> {
238 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
239 f.debug_tuple("IrViewExtensions").finish_non_exhaustive()
240 }
241}
242
243#[derive(Clone, Copy, Debug, Eq, PartialEq)]
245pub enum Traversal {
246 Visit,
248 Stop,
250 Skip,
252 Ignore,
254}