ploidy_core/ir/views/
mod.rs1use std::{any::TypeId, fmt::Debug};
32
33use atomic_refcell::{AtomicRef, AtomicRefMut};
34use petgraph::{
35 graph::NodeIndex,
36 visit::{Bfs, EdgeFiltered, EdgeRef},
37};
38use ref_cast::{RefCastCustom, ref_cast_custom};
39
40use super::{
41 graph::{CookedGraph, Extension, ExtensionMap},
42 types::GraphType,
43};
44
45pub mod any;
46pub mod container;
47pub mod enum_;
48pub mod inline;
49pub mod ir;
50pub mod operation;
51pub mod primitive;
52pub mod schema;
53pub mod struct_;
54pub mod tagged;
55pub mod untagged;
56
57use self::{inline::InlineTypeView, ir::TypeView, operation::OperationView};
58
59pub trait View<'a> {
61 fn inlines(&self) -> impl Iterator<Item = InlineTypeView<'a>> + use<'a, Self>;
64
65 fn used_by(&self) -> impl Iterator<Item = OperationView<'a>> + use<'a, Self>;
69
70 fn dependencies(&self) -> impl Iterator<Item = TypeView<'a>> + use<'a, Self>;
75
76 fn dependents(&self) -> impl Iterator<Item = TypeView<'a>> + use<'a, Self>;
81
82 fn hashable(&self) -> bool;
84
85 fn defaultable(&self) -> bool;
87}
88
89pub trait ExtendableView<'a>: View<'a> {
95 fn extensions(&self) -> &ViewExtensions<Self>
97 where
98 Self: Sized;
99
100 fn extensions_mut(&mut self) -> &mut ViewExtensions<Self>
102 where
103 Self: Sized;
104}
105
106impl<'a, T> View<'a> for T
107where
108 T: ViewNode<'a>,
109{
110 #[inline]
111 fn inlines(&self) -> impl Iterator<Item = InlineTypeView<'a>> + use<'a, T> {
112 let cooked = self.cooked();
113 let filtered = EdgeFiltered::from_fn(&cooked.graph, move |e| {
116 !e.weight().shadow() && matches!(cooked.graph[e.target()], GraphType::Inline(_))
117 });
118 let mut bfs = Bfs::new(&cooked.graph, self.index());
119 std::iter::from_fn(move || bfs.next(&filtered))
120 .skip(1) .filter_map(|index| match cooked.graph[index] {
122 GraphType::Inline(ty) => Some(InlineTypeView::new(cooked, index, ty)),
123 _ => None,
124 })
125 }
126
127 #[inline]
128 fn used_by(&self) -> impl Iterator<Item = OperationView<'a>> + use<'a, T> {
129 let cooked = self.cooked();
130 cooked.metadata.used_by[self.index().index()]
131 .iter()
132 .map(|op| OperationView::new(cooked, op))
133 }
134
135 #[inline]
136 fn dependencies(&self) -> impl Iterator<Item = TypeView<'a>> + use<'a, T> {
137 let cooked = self.cooked();
138 let start = self.index();
139 cooked
140 .metadata
141 .closure
142 .dependencies_of(start)
143 .filter(move |&index| index != start)
144 .map(|index| TypeView::new(cooked, index))
145 }
146
147 #[inline]
148 fn dependents(&self) -> impl Iterator<Item = TypeView<'a>> + use<'a, T> {
149 let cooked = self.cooked();
150 let start = self.index();
151 cooked
152 .metadata
153 .closure
154 .dependents_of(start)
155 .filter(move |&index| index != start)
156 .map(|index| TypeView::new(cooked, index))
157 }
158
159 #[inline]
160 fn hashable(&self) -> bool {
161 self.cooked().metadata.hashable[self.index().index()]
162 }
163
164 #[inline]
165 fn defaultable(&self) -> bool {
166 self.cooked().metadata.defaultable[self.index().index()]
167 }
168}
169
170impl<'a, T> ExtendableView<'a> for T
171where
172 T: ViewNode<'a>,
173{
174 #[inline]
175 fn extensions(&self) -> &ViewExtensions<Self> {
176 ViewExtensions::new(self)
177 }
178
179 #[inline]
180 fn extensions_mut(&mut self) -> &mut ViewExtensions<Self> {
181 ViewExtensions::new_mut(self)
182 }
183}
184
185pub(crate) trait ViewNode<'a> {
186 fn cooked(&self) -> &'a CookedGraph<'a>;
187 fn index(&self) -> NodeIndex<usize>;
188}
189
190impl<'graph, T> internal::Extendable<'graph> for T
191where
192 T: ViewNode<'graph>,
193{
194 #[inline]
195 fn ext<'view>(&'view self) -> AtomicRef<'view, ExtensionMap>
196 where
197 'graph: 'view,
198 {
199 self.cooked().metadata.extensions[self.index().index()].borrow()
200 }
201
202 #[inline]
203 fn ext_mut<'b>(&'b mut self) -> AtomicRefMut<'b, ExtensionMap>
204 where
205 'graph: 'b,
206 {
207 self.cooked().metadata.extensions[self.index().index()].borrow_mut()
208 }
209}
210
211#[derive(RefCastCustom)]
213#[repr(transparent)]
214pub struct ViewExtensions<X>(X);
215
216impl<X> ViewExtensions<X> {
217 #[ref_cast_custom]
218 fn new(view: &X) -> &Self;
219
220 #[ref_cast_custom]
221 fn new_mut(view: &mut X) -> &mut Self;
222}
223
224impl<'a, X: internal::Extendable<'a>> ViewExtensions<X> {
225 #[inline]
228 pub fn get<'b, T: Send + Sync + 'static>(&'b self) -> Option<AtomicRef<'b, T>>
229 where
230 'a: 'b,
231 {
232 AtomicRef::filter_map(self.0.ext(), |ext| {
233 Some(
234 ext.get(&TypeId::of::<T>())?
235 .as_ref()
236 .downcast_ref::<T>()
237 .unwrap(),
238 )
239 })
240 }
241
242 #[inline]
245 pub fn insert<T: Send + Sync + 'static>(&mut self, value: T) -> Option<T> {
246 self.0
247 .ext_mut()
248 .insert(TypeId::of::<T>(), Box::new(value))
249 .and_then(|old| *Extension::into_inner(old).downcast().unwrap())
250 }
251}
252
253impl<X> Debug for ViewExtensions<X> {
254 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
255 f.debug_tuple("ViewExtensions").finish_non_exhaustive()
256 }
257}
258
259mod internal {
260 use atomic_refcell::{AtomicRef, AtomicRefMut};
261
262 use super::ExtensionMap;
263
264 pub trait Extendable<'graph> {
265 fn ext<'view>(&'view self) -> AtomicRef<'view, ExtensionMap>
278 where
279 'graph: 'view;
280
281 fn ext_mut<'view>(&'view mut self) -> AtomicRefMut<'view, ExtensionMap>
282 where
283 'graph: 'view;
284 }
285}