ploidy_core/ir/views/
mod.rs1use std::{any::TypeId, fmt::Debug};
8
9use atomic_refcell::{AtomicRef, AtomicRefMut};
10use petgraph::{
11 graph::NodeIndex,
12 visit::{Bfs, EdgeFiltered, EdgeRef},
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 extensions(&self) -> &IrViewExtensions<Self>
45 where
46 Self: Extendable<'a> + Sized;
47
48 fn extensions_mut(&mut self) -> &mut IrViewExtensions<Self>
50 where
51 Self: Extendable<'a> + Sized;
52}
53
54impl<'a, T> View<'a> for T
55where
56 T: ViewNode<'a>,
57{
58 #[inline]
59 fn inlines(&self) -> impl Iterator<Item = InlineIrTypeView<'a>> {
60 let graph = self.graph();
61 let filtered = EdgeFiltered::from_fn(&graph.g, |r| {
63 !matches!(graph.g[r.target()], IrGraphNode::Schema(_))
64 });
65 let mut bfs = Bfs::new(&graph.g, self.index());
66 std::iter::from_fn(move || bfs.next(&filtered)).filter_map(|index| match graph.g[index] {
67 IrGraphNode::Inline(ty) => Some(InlineIrTypeView::new(graph, index, ty)),
68 _ => None,
69 })
70 }
71
72 #[inline]
73 fn used_by(&self) -> impl Iterator<Item = IrOperationView<'a>> {
74 self.graph()
75 .metadata
76 .get(&self.index())
77 .into_iter()
78 .flat_map(|meta| &meta.operations)
79 .map(|op| IrOperationView::new(self.graph(), op))
80 }
81
82 #[inline]
83 fn reachable(&self) -> impl Iterator<Item = IrTypeView<'a>> {
84 let graph = self.graph();
85 let mut bfs = Bfs::new(&graph.g, self.index());
86 std::iter::from_fn(move || bfs.next(&graph.g)).map(|index| IrTypeView::new(graph, index))
87 }
88
89 #[inline]
90 fn extensions(&self) -> &IrViewExtensions<Self> {
91 IrViewExtensions::new(self)
92 }
93
94 #[inline]
95 fn extensions_mut(&mut self) -> &mut IrViewExtensions<Self> {
96 IrViewExtensions::new_mut(self)
97 }
98}
99
100pub trait ViewNode<'a> {
101 fn graph(&self) -> &'a IrGraph<'a>;
102 fn index(&self) -> NodeIndex;
103}
104
105pub trait Extendable<'graph> {
106 fn ext<'view>(&'view self) -> AtomicRef<'view, ExtensionMap>
119 where
120 'graph: 'view;
121
122 fn ext_mut<'view>(&'view mut self) -> AtomicRefMut<'view, ExtensionMap>
123 where
124 'graph: 'view;
125}
126
127impl<'graph, T> Extendable<'graph> for T
128where
129 T: ViewNode<'graph>,
130{
131 #[inline]
132 fn ext<'view>(&'view self) -> AtomicRef<'view, ExtensionMap>
133 where
134 'graph: 'view,
135 {
136 self.graph().metadata[&self.index()].extensions.borrow()
137 }
138
139 #[inline]
140 fn ext_mut<'b>(&'b mut self) -> AtomicRefMut<'b, ExtensionMap>
141 where
142 'graph: 'b,
143 {
144 self.graph().metadata[&self.index()].extensions.borrow_mut()
145 }
146}
147
148#[derive(RefCastCustom)]
154#[repr(transparent)]
155pub struct IrViewExtensions<X>(X);
156
157impl<X> IrViewExtensions<X> {
158 #[ref_cast_custom]
159 fn new(view: &X) -> &Self;
160
161 #[ref_cast_custom]
162 fn new_mut(view: &mut X) -> &mut Self;
163}
164
165impl<'a, X: Extendable<'a>> IrViewExtensions<X> {
166 #[inline]
169 pub fn get<'b, T: Send + Sync + 'static>(&'b self) -> Option<AtomicRef<'b, T>>
170 where
171 'a: 'b,
172 {
173 AtomicRef::filter_map(self.0.ext(), |ext| {
174 Some(
175 ext.get(&TypeId::of::<T>())?
176 .as_ref()
177 .downcast_ref::<T>()
178 .unwrap(),
179 )
180 })
181 }
182
183 #[inline]
186 pub fn insert<T: Send + Sync + 'static>(&mut self, value: T) -> Option<T> {
187 self.0
188 .ext_mut()
189 .insert(TypeId::of::<T>(), Box::new(value))
190 .and_then(|old| *Extension::into_inner(old).downcast().unwrap())
191 }
192}
193
194impl<X> Debug for IrViewExtensions<X> {
195 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
196 f.debug_tuple("IrViewExtensions").finish_non_exhaustive()
197 }
198}